Updated hidapi to 0.14.0 release

Upstream: https://github.com/libusb/hidapi/releases/tag/hidapi-0.14.0
diff --git a/src/hidapi/.appveyor.yml b/src/hidapi/.appveyor.yml
new file mode 100644
index 0000000..210b3fa
--- /dev/null
+++ b/src/hidapi/.appveyor.yml
@@ -0,0 +1,31 @@
+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"
diff --git a/src/hidapi/.builds/freebsd.yml b/src/hidapi/.builds/freebsd.yml
new file mode 100644
index 0000000..1679b03
--- /dev/null
+++ b/src/hidapi/.builds/freebsd.yml
@@ -0,0 +1,34 @@
+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
diff --git a/src/hidapi/.builds/netbsd.yml b/src/hidapi/.builds/netbsd.yml
new file mode 100644
index 0000000..413d91c
--- /dev/null
+++ b/src/hidapi/.builds/netbsd.yml
@@ -0,0 +1,18 @@
+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
diff --git a/src/hidapi/.builds/openbsd.yml b/src/hidapi/.builds/openbsd.yml
new file mode 100644
index 0000000..780df7f
--- /dev/null
+++ b/src/hidapi/.builds/openbsd.yml
@@ -0,0 +1,19 @@
+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
diff --git a/src/hidapi/.cirrus.yml b/src/hidapi/.cirrus.yml
new file mode 100644
index 0000000..b4cf201
--- /dev/null
+++ b/src/hidapi/.cirrus.yml
@@ -0,0 +1,33 @@
+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
diff --git a/src/hidapi/.gitattributes b/src/hidapi/.gitattributes
new file mode 100644
index 0000000..edb79fe
--- /dev/null
+++ b/src/hidapi/.gitattributes
@@ -0,0 +1,7 @@
+* text=auto
+
+*.sln text eol=crlf
+*.vcproj text eol=crlf
+
+bootstrap text eol=lf
+configure.ac text eol=lf
diff --git a/src/hidapi/.github/workflows/builds.yml b/src/hidapi/.github/workflows/builds.yml
new file mode 100644
index 0000000..056df2c
--- /dev/null
+++ b/src/hidapi/.github/workflows/builds.yml
@@ -0,0 +1,540 @@
+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
+      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
diff --git a/src/hidapi/.github/workflows/checks.yml b/src/hidapi/.github/workflows/checks.yml
new file mode 100644
index 0000000..e03dc66
--- /dev/null
+++ b/src/hidapi/.github/workflows/checks.yml
@@ -0,0 +1,196 @@
+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
diff --git a/src/hidapi/.github/workflows/docs.yaml b/src/hidapi/.github/workflows/docs.yaml
new file mode 100644
index 0000000..4ec09a5
--- /dev/null
+++ b/src/hidapi/.github/workflows/docs.yaml
@@ -0,0 +1,58 @@
+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
diff --git a/src/hidapi/.gitignore b/src/hidapi/.gitignore
new file mode 100644
index 0000000..048900e2
--- /dev/null
+++ b/src/hidapi/.gitignore
@@ -0,0 +1,32 @@
+
+# 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/
diff --git a/src/hidapi/AUTHORS.txt b/src/hidapi/AUTHORS.txt
index f311978..7193d71 100644
--- a/src/hidapi/AUTHORS.txt
+++ b/src/hidapi/AUTHORS.txt
@@ -10,7 +10,9 @@
 	Bug fixes
 	Correctness fixes
 
+libusb/hidapi Team:
+	Development/maintainance since June 4th 2019
 
 For a comprehensive list of contributions, see the commit list at github:
-	https://github.com/libusb/hidapi/commits/master
+	https://github.com/libusb/hidapi/graphs/contributors
 
diff --git a/src/hidapi/BUILD.autotools.md b/src/hidapi/BUILD.autotools.md
new file mode 100644
index 0000000..24b20a5
--- /dev/null
+++ b/src/hidapi/BUILD.autotools.md
@@ -0,0 +1,114 @@
+# 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
+```
diff --git a/src/hidapi/BUILD.cmake.md b/src/hidapi/BUILD.cmake.md
new file mode 100644
index 0000000..9c51d0c
--- /dev/null
+++ b/src/hidapi/BUILD.cmake.md
@@ -0,0 +1,280 @@
+# 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 prefered 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"
+
+```
diff --git a/src/hidapi/BUILD.md b/src/hidapi/BUILD.md
new file mode 100644
index 0000000..d7a3546
--- /dev/null
+++ b/src/hidapi/BUILD.md
@@ -0,0 +1,127 @@
+# 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.
diff --git a/src/hidapi/CMakeLists.txt b/src/hidapi/CMakeLists.txt
new file mode 100644
index 0000000..e18ee23
--- /dev/null
+++ b/src/hidapi/CMakeLists.txt
@@ -0,0 +1,105 @@
+cmake_minimum_required(VERSION 3.1.3 FATAL_ERROR)
+
+if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+    add_subdirectory(src)
+    # compatibility with find_package() vs add_subdirectory
+    set(hidapi_VERSION "${hidapi_VERSION}" PARENT_SCOPE)
+    return()
+endif()
+# All of the below in this file is meant for a standalone build.
+# When building as a subdirectory of a larger project, most of the options may not make sense for it,
+# so it is up to developer to configure those, e.g.:
+#
+# # a subfolder of a master project, e.g.: 3rdparty/hidapi/CMakeLists.txt
+#
+# set(HIDAPI_WITH_HIDRAW OFF)
+# set(CMAKE_FRAMEWORK ON)
+# # and keep everything else to their defaults
+# add_subdirectory(hidapi)
+#
+
+set(DEFAULT_CMAKE_BUILD_TYPES "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
+if(NOT DEFINED CMAKE_BUILD_TYPE OR NOT CMAKE_BUILD_TYPE)
+    set(CMAKE_BUILD_TYPE "Release" CACHE STRING "${DEFAULT_CMAKE_BUILD_TYPES}" FORCE)
+endif()
+# This part is for convenience, when used one of the standard build types with cmake-gui
+list(FIND DEFAULT_CMAKE_BUILD_TYPES "${CMAKE_BUILD_TYPE}" _build_type_index)
+if(${_build_type_index} GREATER -1)
+    # set it optionally, so a custom CMAKE_BUILD_TYPE can be used as well, if needed
+    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${DEFAULT_CMAKE_BUILD_TYPES})
+endif()
+unset(_build_type_index)
+#
+
+project(hidapi LANGUAGES C)
+
+if(APPLE)
+    if(NOT CMAKE_VERSION VERSION_LESS "3.15")
+        option(CMAKE_FRAMEWORK "Build macOS/iOS Framework version of the library" OFF)
+    endif()
+elseif(NOT WIN32)
+    if(CMAKE_SYSTEM_NAME MATCHES "Linux")
+        option(HIDAPI_WITH_HIDRAW "Build HIDRAW-based implementation of HIDAPI" ON)
+        option(HIDAPI_WITH_LIBUSB "Build LIBUSB-based implementation of HIDAPI" ON)
+    endif()
+endif()
+
+option(BUILD_SHARED_LIBS "Build shared version of the libraries, otherwise build statically" ON)
+
+set(HIDAPI_INSTALL_TARGETS ON)
+set(HIDAPI_PRINT_VERSION ON)
+
+set(IS_DEBUG_BUILD OFF)
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+    set(IS_DEBUG_BUILD ON)
+endif()
+
+option(HIDAPI_ENABLE_ASAN "Build HIDAPI with ASAN address sanitizer instrumentation" OFF)
+
+if(HIDAPI_ENABLE_ASAN)
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
+    if(MSVC)
+        # the default is to have "/INCREMENTAL" which causes a warning when "-fsanitize=address" is present
+        set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /INCREMENTAL:NO")
+        set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /INCREMENTAL:NO")
+        set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /INCREMENTAL:NO")
+        set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /INCREMENTAL:NO")
+    endif()
+endif()
+
+if(WIN32)
+    # so far only Windows has tests
+    option(HIDAPI_WITH_TESTS "Build HIDAPI (unit-)tests" ${IS_DEBUG_BUILD})
+else()
+    set(HIDAPI_WITH_TESTS OFF)
+endif()
+
+if(HIDAPI_WITH_TESTS)
+    enable_testing()
+endif()
+
+if(WIN32)
+    option(HIDAPI_BUILD_PP_DATA_DUMP "Build small Windows console application pp_data_dump.exe" ${IS_DEBUG_BUILD})
+endif()
+
+add_subdirectory(src)
+
+option(HIDAPI_BUILD_HIDTEST "Build small console test application hidtest" ${IS_DEBUG_BUILD})
+if(HIDAPI_BUILD_HIDTEST)
+    add_subdirectory(hidtest)
+endif()
+
+if(HIDAPI_ENABLE_ASAN)
+    if(NOT MSVC)
+        # MSVC doesn't recognize those options, other compilers - requiring it
+        foreach(HIDAPI_TARGET hidapi_winapi hidapi_darwin hidapi_hidraw hidapi_libusb hidtest_hidraw hidtest_libusb hidtest)
+            if(TARGET ${HIDAPI_TARGET})
+                if(BUILD_SHARED_LIBS)
+                    target_link_options(${HIDAPI_TARGET} PRIVATE -fsanitize=address)
+                else()
+                    target_link_options(${HIDAPI_TARGET} PUBLIC -fsanitize=address)
+                endif()
+            endif()
+        endforeach()
+    endif()
+endif()
diff --git a/src/hidapi/HACKING.txt b/src/hidapi/HACKING.txt
index 761d4b6..e06b533 100644
--- a/src/hidapi/HACKING.txt
+++ b/src/hidapi/HACKING.txt
@@ -1,15 +1,19 @@
 This file is mostly for the maintainer.
 
-1. Build hidapi.dll
-2. Build hidtest.exe in DEBUG and RELEASE
-3. Commit all
+Updating a Version:
+1. Update VERSION file.
+2. HID_API_VERSION_MAJOR/HID_API_VERSION_MINOR/HID_API_VERSION_PATCH in hidapi.h.
 
-4. Run the Following
-	export VERSION=0.1.0
-	export TAG_NAME=hidapi-$VERSION
-	git tag $TAG_NAME
-	git archive --format zip --prefix $TAG_NAME/ $TAG_NAME >../$TAG_NAME.zip
-5. Test the zip file.
-6. Run the following:
-	git push origin $TAG_NAME
+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.
diff --git a/src/hidapi/Makefile.am b/src/hidapi/Makefile.am
index 3382a1f..00bcb73 100644
--- a/src/hidapi/Makefile.am
+++ b/src/hidapi/Makefile.am
@@ -23,10 +23,6 @@
 SUBDIRS += mac
 endif
 
-if OS_IOS
-SUBDIRS += ios
-endif
-
 if OS_FREEBSD
 SUBDIRS += libusb
 endif
@@ -35,6 +31,10 @@
 SUBDIRS += libusb
 endif
 
+if OS_HAIKU
+SUBDIRS += libusb
+endif
+
 if OS_WINDOWS
 SUBDIRS += windows
 endif
@@ -48,7 +48,7 @@
 EXTRA_DIST = udev doxygen
 
 dist_doc_DATA = \
- README.txt \
+ README.md \
  AUTHORS.txt \
  LICENSE-bsd.txt \
  LICENSE-gpl3.txt \
diff --git a/src/hidapi/README.md b/src/hidapi/README.md
new file mode 100644
index 0000000..257b9f3
--- /dev/null
+++ b/src/hidapi/README.md
@@ -0,0 +1,196 @@
+## HIDAPI library for Windows, Linux, FreeBSD and macOS
+
+| CI instance          | Status |
+|----------------------|--------|
+| `Linux/macOS/Windows (master)` | [![GitHub Builds](https://github.com/libusb/hidapi/workflows/GitHub%20Builds/badge.svg?branch=master)](https://github.com/libusb/hidapi/actions/workflows/builds.yml?query=branch%3Amaster) |
+| `Windows (master)` | [![Build status](https://ci.appveyor.com/api/projects/status/xfmr5fo8w0re8ded/branch/master?svg=true)](https://ci.appveyor.com/project/libusb/hidapi/branch/master) |
+| `BSD, last build (branch/PR)` | [![builds.sr.ht status](https://builds.sr.ht/~z3ntu/hidapi.svg)](https://builds.sr.ht/~z3ntu/hidapi) |
+| `Coverity Scan (last)` | ![Coverity Scan](https://scan.coverity.com/projects/583/badge.svg) |
+
+HIDAPI is a multi-platform library which allows an application to interface
+with USB and Bluetooth HID-Class devices on Windows, Linux, FreeBSD, and macOS.
+HIDAPI can be either built as a shared library (`.so`, `.dll` or `.dylib`) or
+can be embedded directly into a target application by adding a _single source_
+file (per platform) and a single header.<br>
+See [remarks](BUILD.md#embedding-hidapi-directly-into-your-source-tree) on embedding _directly_ into your build system.
+
+HIDAPI library was originally developed by Alan Ott ([signal11](https://github.com/signal11)).
+
+It was moved to [libusb/hidapi](https://github.com/libusb/hidapi) on June 4th, 2019, in order to merge important bugfixes and continue development of the library.
+
+## Table of Contents
+
+* [About](#about)
+    * [Test GUI](#test-gui)
+    * [Console Test App](#console-test-app)
+* [What Does the API Look Like?](#what-does-the-api-look-like)
+* [License](#license)
+* [Installing HIDAPI](#installing-hidapi)
+* [Build from Source](#build-from-source)
+
+
+## About
+
+### HIDAPI has four back-ends:
+* Windows (using `hid.dll`)
+* Linux/hidraw (using the Kernel's hidraw driver)
+* libusb (using libusb-1.0 - Linux/BSD/other UNIX-like systems)
+* macOS (using IOHidManager)
+
+On Linux, either the hidraw or the libusb back-end can be used. There are
+tradeoffs, and the functionality supported is slightly different. Both are
+built by default. It is up to the application linking to hidapi to choose
+the backend at link time by linking to either `libhidapi-libusb` or
+`libhidapi-hidraw`.
+
+Note that you will need to install an udev rule file with your application
+for unprivileged users to be able to access HID devices with hidapi. Refer
+to the [69-hid.rules](udev/69-hid.rules) file in the `udev` directory
+for an example.
+
+#### __Linux/hidraw__ (`linux/hid.c`):
+
+This back-end uses the hidraw interface in the Linux kernel, and supports
+both USB and Bluetooth HID devices. It requires kernel version at least 2.6.39
+to build. In addition, it will only communicate with devices which have hidraw
+nodes associated with them.
+Keyboards, mice, and some other devices which are blacklisted from having
+hidraw nodes will not work. Fortunately, for nearly all the uses of hidraw,
+this is not a problem.
+
+#### __Linux/FreeBSD/libusb__ (`libusb/hid.c`):
+
+This back-end uses libusb-1.0 to communicate directly to a USB device. This
+back-end will of course not work with Bluetooth devices.
+
+### Test GUI
+
+HIDAPI also comes with a Test GUI. The Test GUI is cross-platform and uses
+Fox Toolkit <http://www.fox-toolkit.org>.  It will build on every platform
+which HIDAPI supports.  Since it relies on a 3rd party library, building it
+is optional but it is useful when debugging hardware.
+
+NOTE: Test GUI based on Fox Toolkit is not actively developed nor supported
+by HIDAPI team. It is kept as a historical artifact. It may even work sometime
+or on some platforms, but it is not going to get any new features or bugfixes.
+
+Instructions for installing Fox-Toolkit on each platform is not provided.
+Make sure to use Fox-Toolkit v1.6 if you choose to use it.
+
+### Console Test App
+
+If you want to play around with your HID device before starting
+any development with HIDAPI and using a GUI app is not an option for you, you may try [`hidapitester`](https://github.com/todbot/hidapitester).
+
+This app has a console interface for most of the features supported
+by HIDAPI library.
+
+## What Does the API Look Like?
+
+The API provides the most commonly used HID functions including sending
+and receiving of input, output, and feature reports. The sample program,
+which communicates with a heavily hacked up version of the Microchip USB
+Generic HID sample looks like this (with error checking removed for
+simplicity):
+
+**Warning: Only run the code you understand, and only when it conforms to the
+device spec. Writing data (`hid_write`) at random to your HID devices can break them.**
+
+```c
+#include <stdio.h> // printf
+#include <wchar.h> // wchar_t
+
+#include <hidapi.h>
+
+#define MAX_STR 255
+
+int main(int argc, char* argv[])
+{
+	int res;
+	unsigned char buf[65];
+	wchar_t wstr[MAX_STR];
+	hid_device *handle;
+	int i;
+
+	// Initialize the hidapi library
+	res = hid_init();
+
+	// Open the device using the VID, PID,
+	// and optionally the Serial number.
+	handle = hid_open(0x4d8, 0x3f, NULL);
+	if (!handle) {
+		printf("Unable to open device\n");
+		hid_exit();
+ 		return 1;
+	}
+
+	// Read the Manufacturer String
+	res = hid_get_manufacturer_string(handle, wstr, MAX_STR);
+	printf("Manufacturer String: %ls\n", wstr);
+
+	// Read the Product String
+	res = hid_get_product_string(handle, wstr, MAX_STR);
+	printf("Product String: %ls\n", wstr);
+
+	// Read the Serial Number String
+	res = hid_get_serial_number_string(handle, wstr, MAX_STR);
+	printf("Serial Number String: (%d) %ls\n", wstr[0], wstr);
+
+	// Read Indexed String 1
+	res = hid_get_indexed_string(handle, 1, wstr, MAX_STR);
+	printf("Indexed String 1: %ls\n", wstr);
+
+	// Toggle LED (cmd 0x80). The first byte is the report number (0x0).
+	buf[0] = 0x0;
+	buf[1] = 0x80;
+	res = hid_write(handle, buf, 65);
+
+	// Request state (cmd 0x81). The first byte is the report number (0x0).
+	buf[0] = 0x0;
+	buf[1] = 0x81;
+	res = hid_write(handle, buf, 65);
+
+	// Read requested state
+	res = hid_read(handle, buf, 65);
+
+	// Print out the returned buffer.
+	for (i = 0; i < 4; i++)
+		printf("buf[%d]: %d\n", i, buf[i]);
+
+	// Close the device
+	hid_close(handle);
+
+	// Finalize the hidapi library
+	res = hid_exit();
+
+	return 0;
+}
+```
+
+You can also use [hidtest/test.c](hidtest/test.c)
+as a starting point for your applications.
+
+
+## License
+
+HIDAPI may be used by one of three licenses as outlined in [LICENSE.txt](LICENSE.txt).
+
+## Installing HIDAPI
+
+If you want to build your own application that uses HID devices with HIDAPI,
+you need to get HIDAPI development package.
+
+Depending on what your development environment is, HIDAPI likely to be provided
+by your package manager.
+
+For instance on Ubuntu, HIDAPI is available via APT:
+```sh
+sudo apt install libhidapi-dev
+```
+
+HIDAPI package name for other systems/package managers may differ.
+Check the documentation/package list of your package manager.
+
+## Build from Source
+
+Check [BUILD.md](BUILD.md) for details.
diff --git a/src/hidapi/README.txt b/src/hidapi/README.txt
deleted file mode 100644
index 756901e..0000000
--- a/src/hidapi/README.txt
+++ /dev/null
@@ -1,339 +0,0 @@
-         HIDAPI library for Windows, Linux, FreeBSD and Mac OS X
-        =========================================================
-
-About
-======
-
-HIDAPI is a multi-platform library which allows an application to interface
-with USB and Bluetooth HID-Class devices on Windows, Linux, FreeBSD, and Mac
-OS X.  HIDAPI can be either built as a shared library (.so or .dll) or
-can be embedded directly into a target application by adding a single source
-file (per platform) and a single header.
-
-HIDAPI has four back-ends:
-	* Windows (using hid.dll)
-	* Linux/hidraw (using the Kernel's hidraw driver)
-	* Linux/libusb (using libusb-1.0)
-	* FreeBSD (using libusb-1.0)
-	* Mac (using IOHidManager)
-
-On Linux, either the hidraw or the libusb back-end can be used. There are
-tradeoffs, and the functionality supported is slightly different.
-
-Linux/hidraw (linux/hid.c):
-This back-end uses the hidraw interface in the Linux kernel.  While this
-back-end will support both USB and Bluetooth, it has some limitations on
-kernels prior to 2.6.39, including the inability to send or receive feature
-reports.  In addition, it will only communicate with devices which have
-hidraw nodes associated with them.  Keyboards, mice, and some other devices
-which are blacklisted from having hidraw nodes will not work. Fortunately,
-for nearly all the uses of hidraw, this is not a problem.
-
-Linux/FreeBSD/libusb (libusb/hid.c):
-This back-end uses libusb-1.0 to communicate directly to a USB device. This
-back-end will of course not work with Bluetooth devices.
-
-HIDAPI also comes with a Test GUI. The Test GUI is cross-platform and uses
-Fox Toolkit (http://www.fox-toolkit.org).  It will build on every platform
-which HIDAPI supports.  Since it relies on a 3rd party library, building it
-is optional but recommended because it is so useful when debugging hardware.
-
-What Does the API Look Like?
-=============================
-The API provides the the most commonly used HID functions including sending
-and receiving of input, output, and feature reports.  The sample program,
-which communicates with a heavily hacked up version of the Microchip USB
-Generic HID sample looks like this (with error checking removed for
-simplicity):
-
-#ifdef WIN32
-#include <windows.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include "hidapi.h"
-
-#define MAX_STR 255
-
-int main(int argc, char* argv[])
-{
-	int res;
-	unsigned char buf[65];
-	wchar_t wstr[MAX_STR];
-	hid_device *handle;
-	int i;
-
-	// Initialize the hidapi library
-	res = hid_init();
-
-	// Open the device using the VID, PID,
-	// and optionally the Serial number.
-	handle = hid_open(0x4d8, 0x3f, NULL);
-
-	// Read the Manufacturer String
-	res = hid_get_manufacturer_string(handle, wstr, MAX_STR);
-	wprintf(L"Manufacturer String: %s\n", wstr);
-
-	// Read the Product String
-	res = hid_get_product_string(handle, wstr, MAX_STR);
-	wprintf(L"Product String: %s\n", wstr);
-
-	// Read the Serial Number String
-	res = hid_get_serial_number_string(handle, wstr, MAX_STR);
-	wprintf(L"Serial Number String: (%d) %s\n", wstr[0], wstr);
-
-	// Read Indexed String 1
-	res = hid_get_indexed_string(handle, 1, wstr, MAX_STR);
-	wprintf(L"Indexed String 1: %s\n", wstr);
-
-	// Toggle LED (cmd 0x80). The first byte is the report number (0x0).
-	buf[0] = 0x0;
-	buf[1] = 0x80;
-	res = hid_write(handle, buf, 65);
-
-	// Request state (cmd 0x81). The first byte is the report number (0x0).
-	buf[0] = 0x0;
-	buf[1] = 0x81;
-	res = hid_write(handle, buf, 65);
-
-	// Read requested state
-	res = hid_read(handle, buf, 65);
-
-	// Print out the returned buffer.
-	for (i = 0; i < 4; i++)
-		printf("buf[%d]: %d\n", i, buf[i]);
-
-	// Finalize the hidapi library
-	res = hid_exit();
-
-	return 0;
-}
-
-If you have your own simple test programs which communicate with standard
-hardware development boards (such as those from Microchip, TI, Atmel,
-FreeScale and others), please consider sending me something like the above
-for inclusion into the HIDAPI source.  This will help others who have the
-same hardware as you do.
-
-License
-========
-HIDAPI may be used by one of three licenses as outlined in LICENSE.txt.
-
-Download
-=========
-HIDAPI can be downloaded from github
-	git clone git://github.com/libusb/hidapi.git
-
-Build Instructions
-===================
-
-This section is long. Don't be put off by this. It's not long because it's
-complicated to build HIDAPI; it's quite the opposite.  This section is long
-because of the flexibility of HIDAPI and the large number of ways in which
-it can be built and used.  You will likely pick a single build method.
-
-HIDAPI can be built in several different ways. If you elect to build a
-shared library, you will need to build it from the HIDAPI source
-distribution.  If you choose instead to embed HIDAPI directly into your
-application, you can skip the building and look at the provided platform
-Makefiles for guidance.  These platform Makefiles are located in linux/
-libusb/ mac/ and windows/ and are called Makefile-manual.  In addition,
-Visual Studio projects are provided.  Even if you're going to embed HIDAPI
-into your project, it is still beneficial to build the example programs.
-
-
-Prerequisites:
----------------
-
-	Linux:
-	-------
-	On Linux, you will need to install development packages for libudev,
-	libusb and optionally Fox-toolkit (for the test GUI). On
-	Debian/Ubuntu systems these can be installed by running:
-	    sudo apt-get install libudev-dev libusb-1.0-0-dev libfox-1.6-dev
-
-	If you downloaded the source directly from the git repository (using
-	git clone), you'll need Autotools:
-	    sudo apt-get install autotools-dev autoconf automake libtool
-
-	FreeBSD:
-	---------
-	On FreeBSD you will need to install GNU make, libiconv, and
-	optionally Fox-Toolkit (for the test GUI). This is done by running
-	the following:
-	    pkg_add -r gmake libiconv fox16
-
-	If you downloaded the source directly from the git repository (using
-	git clone), you'll need Autotools:
-	    pkg_add -r autotools
-
-	Mac:
-	-----
-	On Mac, you will need to install Fox-Toolkit if you wish to build
-	the Test GUI. There are two ways to do this, and each has a slight
-	complication. Which method you use depends on your use case.
-
-	If you wish to build the Test GUI just for your own testing on your
-	own computer, then the easiest method is to install Fox-Toolkit
-	using ports:
-		sudo port install fox
-
-	If you wish to build the TestGUI app bundle to redistribute to
-	others, you will need to install Fox-toolkit from source.  This is
-	because the version of fox that gets installed using ports uses the
-	ports X11 libraries which are not compatible with the Apple X11
-	libraries.  If you install Fox with ports and then try to distribute
-	your built app bundle, it will simply fail to run on other systems.
-	To install Fox-Toolkit manually, download the source package from
-	http://www.fox-toolkit.org, extract it, and run the following from
-	within the extracted source:
-		./configure && make && make install
-
-	Windows:
-	---------
-	On Windows, if you want to build the test GUI, you will need to get
-	the hidapi-externals.zip package from the download site.  This
-	contains pre-built binaries for Fox-toolkit.  Extract
-	hidapi-externals.zip just outside of hidapi, so that
-	hidapi-externals and hidapi are on the same level, as shown:
-
-	     Parent_Folder
-	       |
-	       +hidapi
-	       +hidapi-externals
-
-	Again, this step is not required if you do not wish to build the
-	test GUI.
-
-
-Building HIDAPI into a shared library on Unix Platforms:
----------------------------------------------------------
-
-On Unix-like systems such as Linux, FreeBSD, Mac, and even Windows, using
-Mingw or Cygwin, the easiest way to build a standard system-installed shared
-library is to use the GNU Autotools build system.  If you checked out the
-source from the git repository, run the following:
-
-	./bootstrap
-	./configure
-	make
-	make install     <----- as root, or using sudo
-
-If you downloaded a source package (ie: if you did not run git clone), you
-can skip the ./bootstrap step.
-
-./configure can take several arguments which control the build. The two most
-likely to be used are:
-	--enable-testgui
-		Enable build of the Test GUI. This requires Fox toolkit to
-		be installed.  Instructions for installing Fox-Toolkit on
-		each platform are in the Prerequisites section above.
-
-	--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.
-
-Building the manual way on Unix platforms:
--------------------------------------------
-
-Manual Makefiles are provided mostly to give the user and 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 the Autotools method described above.
-
-	To build HIDAPI using the manual makefiles, change to the directory
-	of your platform and run make. For example, on Linux run:
-		cd linux/
-		make -f Makefile-manual
-
-	To build the Test GUI using the manual makefiles:
-		cd testgui/
-		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 the Test GUI on windows using Visual Studio, build the .sln file in
-the testgui/ directory.
-
-To build HIDAPI using MinGW or Cygwin using Autotools, use the instructions
-in the section titled "Building HIDAPI into a shared library on Unix
-Platforms" above.  Note that building the Test GUI with MinGW or Cygwin will
-require the Windows procedure in the Prerequisites section above (ie:
-hidapi-externals.zip).
-
-To build HIDAPI using MinGW using the Manual Makefiles, see the section
-"Building the manual way on Unix platforms" above.
-
-HIDAPI can also be built using the Windows DDK (now also called the Windows
-Driver Kit or WDK). This method was originally required for the HIDAPI build
-but not anymore. However, some users still prefer this method. It is not as
-well supported anymore but should still work. Patches are welcome if it does
-not. To build using the DDK:
-
-   1. Install the Windows Driver Kit (WDK) from Microsoft.
-   2. From the Start menu, in the Windows Driver Kits folder, select Build
-      Environments, then your operating system, then the x86 Free Build
-      Environment (or one that is appropriate for your system).
-   3. From the console, change directory to the windows/ddk_build/ directory,
-      which is part of the HIDAPI distribution.
-   4. Type build.
-   5. You can find the output files (DLL and LIB) in a subdirectory created
-      by the build system which is appropriate for your environment. On
-      Windows XP, this directory is objfre_wxp_x86/i386.
-
-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.
-
-	$ export STAGING=$HOME/out
-	$ export HOST=arm-linux
-
-STAGING and HOST can be modified to suit your setup.
-
-Prerequisites
---------------
-
-Note that the build of libudev is the very basic configuration.
-
-Build Libusb. From the libusb source directory, run:
-	./configure --host=$HOST --prefix=$STAGING
-	make
-	make install
-
-Build libudev. From the libudev source directory, run:
-	./configure --disable-gudev --disable-introspection --disable-hwdb \
-		 --host=$HOST --prefix=$STAGING
-	make
-	make install
-
-Building HIDAPI
-----------------
-
-Build HIDAPI:
-
-	PKG_CONFIG_DIR= \
-	PKG_CONFIG_LIBDIR=$STAGING/lib/pkgconfig:$STAGING/share/pkgconfig \
-	PKG_CONFIG_SYSROOT_DIR=$STAGING \
-	./configure --host=$HOST --prefix=$STAGING
-
-
-Signal 11 Software - 2010-04-11
-                     2010-07-28
-                     2011-09-10
-                     2012-05-01
-                     2012-07-03
diff --git a/src/hidapi/VERSION b/src/hidapi/VERSION
new file mode 100644
index 0000000..0548fb4
--- /dev/null
+++ b/src/hidapi/VERSION
@@ -0,0 +1 @@
+0.14.0
\ No newline at end of file
diff --git a/src/hidapi/android/hid.cpp b/src/hidapi/android/hid.cpp
deleted file mode 100644
index 450cab2..0000000
--- a/src/hidapi/android/hid.cpp
+++ /dev/null
@@ -1,1443 +0,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 2022 Valve Corporation
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-#include "SDL_internal.h"
-
-// Purpose: A wrapper implementing "HID" API for Android
-//
-//          This layer glues the hidapi API to Android's USB and BLE stack.
-
-#include "hid.h"
-
-// Common to stub version and non-stub version of functions
-#include <jni.h>
-#include <android/log.h>
-
-#define TAG "hidapi"
-
-// Have error log always available
-#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
-
-#ifdef DEBUG
-#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
-#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
-#else
-#define LOGV(...)
-#define LOGD(...)
-#endif
-
-#define SDL_JAVA_PREFIX                                 org_libsdl_app
-#define CONCAT1(prefix, class, function)                CONCAT2(prefix, class, function)
-#define CONCAT2(prefix, class, function)                Java_ ## prefix ## _ ## class ## _ ## function
-#define HID_DEVICE_MANAGER_JAVA_INTERFACE(function)     CONCAT1(SDL_JAVA_PREFIX, HIDDeviceManager, function)
-
-
-#ifndef SDL_HIDAPI_DISABLED
-
-#include "../../core/android/SDL_android.h"
-
-#define hid_init                        PLATFORM_hid_init
-#define hid_exit                        PLATFORM_hid_exit
-#define hid_enumerate                   PLATFORM_hid_enumerate
-#define hid_free_enumeration            PLATFORM_hid_free_enumeration
-#define hid_open                        PLATFORM_hid_open
-#define hid_open_path                   PLATFORM_hid_open_path
-#define hid_write                       PLATFORM_hid_write
-#define hid_read_timeout                PLATFORM_hid_read_timeout
-#define hid_read                        PLATFORM_hid_read
-#define hid_set_nonblocking             PLATFORM_hid_set_nonblocking
-#define hid_send_feature_report         PLATFORM_hid_send_feature_report
-#define hid_get_feature_report          PLATFORM_hid_get_feature_report
-#define hid_close                       PLATFORM_hid_close
-#define hid_get_manufacturer_string     PLATFORM_hid_get_manufacturer_string
-#define hid_get_product_string          PLATFORM_hid_get_product_string
-#define hid_get_serial_number_string    PLATFORM_hid_get_serial_number_string
-#define hid_get_indexed_string          PLATFORM_hid_get_indexed_string
-#define hid_error                       PLATFORM_hid_error
-
-#include <pthread.h>
-#include <errno.h>	// For ETIMEDOUT and ECONNRESET
-#include <stdlib.h> // For malloc() and free()
-
-#include "../hidapi/hidapi.h"
-
-typedef uint32_t uint32;
-typedef uint64_t uint64;
-
-
-struct hid_device_
-{
-	int m_nId;
-	int m_nDeviceRefCount;
-};
-
-static JavaVM *g_JVM;
-static pthread_key_t g_ThreadKey;
-
-template<class T>
-class hid_device_ref
-{
-public:
-	hid_device_ref( T *pObject = nullptr ) : m_pObject( nullptr )
-	{
-		SetObject( pObject );
-	}
-
-	hid_device_ref( const hid_device_ref &rhs ) : m_pObject( nullptr )
-	{
-		SetObject( rhs.GetObject() );
-	}
-
-	~hid_device_ref()
-	{
-		SetObject( nullptr );
-	}
-
-	void SetObject( T *pObject )
-	{
-		if ( m_pObject && m_pObject->DecrementRefCount() == 0 )
-		{
-			delete m_pObject;
-		}
-
-		m_pObject = pObject;
-
-		if ( m_pObject )
-		{
-			m_pObject->IncrementRefCount();
-		}
-	}
-
-	hid_device_ref &operator =( T *pObject )
-	{
-		SetObject( pObject );
-		return *this;
-	}
-
-	hid_device_ref &operator =( const hid_device_ref &rhs )
-	{
-		SetObject( rhs.GetObject() );
-		return *this;
-	}
-
-	T *GetObject() const
-	{
-		return m_pObject;
-	}
-
-	T* operator->() const
-	{
-		return m_pObject;
-	}
-
-	operator bool() const
-	{
-		return ( m_pObject != nullptr );
-	}
-
-private:
-	T *m_pObject;
-};
-
-class hid_mutex_guard
-{
-public:
-	hid_mutex_guard( pthread_mutex_t *pMutex ) : m_pMutex( pMutex )
-	{
-		pthread_mutex_lock( m_pMutex );
-	}
-	~hid_mutex_guard()
-	{
-		pthread_mutex_unlock( m_pMutex );
-	}
-
-private:
-	pthread_mutex_t *m_pMutex;
-};
-
-class hid_buffer
-{
-public:
-	hid_buffer() : m_pData( nullptr ), m_nSize( 0 ), m_nAllocated( 0 )
-	{
-	}
-
-	hid_buffer( const uint8_t *pData, size_t nSize ) : m_pData( nullptr ), m_nSize( 0 ), m_nAllocated( 0 )
-	{
-		assign( pData, nSize );
-	}
-
-	~hid_buffer()
-	{
-		delete[] m_pData;
-	}
-
-	void assign( const uint8_t *pData, size_t nSize )
-	{
-		if ( nSize > m_nAllocated )
-		{
-			delete[] m_pData;
-			m_pData = new uint8_t[ nSize ];
-			m_nAllocated = nSize;
-		}
-
-		m_nSize = nSize;
-		SDL_memcpy( m_pData, pData, nSize );
-	}
-
-	void clear()
-	{
-		m_nSize = 0;
-	}
-
-	size_t size() const
-	{
-		return m_nSize;
-	}
-
-	const uint8_t *data() const
-	{
-		return m_pData;
-	}
-
-private:
-	uint8_t *m_pData;
-	size_t m_nSize;
-	size_t m_nAllocated;
-};
-
-class hid_buffer_pool
-{
-public:
-	hid_buffer_pool() : m_nSize( 0 ), m_pHead( nullptr ), m_pTail( nullptr ), m_pFree( nullptr )
-	{
-	}
-
-	~hid_buffer_pool()
-	{
-		clear();
-
-		while ( m_pFree )
-		{
-			hid_buffer_entry *pEntry = m_pFree;
-			m_pFree = m_pFree->m_pNext;
-			delete pEntry;
-		}
-	}
-
-	size_t size() const { return m_nSize; }
-
-	const hid_buffer &front() const { return m_pHead->m_buffer; }
-
-	void pop_front()
-	{
-		hid_buffer_entry *pEntry = m_pHead;
-		if ( pEntry )
-		{
-			m_pHead = pEntry->m_pNext;
-			if ( !m_pHead )
-			{
-				m_pTail = nullptr;
-			}
-			pEntry->m_pNext = m_pFree;
-			m_pFree = pEntry;
-			--m_nSize;
-		}
-	}
-
-	void emplace_back( const uint8_t *pData, size_t nSize )
-	{
-		hid_buffer_entry *pEntry;
-
-		if ( m_pFree )
-		{
-			pEntry = m_pFree;
-			m_pFree = m_pFree->m_pNext;
-		}
-		else
-		{
-			pEntry = new hid_buffer_entry;
-		}
-		pEntry->m_pNext = nullptr;
-
-		if ( m_pTail )
-		{
-			m_pTail->m_pNext = pEntry;
-		}
-		else
-		{
-			m_pHead = pEntry;
-		}
-		m_pTail = pEntry;
-
-		pEntry->m_buffer.assign( pData, nSize );
-		++m_nSize;
-	}
-
-	void clear()
-	{
-		while ( size() > 0 )
-		{
-			pop_front();
-		}
-	}
-
-private:
-	struct hid_buffer_entry
-	{
-		hid_buffer m_buffer;
-		hid_buffer_entry *m_pNext;
-	};
-
-	size_t m_nSize;
-	hid_buffer_entry *m_pHead;
-	hid_buffer_entry *m_pTail;
-	hid_buffer_entry *m_pFree;
-};
-
-static jbyteArray NewByteArray( JNIEnv* env, const uint8_t *pData, size_t nDataLen )
-{
-	jbyteArray array = env->NewByteArray( (jsize)nDataLen );
-	jbyte *pBuf = env->GetByteArrayElements( array, NULL );
-	SDL_memcpy( pBuf, pData, nDataLen );
-	env->ReleaseByteArrayElements( array, pBuf, 0 );
-
-	return array;
-}
-
-static char *CreateStringFromJString( JNIEnv *env, const jstring &sString )
-{
-	size_t nLength = env->GetStringUTFLength( sString );
-	const char *pjChars = env->GetStringUTFChars( sString, NULL );
-	char *psString = (char*)malloc( nLength + 1 );
-	SDL_memcpy( psString, pjChars, nLength );
-	psString[ nLength ] = '\0';
-	env->ReleaseStringUTFChars( sString, pjChars );
-	return psString;
-}
-
-static wchar_t *CreateWStringFromJString( JNIEnv *env, const jstring &sString )
-{
-	size_t nLength = env->GetStringLength( sString );
-	const jchar *pjChars = env->GetStringChars( sString, NULL );
-	wchar_t *pwString = (wchar_t*)malloc( ( nLength + 1 ) * sizeof( wchar_t ) );
-	wchar_t *pwChars = pwString;
-	for ( size_t iIndex = 0; iIndex < nLength; ++iIndex )
-	{
-		pwChars[ iIndex ] = pjChars[ iIndex ];
-	}
-	pwString[ nLength ] = '\0';
-	env->ReleaseStringChars( sString, pjChars );
-	return pwString;
-}
-
-static wchar_t *CreateWStringFromWString( const wchar_t *pwSrc )
-{
-	size_t nLength = SDL_wcslen( pwSrc );
-	wchar_t *pwString = (wchar_t*)malloc( ( nLength + 1 ) * sizeof( wchar_t ) );
-	SDL_memcpy( pwString, pwSrc, nLength * sizeof( wchar_t ) );
-	pwString[ nLength ] = '\0';
-	return pwString;
-}
-
-static hid_device_info *CopyHIDDeviceInfo( const hid_device_info *pInfo )
-{
-	hid_device_info *pCopy = new hid_device_info;
-	*pCopy = *pInfo;
-	pCopy->path = SDL_strdup( pInfo->path );
-	pCopy->product_string = CreateWStringFromWString( pInfo->product_string );
-	pCopy->manufacturer_string = CreateWStringFromWString( pInfo->manufacturer_string );
-	pCopy->serial_number = CreateWStringFromWString( pInfo->serial_number );
-	return pCopy;
-}
-
-static void FreeHIDDeviceInfo( hid_device_info *pInfo )
-{
-	free( pInfo->path );
-	free( pInfo->serial_number );
-	free( pInfo->manufacturer_string );
-	free( pInfo->product_string );
-	delete pInfo;
-}
-
-static jclass  g_HIDDeviceManagerCallbackClass;
-static jobject g_HIDDeviceManagerCallbackHandler;
-static jmethodID g_midHIDDeviceManagerInitialize;
-static jmethodID g_midHIDDeviceManagerOpen;
-static jmethodID g_midHIDDeviceManagerSendOutputReport;
-static jmethodID g_midHIDDeviceManagerSendFeatureReport;
-static jmethodID g_midHIDDeviceManagerGetFeatureReport;
-static jmethodID g_midHIDDeviceManagerClose;
-static bool g_initialized = false;
-
-static uint64_t get_timespec_ms( const struct timespec &ts )
-{
-	return (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
-}
-
-static void ExceptionCheck( JNIEnv *env, const char *pszClassName, const char *pszMethodName )
-{
-	if ( env->ExceptionCheck() )
-	{
-		// Get our exception
-		jthrowable jExcept = env->ExceptionOccurred();
-
-		// Clear the exception so we can call JNI again
-		env->ExceptionClear();
-
-		// Get our exception message
-		jclass jExceptClass = env->GetObjectClass( jExcept );
-		jmethodID jMessageMethod = env->GetMethodID( jExceptClass, "getMessage", "()Ljava/lang/String;" );
-		jstring jMessage = (jstring)( env->CallObjectMethod( jExcept, jMessageMethod ) );
-		const char *pszMessage = env->GetStringUTFChars( jMessage, NULL );
-
-		// ...and log it.
-		LOGE( "%s%s%s threw an exception: %s",
-			pszClassName ? pszClassName : "",
-			pszClassName ? "::" : "",
-			pszMethodName, pszMessage );
-
-		// Cleanup
-		env->ReleaseStringUTFChars( jMessage, pszMessage );
-		env->DeleteLocalRef( jMessage );
-		env->DeleteLocalRef( jExceptClass );
-		env->DeleteLocalRef( jExcept );
-	}
-}
-
-class CHIDDevice
-{
-public:
-	CHIDDevice( int nDeviceID, hid_device_info *pInfo )
-	{
-		m_nId = nDeviceID;
-		m_pInfo = pInfo;
-
-		// The Bluetooth Steam Controller needs special handling
-		const int VALVE_USB_VID	= 0x28DE;
-		const int D0G_BLE2_PID = 0x1106;
-		if ( pInfo->vendor_id == VALVE_USB_VID && pInfo->product_id == D0G_BLE2_PID )
-		{
-			m_bIsBLESteamController = true;
-		}
-	}
-
-	~CHIDDevice()
-	{
-		FreeHIDDeviceInfo( m_pInfo );
-
-		// Note that we don't delete m_pDevice, as the app may still have a reference to it
-	}
-
-	int IncrementRefCount()
-	{
-		int nValue;
-		pthread_mutex_lock( &m_refCountLock );
-		nValue = ++m_nRefCount;
-		pthread_mutex_unlock( &m_refCountLock );
-		return nValue;
-	}
-
-	int DecrementRefCount()
-	{
-		int nValue;
-		pthread_mutex_lock( &m_refCountLock );
-		nValue = --m_nRefCount;
-		pthread_mutex_unlock( &m_refCountLock );
-		return nValue;
-	}
-
-	int GetId()
-	{
-		return m_nId;
-	}
-
-	const hid_device_info *GetDeviceInfo()
-	{
-		return m_pInfo;
-	}
-
-	hid_device *GetDevice()
-	{
-		return m_pDevice;
-	}
-
-	void ExceptionCheck( JNIEnv *env, const char *pszMethodName )
-	{
-		::ExceptionCheck( env, "CHIDDevice", pszMethodName );
-	}
-
-	bool BOpen()
-	{
-		// Make sure thread is attached to JVM/env
-		JNIEnv *env;
-		g_JVM->AttachCurrentThread( &env, NULL );
-		pthread_setspecific( g_ThreadKey, (void*)env );
-
-		if ( !g_HIDDeviceManagerCallbackHandler )
-		{
-			LOGV( "Device open without callback handler" );
-			return false;
-		}
-
-		m_bIsWaitingForOpen = false;
-		m_bOpenResult = env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerOpen, m_nId );
-		ExceptionCheck( env, "BOpen" );
-
-		if ( m_bIsWaitingForOpen )
-		{
-			hid_mutex_guard cvl( &m_cvLock );
-
-			const int OPEN_TIMEOUT_SECONDS = 60;
-			struct timespec ts, endtime;
-			clock_gettime( CLOCK_REALTIME, &ts );
-			endtime = ts;
-			endtime.tv_sec += OPEN_TIMEOUT_SECONDS;
-			do
-			{
-				if ( pthread_cond_timedwait( &m_cv, &m_cvLock, &endtime ) != 0 )
-				{
-					break;
-				}
-			}
-			while ( m_bIsWaitingForOpen && get_timespec_ms( ts ) < get_timespec_ms( endtime ) );
-		}
-
-		if ( !m_bOpenResult )
-		{
-			if ( m_bIsWaitingForOpen )
-			{
-				LOGV( "Device open failed - timed out waiting for device permission" );
-			}
-			else
-			{
-				LOGV( "Device open failed" );
-			}
-			return false;
-		}
-
-		m_pDevice = new hid_device;
-		m_pDevice->m_nId = m_nId;
-		m_pDevice->m_nDeviceRefCount = 1;
-		LOGD("Creating device %d (%p), refCount = 1\n", m_pDevice->m_nId, m_pDevice);
-		return true;
-	}
-
-	void SetOpenPending()
-	{
-		m_bIsWaitingForOpen = true;
-	}
-
-	void SetOpenResult( bool bResult )
-	{
-		if ( m_bIsWaitingForOpen )
-		{
-			m_bOpenResult = bResult;
-			m_bIsWaitingForOpen = false;
-			pthread_cond_signal( &m_cv );
-		}
-	}
-
-	void ProcessInput( const uint8_t *pBuf, size_t nBufSize )
-	{
-		hid_mutex_guard l( &m_dataLock );
-
-		size_t MAX_REPORT_QUEUE_SIZE = 16;
-		if ( m_vecData.size() >= MAX_REPORT_QUEUE_SIZE )
-		{
-			m_vecData.pop_front();
-		}
-		m_vecData.emplace_back( pBuf, nBufSize );
-	}
-
-	int GetInput( unsigned char *data, size_t length )
-	{
-		hid_mutex_guard l( &m_dataLock );
-
-		if ( m_vecData.size() == 0 )
-		{
-//			LOGV( "hid_read_timeout no data available" );
-			return 0;
-		}
-
-		const hid_buffer &buffer = m_vecData.front();
-		size_t nDataLen = buffer.size() > length ? length : buffer.size();
-		if ( m_bIsBLESteamController )
-		{
-			data[0] = 0x03;
-			SDL_memcpy( data + 1, buffer.data(), nDataLen );
-			++nDataLen;
-		}
-		else
-		{
-			SDL_memcpy( data, buffer.data(), nDataLen );
-		}
-		m_vecData.pop_front();
-
-//		LOGV("Read %u bytes", nDataLen);
-//		LOGV("%02x %02x %02x %02x %02x %02x %02x %02x ....",
-//			 data[0], data[1], data[2], data[3],
-//			 data[4], data[5], data[6], data[7]);
-
-		return (int)nDataLen;
-	}
-
-	int SendOutputReport( const unsigned char *pData, size_t nDataLen )
-	{
-		// Make sure thread is attached to JVM/env
-		JNIEnv *env;
-		g_JVM->AttachCurrentThread( &env, NULL );
-		pthread_setspecific( g_ThreadKey, (void*)env );
-
-		int nRet = -1;
-		if ( g_HIDDeviceManagerCallbackHandler )
-		{
-			jbyteArray pBuf = NewByteArray( env, pData, nDataLen );
-			nRet = env->CallIntMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerSendOutputReport, m_nId, pBuf );
-			ExceptionCheck( env, "SendOutputReport" );
-			env->DeleteLocalRef( pBuf );
-		}
-		else
-		{
-			LOGV( "SendOutputReport without callback handler" );
-		}
-		return nRet;
-	}
-
-	int SendFeatureReport( const unsigned char *pData, size_t nDataLen )
-	{
-		// Make sure thread is attached to JVM/env
-		JNIEnv *env;
-		g_JVM->AttachCurrentThread( &env, NULL );
-		pthread_setspecific( g_ThreadKey, (void*)env );
-
-		int nRet = -1;
-		if ( g_HIDDeviceManagerCallbackHandler )
-		{
-			jbyteArray pBuf = NewByteArray( env, pData, nDataLen );
-			nRet = env->CallIntMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerSendFeatureReport, m_nId, pBuf );
-			ExceptionCheck( env, "SendFeatureReport" );
-			env->DeleteLocalRef( pBuf );
-		}
-		else
-		{
-			LOGV( "SendFeatureReport without callback handler" );
-		}
-		return nRet;
-	}
-
-	void ProcessFeatureReport( const uint8_t *pBuf, size_t nBufSize )
-	{
-		hid_mutex_guard cvl( &m_cvLock );
-		if ( m_bIsWaitingForFeatureReport )
-		{
-			m_featureReport.assign( pBuf, nBufSize );
-
-			m_bIsWaitingForFeatureReport = false;
-			m_nFeatureReportError = 0;
-			pthread_cond_signal( &m_cv );
-		}
-	}
-
-	int GetFeatureReport( unsigned char *pData, size_t nDataLen )
-	{
-		// Make sure thread is attached to JVM/env
-		JNIEnv *env;
-		g_JVM->AttachCurrentThread( &env, NULL );
-		pthread_setspecific( g_ThreadKey, (void*)env );
-
-		if ( !g_HIDDeviceManagerCallbackHandler )
-		{
-			LOGV( "GetFeatureReport without callback handler" );
-			return -1;
-		}
-
-		{
-			hid_mutex_guard cvl( &m_cvLock );
-			if ( m_bIsWaitingForFeatureReport )
-			{
-				LOGV( "Get feature report already ongoing... bail" );
-				return -1; // Read already ongoing, we currently do not serialize, TODO
-			}
-			m_bIsWaitingForFeatureReport = true;
-		}
-
-		jbyteArray pBuf = NewByteArray( env, pData, nDataLen );
-		int nRet = env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerGetFeatureReport, m_nId, pBuf ) ? 0 : -1;
-		ExceptionCheck( env, "GetFeatureReport" );
-		env->DeleteLocalRef( pBuf );
-		if ( nRet < 0 )
-		{
-			LOGV( "GetFeatureReport failed" );
-			m_bIsWaitingForFeatureReport = false;
-			return -1;
-		}
-
-		{
-			hid_mutex_guard cvl( &m_cvLock );
-			if ( m_bIsWaitingForFeatureReport )
-			{
-				LOGV("=== Going to sleep" );
-				// Wait in CV until we are no longer waiting for a feature report.
-				const int FEATURE_REPORT_TIMEOUT_SECONDS = 2;
-				struct timespec ts, endtime;
-				clock_gettime( CLOCK_REALTIME, &ts );
-				endtime = ts;
-				endtime.tv_sec += FEATURE_REPORT_TIMEOUT_SECONDS;
-				do
-				{
-					if ( pthread_cond_timedwait( &m_cv, &m_cvLock, &endtime ) != 0 )
-					{
-						break;
-					}
-				}
-				while ( m_bIsWaitingForFeatureReport && get_timespec_ms( ts ) < get_timespec_ms( endtime ) );
-
-				// We are back
-				if ( m_bIsWaitingForFeatureReport )
-				{
-					m_nFeatureReportError = -ETIMEDOUT;
-					m_bIsWaitingForFeatureReport = false;
-				}
-				LOGV( "=== Got feature report err=%d", m_nFeatureReportError );
-				if ( m_nFeatureReportError != 0 )
-				{
-					return m_nFeatureReportError;
-				}
-			}
-
-			size_t uBytesToCopy = m_featureReport.size() > nDataLen ? nDataLen : m_featureReport.size();
-			SDL_memcpy( pData, m_featureReport.data(), uBytesToCopy );
-			m_featureReport.clear();
-			LOGV( "=== Got %u bytes", uBytesToCopy );
-
-			return (int)uBytesToCopy;
-		}
-	}
-
-	void Close( bool bDeleteDevice )
-	{
-		// Make sure thread is attached to JVM/env
-		JNIEnv *env;
-		g_JVM->AttachCurrentThread( &env, NULL );
-		pthread_setspecific( g_ThreadKey, (void*)env );
-
-		if ( g_HIDDeviceManagerCallbackHandler )
-		{
-			env->CallVoidMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerClose, m_nId );
-			ExceptionCheck( env, "Close" );
-		}
-
-		hid_mutex_guard dataLock( &m_dataLock );
-		m_vecData.clear();
-
-		// Clean and release pending feature report reads
-		hid_mutex_guard cvLock( &m_cvLock );
-		m_featureReport.clear();
-		m_bIsWaitingForFeatureReport = false;
-		m_nFeatureReportError = -ECONNRESET;
-		pthread_cond_broadcast( &m_cv );
-
-		if ( bDeleteDevice )
-		{
-			delete m_pDevice;
-			m_pDevice = nullptr;
-		}
-	}
-
-private:
-	pthread_mutex_t m_refCountLock = PTHREAD_MUTEX_INITIALIZER;
-	int m_nRefCount = 0;
-	int m_nId = 0;
-	hid_device_info *m_pInfo = nullptr;
-	hid_device *m_pDevice = nullptr;
-	bool m_bIsBLESteamController = false;
-
-	pthread_mutex_t m_dataLock = PTHREAD_MUTEX_INITIALIZER; // This lock has to be held to access m_vecData
-	hid_buffer_pool m_vecData;
-
-	// For handling get_feature_report
-	pthread_mutex_t m_cvLock = PTHREAD_MUTEX_INITIALIZER; // This lock has to be held to access any variables below
-	pthread_cond_t m_cv = PTHREAD_COND_INITIALIZER;
-	bool m_bIsWaitingForOpen = false;
-	bool m_bOpenResult = false;
-	bool m_bIsWaitingForFeatureReport = false;
-	int m_nFeatureReportError = 0;
-	hid_buffer m_featureReport;
-
-public:
-	hid_device_ref<CHIDDevice> next;
-};
-
-class CHIDDevice;
-static pthread_mutex_t g_DevicesMutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t g_DevicesRefCountMutex = PTHREAD_MUTEX_INITIALIZER;
-static hid_device_ref<CHIDDevice> g_Devices;
-
-static hid_device_ref<CHIDDevice> FindDevice( int nDeviceId )
-{
-	hid_device_ref<CHIDDevice> pDevice;
-
-	hid_mutex_guard l( &g_DevicesMutex );
-	for ( pDevice = g_Devices; pDevice; pDevice = pDevice->next )
-	{
-		if ( pDevice->GetId() == nDeviceId )
-		{
-			break;
-		}
-	}
-	return pDevice;
-}
-
-static void ThreadDestroyed(void* value)
-{
-	/* The thread is being destroyed, detach it from the Java VM and set the g_ThreadKey value to NULL as required */
-	JNIEnv *env = (JNIEnv*) value;
-	if (env != NULL) {
-		g_JVM->DetachCurrentThread();
-		pthread_setspecific(g_ThreadKey, NULL);
-	}
-}
-
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz);
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz);
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface, int nInterfaceClass, int nInterfaceSubclass, int nInterfaceProtocol );
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID);
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, int nDeviceID, bool bOpened);
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, int nDeviceID);
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value);
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceFeatureReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value);
-
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz )
-{
-	LOGV( "HIDDeviceRegisterCallback()");
-
-	env->GetJavaVM( &g_JVM );
-
-	/*
-	 * Create mThreadKey so we can keep track of the JNIEnv assigned to each thread
-	 * Refer to http://developer.android.com/guide/practices/design/jni.html for the rationale behind this
-	 */
-	if (pthread_key_create(&g_ThreadKey, ThreadDestroyed) != 0) {
-		__android_log_print(ANDROID_LOG_ERROR, TAG, "Error initializing pthread key");
-	}
-
-	if ( g_HIDDeviceManagerCallbackHandler != NULL )
-	{
-		env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass );
-		g_HIDDeviceManagerCallbackClass = NULL;
-		env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler );
-		g_HIDDeviceManagerCallbackHandler = NULL;
-	}
-
-	g_HIDDeviceManagerCallbackHandler = env->NewGlobalRef( thiz );
-	jclass objClass = env->GetObjectClass( thiz );
-	if ( objClass )
-	{
-		g_HIDDeviceManagerCallbackClass = reinterpret_cast< jclass >( env->NewGlobalRef( objClass ) );
-		g_midHIDDeviceManagerInitialize = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "initialize", "(ZZ)Z" );
-		if ( !g_midHIDDeviceManagerInitialize )
-		{
-			__android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing initialize" );
-		}
-		g_midHIDDeviceManagerOpen = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "openDevice", "(I)Z" );
-		if ( !g_midHIDDeviceManagerOpen )
-		{
-			__android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing openDevice" );
-		}
-		g_midHIDDeviceManagerSendOutputReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "sendOutputReport", "(I[B)I" );
-		if ( !g_midHIDDeviceManagerSendOutputReport )
-		{
-			__android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing sendOutputReport" );
-		}
-		g_midHIDDeviceManagerSendFeatureReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "sendFeatureReport", "(I[B)I" );
-		if ( !g_midHIDDeviceManagerSendFeatureReport )
-		{
-			__android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing sendFeatureReport" );
-		}
-		g_midHIDDeviceManagerGetFeatureReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "getFeatureReport", "(I[B)Z" );
-		if ( !g_midHIDDeviceManagerGetFeatureReport )
-		{
-			__android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing getFeatureReport" );
-		}
-		g_midHIDDeviceManagerClose = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "closeDevice", "(I)V" );
-		if ( !g_midHIDDeviceManagerClose )
-		{
-			__android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing closeDevice" );
-		}
-		env->DeleteLocalRef( objClass );
-	}
-}
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz)
-{
-	LOGV("HIDDeviceReleaseCallback");
-	if ( env->IsSameObject( thiz, g_HIDDeviceManagerCallbackHandler ) )
-	{
-		env->DeleteGlobalRef( g_HIDDeviceManagerCallbackClass );
-		g_HIDDeviceManagerCallbackClass = NULL;
-		env->DeleteGlobalRef( g_HIDDeviceManagerCallbackHandler );
-		g_HIDDeviceManagerCallbackHandler = NULL;
-		g_initialized = false;
-	}
-}
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface, int nInterfaceClass, int nInterfaceSubclass, int nInterfaceProtocol )
-{
-	LOGV( "HIDDeviceConnected() id=%d VID/PID = %.4x/%.4x, interface %d\n", nDeviceID, nVendorId, nProductId, nInterface );
-
-	hid_device_info *pInfo = new hid_device_info;
-	SDL_memset( pInfo, 0, sizeof( *pInfo ) );
-	pInfo->path = CreateStringFromJString( env, sIdentifier );
-	pInfo->vendor_id = nVendorId;
-	pInfo->product_id = nProductId;
-	pInfo->serial_number = CreateWStringFromJString( env, sSerialNumber );
-	pInfo->release_number = nReleaseNumber;
-	pInfo->manufacturer_string = CreateWStringFromJString( env, sManufacturer );
-	pInfo->product_string = CreateWStringFromJString( env, sProduct );
-	pInfo->interface_number = nInterface;
-	pInfo->interface_class = nInterfaceClass;
-	pInfo->interface_subclass = nInterfaceSubclass;
-	pInfo->interface_protocol = nInterfaceProtocol;
-
-	hid_device_ref<CHIDDevice> pDevice( new CHIDDevice( nDeviceID, pInfo ) );
-
-	hid_mutex_guard l( &g_DevicesMutex );
-	hid_device_ref<CHIDDevice> pLast, pCurr;
-	for ( pCurr = g_Devices; pCurr; pLast = pCurr, pCurr = pCurr->next )
-	{
-		continue;
-	}
-	if ( pLast )
-	{
-		pLast->next = pDevice;
-	}
-	else
-	{
-		g_Devices = pDevice;
-	}
-}
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID)
-{
-	LOGV( "HIDDeviceOpenPending() id=%d\n", nDeviceID );
-	hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID );
-	if ( pDevice )
-	{
-		pDevice->SetOpenPending();
-	}
-}
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, int nDeviceID, bool bOpened)
-{
-	LOGV( "HIDDeviceOpenResult() id=%d, result=%s\n", nDeviceID, bOpened ? "true" : "false" );
-	hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID );
-	if ( pDevice )
-	{
-		pDevice->SetOpenResult( bOpened );
-	}
-}
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, int nDeviceID)
-{
-	LOGV( "HIDDeviceDisconnected() id=%d\n", nDeviceID );
-	hid_device_ref<CHIDDevice> pDevice;
-	{
-		hid_mutex_guard l( &g_DevicesMutex );
-		hid_device_ref<CHIDDevice> pLast, pCurr;
-		for ( pCurr = g_Devices; pCurr; pLast = pCurr, pCurr = pCurr->next )
-		{
-			if ( pCurr->GetId() == nDeviceID )
-			{
-				pDevice = pCurr;
-
-				if ( pLast )
-				{
-					pLast->next = pCurr->next;
-				}
-				else
-				{
-					g_Devices = pCurr->next;
-				}
-			}
-		}
-	}
-	if ( pDevice )
-	{
-		pDevice->Close( false );
-	}
-}
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value)
-{
-	jbyte *pBuf = env->GetByteArrayElements(value, NULL);
-	jsize nBufSize = env->GetArrayLength(value);
-
-//	LOGV( "HIDDeviceInput() id=%d len=%u\n", nDeviceID, nBufSize );
-	hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID );
-	if ( pDevice )
-	{
-		pDevice->ProcessInput( reinterpret_cast< const uint8_t* >( pBuf ), nBufSize );
-	}
-
-	env->ReleaseByteArrayElements(value, pBuf, 0);
-}
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceFeatureReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value)
-{
-	jbyte *pBuf = env->GetByteArrayElements(value, NULL);
-	jsize nBufSize = env->GetArrayLength(value);
-
-	LOGV( "HIDDeviceFeatureReport() id=%d len=%u\n", nDeviceID, nBufSize );
-	hid_device_ref<CHIDDevice> pDevice = FindDevice( nDeviceID );
-	if ( pDevice )
-	{
-		pDevice->ProcessFeatureReport( reinterpret_cast< const uint8_t* >( pBuf ), nBufSize );
-	}
-
-	env->ReleaseByteArrayElements(value, pBuf, 0);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-extern "C"
-{
-
-int hid_init(void)
-{
-	if ( !g_initialized )
-	{
-		// HIDAPI doesn't work well with Android < 4.3
-		if (SDL_GetAndroidSDKVersion() >= 18) {
-			// Make sure thread is attached to JVM/env
-			JNIEnv *env;
-			g_JVM->AttachCurrentThread( &env, NULL );
-			pthread_setspecific( g_ThreadKey, (void*)env );
-
-			if ( !g_HIDDeviceManagerCallbackHandler )
-			{
-				LOGV( "hid_init() without callback handler" );
-				return -1;
-			}
-
-			// Bluetooth is currently only used for Steam Controllers, so check that hint
-			// before initializing Bluetooth, which will prompt the user for permission.
-			bool init_usb = true;
-			bool init_bluetooth = false;
-			if (SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_STEAM, SDL_FALSE)) {
-				if (SDL_GetAndroidSDKVersion() < 31 ||
-					Android_JNI_RequestPermission("android.permission.BLUETOOTH_CONNECT")) {
-					init_bluetooth = true;
-				}
-			}
-			env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerInitialize, init_usb, init_bluetooth );
-			ExceptionCheck( env, NULL, "hid_init" );
-		}
-		g_initialized = true;	// Regardless of result, so it's only called once
-	}
-	return 0;
-}
-
-struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
-{
-	struct hid_device_info *root = NULL;
-	const char *hint = SDL_GetHint(SDL_HINT_HIDAPI_IGNORE_DEVICES);
-
-	hid_mutex_guard l( &g_DevicesMutex );
-	for ( hid_device_ref<CHIDDevice> pDevice = g_Devices; pDevice; pDevice = pDevice->next )
-	{
-		const hid_device_info *info = pDevice->GetDeviceInfo();
-
-		/* See if there are any devices we should skip in enumeration */
-		if (hint) {
-			char vendor_match[16], product_match[16];
-			SDL_snprintf(vendor_match, sizeof(vendor_match), "0x%.4x/0x0000", info->vendor_id);
-			SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", info->vendor_id, info->product_id);
-			if (SDL_strcasestr(hint, vendor_match) || SDL_strcasestr(hint, product_match)) {
-				continue;
-			}
-		}
-
-		if ( ( vendor_id == 0x0 || info->vendor_id == vendor_id ) &&
-		     ( product_id == 0x0 || info->product_id == product_id ) )
-		{
-			hid_device_info *dev = CopyHIDDeviceInfo( info );
-			dev->next = root;
-			root = dev;
-		}
-	}
-	return root;
-}
-
-void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
-{
-	while ( devs )
-	{
-		struct hid_device_info *next = devs->next;
-		FreeHIDDeviceInfo( devs );
-		devs = next;
-	}
-}
-
-HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
-{
-	// TODO: Implement
-	return NULL;
-}
-
-HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path, int bExclusive)
-{
-	LOGV( "hid_open_path( %s )", path );
-
-	hid_device_ref< CHIDDevice > pDevice;
-	{
-		hid_mutex_guard r( &g_DevicesRefCountMutex );
-		hid_mutex_guard l( &g_DevicesMutex );
-		for ( hid_device_ref<CHIDDevice> pCurr = g_Devices; pCurr; pCurr = pCurr->next )
-		{
-			if ( SDL_strcmp( pCurr->GetDeviceInfo()->path, path ) == 0 )
-			{
-				hid_device *pValue = pCurr->GetDevice();
-				if ( pValue )
-				{
-					++pValue->m_nDeviceRefCount;
-					LOGD("Incrementing device %d (%p), refCount = %d\n", pValue->m_nId, pValue, pValue->m_nDeviceRefCount);
-					return pValue;
-				}
-
-				// Hold a shared pointer to the controller for the duration
-				pDevice = pCurr;
-				break;
-			}
-		}
-	}
-	if ( pDevice && pDevice->BOpen() )
-	{
-		return pDevice->GetDevice();
-	}
-	return NULL;
-}
-
-int  HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length)
-{
-	if ( device )
-	{
-		LOGV( "hid_write id=%d length=%u", device->m_nId, length );
-		hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
-		if ( pDevice )
-		{
-			return pDevice->SendOutputReport( data, length );
-		}
-	}
-	return -1; // Controller was disconnected
-}
-
-static uint32_t getms()
-{
-	struct timeval now;
-
-	gettimeofday(&now, NULL);
-	return (uint32_t)(now.tv_sec * 1000 + now.tv_usec / 1000);
-}
-
-static void delayms(uint32_t ms)
-{
-    int was_error;
-
-    struct timespec elapsed, tv;
-
-    /* Set the timeout interval */
-    elapsed.tv_sec = ms / 1000;
-    elapsed.tv_nsec = (ms % 1000) * 1000000;
-    do {
-        errno = 0;
-
-        tv.tv_sec = elapsed.tv_sec;
-        tv.tv_nsec = elapsed.tv_nsec;
-        was_error = nanosleep(&tv, &elapsed);
-    } while (was_error && (errno == EINTR));
-}
-
-int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *device, unsigned char *data, size_t length, int milliseconds)
-{
-	if ( device )
-	{
-//		LOGV( "hid_read_timeout id=%d length=%u timeout=%d", device->m_nId, length, milliseconds );
-		hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
-		if ( pDevice )
-		{
-			int nResult = pDevice->GetInput( data, length );
-			if ( nResult == 0 && milliseconds > 0 )
-			{
-				uint32_t start = getms();
-				do
-				{
-					delayms( 1 );
-					nResult = pDevice->GetInput( data, length );
-				} while ( nResult == 0 && ( getms() - start ) < milliseconds );
-			}
-			return nResult;
-		}
-		LOGV( "controller was disconnected" );
-	}
-	return -1; // Controller was disconnected
-}
-
-// TODO: Implement blocking
-int  HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length)
-{
-	LOGV( "hid_read id=%d length=%u", device->m_nId, length );
-	return hid_read_timeout( device, data, length, 0 );
-}
-
-// TODO: Implement?
-int  HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock)
-{
-	return -1;
-}
-
-int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length)
-{
-	if ( device )
-	{
-		LOGV( "hid_send_feature_report id=%d length=%u", device->m_nId, length );
-		hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
-		if ( pDevice )
-		{
-			return pDevice->SendFeatureReport( data, length );
-		}
-	}
-	return -1; // Controller was disconnected
-}
-
-
-// Synchronous operation. Will block until completed.
-int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length)
-{
-	if ( device )
-	{
-		LOGV( "hid_get_feature_report id=%d length=%u", device->m_nId, length );
-		hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
-		if ( pDevice )
-		{
-			return pDevice->GetFeatureReport( data, length );
-		}
-	}
-	return -1; // Controller was disconnected
-}
-
-
-void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device)
-{
-	if ( device )
-	{
-		LOGV( "hid_close id=%d", device->m_nId );
-		hid_mutex_guard r( &g_DevicesRefCountMutex );
-		LOGD("Decrementing device %d (%p), refCount = %d\n", device->m_nId, device, device->m_nDeviceRefCount - 1);
-		if ( --device->m_nDeviceRefCount == 0 )
-		{
-			hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
-			if ( pDevice )
-			{
-				pDevice->Close( true );
-			}
-			else
-			{
-				delete device;
-			}
-			LOGD("Deleted device %p\n", device);
-		}
-	}
-}
-
-int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen)
-{
-	if ( device )
-	{
-		hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
-		if ( pDevice )
-		{
-			wcsncpy( string, pDevice->GetDeviceInfo()->manufacturer_string, maxlen );
-			return 0;
-		}
-	}
-	return -1;
-}
-
-int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen)
-{
-	if ( device )
-	{
-		hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
-		if ( pDevice )
-		{
-			wcsncpy( string, pDevice->GetDeviceInfo()->product_string, maxlen );
-			return 0;
-		}
-	}
-	return -1;
-}
-
-int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen)
-{
-	if ( device )
-	{
-		hid_device_ref<CHIDDevice> pDevice = FindDevice( device->m_nId );
-		if ( pDevice )
-		{
-			wcsncpy( string, pDevice->GetDeviceInfo()->serial_number, maxlen );
-			return 0;
-		}
-	}
-	return -1;
-}
-
-int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen)
-{
-	return -1;
-}
-
-HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device)
-{
-	return NULL;
-}
-
-int hid_exit(void)
-{
-	return 0;
-}
-
-}
-
-#else
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz);
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz);
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface, int nInterfaceClass, int nInterfaceSubclass, int nInterfaceProtocol );
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID);
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, int nDeviceID, bool bOpened);
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, int nDeviceID);
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value);
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceFeatureReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value);
-
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback)(JNIEnv *env, jobject thiz )
-{
-	LOGV("Stub HIDDeviceRegisterCallback()");
-}
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback)(JNIEnv *env, jobject thiz)
-{
-	LOGV("Stub HIDDeviceReleaseCallback()");
-}
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected)(JNIEnv *env, jobject thiz, int nDeviceID, jstring sIdentifier, int nVendorId, int nProductId, jstring sSerialNumber, int nReleaseNumber, jstring sManufacturer, jstring sProduct, int nInterface, int nInterfaceClass, int nInterfaceSubclass, int nInterfaceProtocol )
-{
-	LOGV("Stub HIDDeviceConnected() id=%d VID/PID = %.4x/%.4x, interface %d\n", nDeviceID, nVendorId, nProductId, nInterface);
-}
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending)(JNIEnv *env, jobject thiz, int nDeviceID)
-{
-	LOGV("Stub HIDDeviceOpenPending() id=%d\n", nDeviceID);
-}
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult)(JNIEnv *env, jobject thiz, int nDeviceID, bool bOpened)
-{
-	LOGV("Stub HIDDeviceOpenResult() id=%d, result=%s\n", nDeviceID, bOpened ? "true" : "false");
-}
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected)(JNIEnv *env, jobject thiz, int nDeviceID)
-{
-	LOGV("Stub HIDDeviceDisconnected() id=%d\n", nDeviceID);
-}
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value)
-{
-	LOGV("Stub HIDDeviceInput() id=%d len=%u\n", nDeviceID, nBufSize);
-}
-
-extern "C"
-JNIEXPORT void JNICALL HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceFeatureReport)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value)
-{
-	LOGV("Stub HIDDeviceFeatureReport() id=%d len=%u\n", nDeviceID, nBufSize);
-}
-
-#endif /* SDL_HIDAPI_DISABLED */
-
-extern "C"
-JNINativeMethod HIDDeviceManager_tab[8] = {
-        { "HIDDeviceRegisterCallback", "()V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceRegisterCallback) },
-        { "HIDDeviceReleaseCallback", "()V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReleaseCallback) },
-        { "HIDDeviceConnected", "(ILjava/lang/String;IILjava/lang/String;ILjava/lang/String;Ljava/lang/String;IIII)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceConnected) },
-        { "HIDDeviceOpenPending", "(I)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenPending) },
-        { "HIDDeviceOpenResult", "(IZ)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceOpenResult) },
-        { "HIDDeviceDisconnected", "(I)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceDisconnected) },
-        { "HIDDeviceInputReport", "(I[B)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceInputReport) },
-        { "HIDDeviceFeatureReport", "(I[B)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceFeatureReport) }
-};
diff --git a/src/hidapi/android/hid.h b/src/hidapi/android/hid.h
deleted file mode 100644
index 5e6253b..0000000
--- a/src/hidapi/android/hid.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 2022 Valve Corporation
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-
-// Purpose: Exporting table containing HIDDeviceManager native methods
-
-#ifndef SDL_android_hid_h_
-#define SDL_android_hid_h_
-
-#include <jni.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern JNINativeMethod HIDDeviceManager_tab[8];
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/src/hidapi/android/jni/Android.mk b/src/hidapi/android/jni/Android.mk
deleted file mode 100644
index 4462e88..0000000
--- a/src/hidapi/android/jni/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-HIDAPI_ROOT_REL:= ../..
-HIDAPI_ROOT_ABS:= $(LOCAL_PATH)/../..
-
-include $(CLEAR_VARS)
-
-LOCAL_CPPFLAGS += -std=c++11
-
-LOCAL_SRC_FILES := \
-  $(HIDAPI_ROOT_REL)/android/hid.cpp
-
-LOCAL_MODULE := libhidapi
-LOCAL_LDLIBS := -llog
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/src/hidapi/android/jni/Application.mk b/src/hidapi/android/jni/Application.mk
deleted file mode 100644
index 4fc6ba5..0000000
--- a/src/hidapi/android/jni/Application.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-APP_STL := gnustl_static
-APP_ABI := armeabi-v7a
diff --git a/src/hidapi/android/project.properties b/src/hidapi/android/project.properties
deleted file mode 100644
index 6e18427..0000000
--- a/src/hidapi/android/project.properties
+++ /dev/null
@@ -1,14 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system edit
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-#
-# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
-#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
-
-# Project target.
-target=android-21
diff --git a/src/hidapi/configure.ac b/src/hidapi/configure.ac
index c6747f9..cc7ceac 100644
--- a/src/hidapi/configure.ac
+++ b/src/hidapi/configure.ac
@@ -1,13 +1,9 @@
 AC_PREREQ(2.63)
 
-# Version number. This is currently the only place.
-m4_define([HIDAPI_MAJOR],   0)
-m4_define([HIDAPI_MINOR],   8)
-m4_define([HIDAPI_RELEASE], 0)
-m4_define([HIDAPI_RC],      -rc1)
-m4_define([VERSION_STRING], HIDAPI_MAJOR[.]HIDAPI_MINOR[.]HIDAPI_RELEASE[]HIDAPI_RC)
+AC_INIT([hidapi],[m4_normalize(m4_builtin([include], VERSION))],[https://github.com/libusb/hidapi/issues])
 
-AC_INIT([hidapi],[VERSION_STRING],[alan@signal11.us])
+echo "This build script for HIDAPI is deprecated."
+echo "Consider using CMake instead."
 
 # Library soname version
 # Follow the following rules (particularly the ones in the second link):
@@ -20,7 +16,6 @@
 
 AC_CONFIG_MACRO_DIR([m4])
 AM_INIT_AUTOMAKE([foreign -Wall -Werror])
-AC_CONFIG_MACRO_DIR([m4])
 
 m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
 LT_INIT
@@ -63,14 +58,14 @@
 
 	# HIDAPI/hidraw libs
 	PKG_CHECK_MODULES([libudev], [libudev], true, [hidapi_lib_error libudev])
-	LIBS_HIDRAW_PR+=" $libudev_LIBS"
-	CFLAGS_HIDRAW+=" $libudev_CFLAGS"
+	LIBS_HIDRAW_PR="${LIBS_HIDRAW_PR} $libudev_LIBS"
+	CFLAGS_HIDRAW="${CFLAGS_HIDRAW} $libudev_CFLAGS"
 
 	# HIDAPI/libusb libs
-	AC_CHECK_LIB([rt], [clock_gettime], [LIBS_LIBUSB_PRIVATE+=" -lrt"], [hidapi_lib_error librt])
+	AC_CHECK_LIB([rt], [clock_gettime], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -lrt"], [hidapi_lib_error librt])
 	PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.9], true, [hidapi_lib_error libusb-1.0])
-	LIBS_LIBUSB_PRIVATE+=" $libusb_LIBS"
-	CFLAGS_LIBUSB+=" $libusb_CFLAGS"
+	LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} $libusb_LIBS"
+	CFLAGS_LIBUSB="${CFLAGS_LIBUSB} $libusb_CFLAGS"
 	;;
 *-darwin*)
 	AC_MSG_RESULT([ (Mac OS X back-end)])
@@ -79,7 +74,7 @@
 	backend="mac"
 	os="darwin"
 	threads="pthreads"
-	LIBS="${LIBS} -framework IOKit -framework CoreFoundation"
+	LIBS="${LIBS} -framework IOKit -framework CoreFoundation -framework AppKit"
 	;;
 *-freebsd*)
 	AC_MSG_RESULT([ (FreeBSD back-end)])
@@ -92,9 +87,10 @@
 	CFLAGS="$CFLAGS -I/usr/local/include"
 	LDFLAGS="$LDFLAGS -L/usr/local/lib"
 	LIBS="${LIBS}"
-	AC_CHECK_LIB([usb], [libusb_init], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -lusb"], [hidapi_lib_error libusb])
+	PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.9], true, [hidapi_lib_error libusb-1.0])
+	LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} $libusb_LIBS"
+	CFLAGS_LIBUSB="${CFLAGS_LIBUSB} $libusb_CFLAGS"
 	AC_CHECK_LIB([iconv], [iconv_open], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -liconv"], [hidapi_lib_error libiconv])
-	echo libs_priv: $LIBS_LIBUSB_PRIVATE
 	;;
 *-kfreebsd*)
 	AC_MSG_RESULT([ (kFreeBSD back-end)])
@@ -104,8 +100,22 @@
 	os="kfreebsd"
 	threads="pthreads"
 
-	AC_CHECK_LIB([usb], [libusb_init], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -lusb"], [hidapi_lib_error libusb])
-	echo libs_priv: $LIBS_LIBUSB_PRIVATE
+	PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.9], true, [hidapi_lib_error libusb-1.0])
+	LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} $libusb_LIBS"
+	CFLAGS_LIBUSB="${CFLAGS_LIBUSB} $libusb_CFLAGS"
+	;;
+*-*-haiku)
+	AC_MSG_RESULT([ (Haiku back-end)])
+	AC_DEFINE(OS_HAIKU, 1, [Haiku implementation])
+	AC_SUBST(OS_HAIKU)
+	backend="libusb"
+	os="haiku"
+	threads="pthreads"
+
+	PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.9], true, [hidapi_lib_error libusb-1.0])
+	LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} $libusb_LIBS"
+	CFLAGS_LIBUSB="${CFLAGS_LIBUSB} $libusb_CFLAGS"
+	AC_CHECK_LIB([iconv], [libiconv_open], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -liconv"], [hidapi_lib_error libiconv])
 	;;
 *-mingw*)
 	AC_MSG_RESULT([ (Windows back-end, using MinGW)])
@@ -113,6 +123,15 @@
 	os="windows"
 	threads="windows"
 	win_implementation="mingw"
+	LDFLAGS="${LDFLAGS} -static-libgcc"
+	;;
+*-msys*)
+	AC_MSG_RESULT([ (Windows back-end, using MSYS2)])
+	backend="windows"
+	os="windows"
+	threads="windows"
+	win_implementation="mingw"
+	LDFLAGS="${LDFLAGS} -static-libgcc"
 	;;
 *-cygwin*)
 	AC_MSG_RESULT([ (Windows back-end, using Cygwin)])
@@ -136,7 +155,7 @@
 	AC_DEFINE(OS_WINDOWS, 1, [Windows implementations])
 	AC_SUBST(OS_WINDOWS)
 	LDFLAGS="${LDFLAGS} -no-undefined"
-	LIBS="${LIBS} -lsetupapi"
+	LIBS="${LIBS}"
 fi
 
 if test "x$threads" = xpthreads; then
@@ -175,15 +194,15 @@
 
 if test "x$testgui_enabled" != "xno"; then
 	if test "x$os" = xdarwin; then
-		# On Mac OS, don't use pkg-config.
+		# On Mac OS, do not use pkg-config.
 		AC_CHECK_PROG([foxconfig], [fox-config], [fox-config], false)
 		if test "x$foxconfig" = "xfalse"; then
 			hidapi_prog_error fox-config "FOX Toolkit"
 		fi
-		LIBS_TESTGUI+=`$foxconfig --libs`
-		LIBS_TESTGUI+=" -framework Cocoa -L/usr/X11R6/lib"
-		CFLAGS_TESTGUI+=`$foxconfig --cflags`
-		OBJCFLAGS+=" -x objective-c++"
+		LIBS_TESTGUI="${LIBS_TESTGUI} `$foxconfig --libs`"
+		LIBS_TESTGUI="${LIBS_TESTGUI} -framework Cocoa -L/usr/X11R6/lib"
+		CFLAGS_TESTGUI="${CFLAGS_TESTGUI} `$foxconfig --cflags`"
+		OBJCFLAGS="${OBJCFLAGS} -x objective-c++"
 	elif test "x$os" = xwindows; then
 		# On Windows, just set the paths for Fox toolkit
 		if test "x$win_implementation" = xmingw; then
@@ -213,6 +232,7 @@
 AM_CONDITIONAL(OS_DARWIN, test "x$os" = xdarwin)
 AM_CONDITIONAL(OS_FREEBSD, test "x$os" = xfreebsd)
 AM_CONDITIONAL(OS_KFREEBSD, test "x$os" = xkfreebsd)
+AM_CONDITIONAL(OS_HAIKU, test "x$os" = xhaiku)
 AM_CONDITIONAL(OS_WINDOWS, test "x$os" = xwindows)
 
 AC_CONFIG_HEADERS([config.h])
diff --git a/src/hidapi/dist/hidapi.podspec b/src/hidapi/dist/hidapi.podspec
new file mode 100644
index 0000000..74642ef
--- /dev/null
+++ b/src/hidapi/dist/hidapi.podspec
@@ -0,0 +1,31 @@
+Pod::Spec.new do |spec|
+
+  spec.name         = "hidapi"
+  spec.version      = File.read('../VERSION')
+  spec.summary      = "A Simple library for communicating with USB and Bluetooth HID devices on Linux, Mac and Windows."
+
+  spec.description  = <<-DESC
+  HIDAPI is a multi-platform library which allows an application to interface with USB and Bluetooth HID-Class devices on Windows, Linux, FreeBSD, and macOS. HIDAPI can be either built as a shared library (.so, .dll or .dylib) or can be embedded directly into a target application by adding a single source file (per platform) and a single header.
+                   DESC
+
+  spec.homepage     = "https://github.com/libusb/hidapi"
+
+  spec.license      = { :type=> "GNU GPLv3 or BSD or HIDAPI original", :file => "LICENSE.txt" }
+
+  spec.authors      = { "Alan Ott" => "alan@signal11.us",
+                        "Ludovic Rousseau" => "rousseau@debian.org",
+                        "libusb/hidapi Team" => "https://github.com/libusb/hidapi/blob/master/AUTHORS.txt",
+                      }
+
+  spec.platform     = :osx
+  spec.osx.deployment_target = "10.7"
+
+  spec.source       = { :git => "https://github.com/libusb/hidapi.git", :tag => "hidapi-#{spec.version}" }
+
+  spec.source_files = "mac/hid.c", "hidapi/hidapi.h", "mac/hidapi_darwin.h"
+
+  spec.public_header_files = "hidapi/hidapi.h", "mac/hidapi_darwin.h"
+
+  spec.frameworks   = "IOKit", "CoreFoundation", "AppKit"
+
+end
diff --git a/src/hidapi/documentation/cmake-gui-drop-down.png b/src/hidapi/documentation/cmake-gui-drop-down.png
new file mode 100644
index 0000000..548abe8
--- /dev/null
+++ b/src/hidapi/documentation/cmake-gui-drop-down.png
Binary files differ
diff --git a/src/hidapi/documentation/cmake-gui-highlights.png b/src/hidapi/documentation/cmake-gui-highlights.png
new file mode 100644
index 0000000..228838f
--- /dev/null
+++ b/src/hidapi/documentation/cmake-gui-highlights.png
Binary files differ
diff --git a/src/hidapi/doxygen/Doxyfile b/src/hidapi/doxygen/Doxyfile
index 9d983e9..4e01360 100644
--- a/src/hidapi/doxygen/Doxyfile
+++ b/src/hidapi/doxygen/Doxyfile
@@ -1,96 +1,151 @@
-# Doxyfile 1.7.1
+# Doxyfile 1.9.6
 
 # This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project
+# doxygen (www.doxygen.org) for a project.
 #
-# All text after a hash (#) is considered a comment and will be ignored
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
 # The format is:
-#       TAG = value [value, ...]
-# For lists items can also be appended using:
-#       TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+#
+# Note:
+#
+# Use doxygen to compare the used configuration file with the template
+# configuration file:
+# doxygen -x [configFile]
+# Use doxygen to compare the used configuration file with the template
+# configuration file without replacing the environment variables or CMake type
+# replacement variables:
+# doxygen -x_noenv [configFile]
 
 #---------------------------------------------------------------------------
 # Project related configuration options
 #---------------------------------------------------------------------------
 
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
 # text before the first occurrence of this tag. Doxygen uses libiconv (or the
 # iconv built into libc) for the transcoding. See
-# http://www.gnu.org/software/libiconv for the list of possible encodings.
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
 
 DOXYFILE_ENCODING      = UTF-8
 
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
 
 PROJECT_NAME           = hidapi
 
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
 
 PROJECT_NUMBER         =
 
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
 
 OUTPUT_DIRECTORY       =
 
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
+# sub-directories (in 2 levels) under the output directory of each output format
+# and will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
+# control the number of sub-directories.
+# The default value is: NO.
 
 CREATE_SUBDIRS         = NO
 
+# Controls the number of sub-directories that will be created when
+# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
+# level increment doubles the number of directories, resulting in 4096
+# directories at level 8 which is the default and also the maximum value. The
+# sub-directories are organized in 2 levels, the first level always has a fixed
+# number of 16 directories.
+# Minimum value: 0, maximum value: 8, default value: 8.
+# This tag requires that the tag CREATE_SUBDIRS is set to YES.
+
+CREATE_SUBDIRS_LEVEL   = 8
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
 # The OUTPUT_LANGUAGE tag is used to specify the language in which all
 # documentation generated by doxygen is written. Doxygen will use this
 # information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
-# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
+# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
+# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
+# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
+# English messages), Korean, Korean-en (Korean with English messages), Latvian,
+# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
+# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
+# Swedish, Turkish, Ukrainian and Vietnamese.
+# The default value is: English.
 
 OUTPUT_LANGUAGE        = English
 
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
 
 BRIEF_MEMBER_DESC      = YES
 
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
 # brief descriptions will be completely suppressed.
+# The default value is: YES.
 
 REPEAT_BRIEF           = YES
 
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
 
 ABBREVIATE_BRIEF       =
 
 # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
+# doxygen will generate a detailed section even if there is only a brief
 # description.
+# The default value is: NO.
 
 ALWAYS_DETAILED_SEC    = NO
 
@@ -98,531 +153,831 @@
 # inherited members of a class in the documentation of that class as if those
 # members were ordinary class members. Constructors, destructors and assignment
 # operators of the base classes will not be shown.
+# The default value is: NO.
 
 INLINE_INHERITED_MEMB  = NO
 
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
 
 FULL_PATH_NAMES        = YES
 
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
 
-STRIP_FROM_PATH        =
+STRIP_FROM_PATH        = ../
 
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
 
 STRIP_FROM_INC_PATH    =
 
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful is your file systems
-# doesn't support long names like on DOS, Mac, or CD-ROM.
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
 
 SHORT_NAMES            = NO
 
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like regular Qt-style comments
-# (thus requiring an explicit @brief command for a brief description.)
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
 
 JAVADOC_AUTOBRIEF      = NO
 
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
-# interpret the first line (until the first dot) of a Qt-style
-# comment as the brief description. If set to NO, the comments
-# will behave just like regular Qt-style comments (thus requiring
-# an explicit \brief command for a brief description.)
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER         = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
 
 QT_AUTOBRIEF           = NO
 
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
 
 MULTILINE_CPP_IS_BRIEF = NO
 
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
+# By default Python docstrings are displayed as preformatted text and doxygen's
+# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
+# doxygen's special commands can be used and the contents of the docstring
+# documentation blocks is shown as doxygen documentation.
+# The default value is: YES.
+
+PYTHON_DOCSTRING       = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
 
 INHERIT_DOCS           = YES
 
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
-# be part of the file/class/namespace that contains it.
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
 
 SEPARATE_MEMBER_PAGES  = NO
 
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
 
 TAB_SIZE               = 8
 
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:^^"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". Note that you cannot put \n's in the value part of an alias
+# to insert newlines (in the resulting output). You can put ^^ in the value part
+# of an alias to insert a newline as if a physical newline was in the original
+# file. When you need a literal { or } or , in the value part of an alias you
+# have to escape them by means of a backslash (\), this can lead to conflicts
+# with the commands \{ and \} for these it is advised to use the version @{ and
+# @} or use a double escape (\\{ and \\})
 
 ALIASES                =
 
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
 
 OPTIMIZE_OUTPUT_FOR_C  = YES
 
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
-# scopes will look different, etc.
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
 
 OPTIMIZE_OUTPUT_JAVA   = NO
 
 # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources only. Doxygen will then generate output that is more tailored for
-# Fortran.
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
 
 OPTIMIZE_FOR_FORTRAN   = NO
 
 # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for
-# VHDL.
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
 
 OPTIMIZE_OUTPUT_VHDL   = NO
 
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE  = NO
+
 # Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given extension.
-# Doxygen has a built-in mapping, but you can override or extend it using this
-# tag. The format is ext=language, where ext is a file extension, and language
-# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
-# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
-# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
-# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
-# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
+# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
+# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files). For instance to make doxygen treat .inc files
+# as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen. When specifying no_extension you should add
+# * to the FILE_PATTERNS.
+#
+# Note see also the list of default file extension mappings.
 
 EXTENSION_MAPPING      =
 
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = NO
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS   = 5
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
 # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also make the inheritance and collaboration
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
 # diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
 
 BUILTIN_STL_SUPPORT    = NO
 
 # If you use Microsoft's C++/CLI language, you should set this option to YES to
 # enable parsing support.
+# The default value is: NO.
 
 CPP_CLI_SUPPORT        = NO
 
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
-# Doxygen will parse them like normal C++ but will assume all classes use public
-# instead of private inheritance when no explicit protection keyword is present.
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
 
 SIP_SUPPORT            = NO
 
-# For Microsoft's IDL there are propget and propput attributes to indicate getter
-# and setter methods for a property. Setting this option to YES (the default)
-# will make doxygen to replace the get and set methods by a property in the
-# documentation. This will only work if the methods are indeed getting or
-# setting a simple type. If this is not the case, or you want to show the
-# methods anyway, you should set this option to NO.
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
 
 IDL_PROPERTY_SUPPORT   = YES
 
 # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES, then doxygen will reuse the documentation of the first
+# tag is set to YES then doxygen will reuse the documentation of the first
 # member in the group (if any) for the other members of the group. By default
 # all members of a group must be documented explicitly.
+# The default value is: NO.
 
 DISTRIBUTE_GROUP_DOC   = NO
 
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
 
 SUBGROUPING            = YES
 
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
 # typedef struct TypeS {} TypeT, will appear in the documentation as a struct
 # with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically
-# be useful for C code in case the coding convention dictates that all compound
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
 # types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
 
 TYPEDEF_HIDES_STRUCT   = NO
 
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penality.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will rougly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
 
-SYMBOL_CACHE_SIZE      = 0
+LOOKUP_CACHE_SIZE      = 0
+
+# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
+# during processing. When set to 0 doxygen will based this on the number of
+# cores available in the system. You can set it explicitly to a value larger
+# than 0 to get more control over the balance between CPU load and processing
+# speed. At this moment only the input processing can be done using multiple
+# threads. Since this is still an experimental feature the default is set to 1,
+# which effectively disables parallel processing. Please report any issues you
+# encounter. Generating dot graphs in parallel is controlled by the
+# DOT_NUM_THREADS setting.
+# Minimum value: 0, maximum value: 32, default value: 1.
+
+NUM_PROC_THREADS       = 1
 
 #---------------------------------------------------------------------------
 # Build related configuration options
 #---------------------------------------------------------------------------
 
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
 
 EXTRACT_ALL            = NO
 
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
 
 EXTRACT_PRIVATE        = NO
 
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL   = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
 
 EXTRACT_STATIC         = NO
 
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
 
 EXTRACT_LOCAL_CLASSES  = YES
 
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
 
 EXTRACT_LOCAL_METHODS  = NO
 
 # If this flag is set to YES, the members of anonymous namespaces will be
 # extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base
-# name of the file that contains the anonymous namespace. By default
-# anonymous namespace are hidden.
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
 
 EXTRACT_ANON_NSPACES   = NO
 
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
+# If this flag is set to YES, the name of an unnamed parameter in a declaration
+# will be determined by the corresponding definition. By default unnamed
+# parameters remain unnamed in the output.
+# The default value is: YES.
+
+RESOLVE_UNNAMED_PARAMS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
 
 HIDE_UNDOC_MEMBERS     = NO
 
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# will also hide undocumented C++ concepts if enabled. This option has no effect
+# if EXTRACT_ALL is enabled.
+# The default value is: NO.
 
 HIDE_UNDOC_CLASSES     = NO
 
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# declarations. If set to NO, these declarations will be included in the
 # documentation.
+# The default value is: NO.
 
 HIDE_FRIEND_COMPOUNDS  = NO
 
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
 
 HIDE_IN_BODY_DOCS      = NO
 
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
 
 INTERNAL_DOCS          = NO
 
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
+# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
+# able to match the capabilities of the underlying filesystem. In case the
+# filesystem is case sensitive (i.e. it supports files in the same directory
+# whose names only differ in casing), the option must be set to YES to properly
+# deal with such files in case they appear in the input. For filesystems that
+# are not case sensitive the option should be set to NO to properly deal with
+# output files written for symbols that only differ in casing, such as for two
+# classes, one named CLASS and the other named Class, and to also support
+# references to files without having to specify the exact matching casing. On
+# Windows (including Cygwin) and MacOS, users should typically set this option
+# to NO, whereas on Linux or other Unix flavors it should typically be set to
+# YES.
+# Possible values are: SYSTEM, NO and YES.
+# The default value is: SYSTEM.
 
 CASE_SENSE_NAMES       = YES
 
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
 
 HIDE_SCOPE_NAMES       = NO
 
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
+# will show which file needs to be included to use the class.
+# The default value is: YES.
+
+SHOW_HEADERFILE        = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
 
 SHOW_INCLUDE_FILES     = YES
 
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
-# will list include files with double quotes in the documentation
-# rather than with sharp brackets.
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
 
 FORCE_LOCAL_INCLUDES   = NO
 
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
 
 INLINE_INFO            = YES
 
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
 
 SORT_MEMBER_DOCS       = YES
 
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
 
 SORT_BRIEF_DOCS        = NO
 
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
-# will sort the (brief and detailed) documentation of class members so that
-# constructors and destructors are listed first. If set to NO (the default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
-# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
 
 SORT_MEMBERS_CTORS_1ST = NO
 
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
-# hierarchy of group names into alphabetical order. If set to NO (the default)
-# the group names will appear in their defined order.
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
 
 SORT_GROUP_NAMES       = NO
 
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
 # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
 
 SORT_BY_SCOPE_NAME     = NO
 
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
 
 GENERATE_TODOLIST      = YES
 
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
 
 GENERATE_TESTLIST      = YES
 
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
 
 GENERATE_BUGLIST       = YES
 
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
 
 GENERATE_DEPRECATEDLIST= YES
 
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
 
 ENABLED_SECTIONS       =
 
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or define consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and defines in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
 
 MAX_INITIALIZER_LINES  = 30
 
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
 # list will mention the files that were used to generate the documentation.
+# The default value is: YES.
 
 SHOW_USED_FILES        = YES
 
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES       = NO
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
-# This will remove the Files entry from the Quick Index and from the
-# Folder Tree View (if specified). The default is YES.
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
 
 SHOW_FILES             = YES
 
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
-# Namespaces page.
-# This will remove the Namespaces entry from the Quick Index
-# and from the Folder Tree View (if specified). The default is YES.
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
 
 SHOW_NAMESPACES        = YES
 
 # The FILE_VERSION_FILTER tag can be used to specify a program or script that
 # doxygen should invoke to get the current version for each file (typically from
 # the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
-# is used as the file version. See the manual for examples.
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
 
 FILE_VERSION_FILTER    =
 
 # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
 # by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. The create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option.
-# You can optionally specify a file name after the option, if omitted
-# DoxygenLayout.xml will be used as the name of the layout file.
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file. See also section "Changing the
+# layout of pages" for information.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
 
 LAYOUT_FILE            =
 
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
 #---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
+# Configuration options related to warning and progress messages
 #---------------------------------------------------------------------------
 
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
 
 QUIET                  = NO
 
 # The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
 
 WARNINGS               = YES
 
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
 
 WARN_IF_UNDOCUMENTED   = YES
 
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as documenting some parameters in
+# a documented function twice, or documenting parameters that don't exist or
+# using markup commands wrongly.
+# The default value is: YES.
 
 WARN_IF_DOC_ERROR      = YES
 
-# This WARN_NO_PARAMDOC option can be abled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
+# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
+# function parameter documentation. If set to NO, doxygen will accept that some
+# parameters have no documentation without warning.
+# The default value is: YES.
+
+WARN_IF_INCOMPLETE_DOC = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong parameter
+# documentation, but not about the absence of documentation. If EXTRACT_ALL is
+# set to YES then this flag will automatically be disabled. See also
+# WARN_IF_INCOMPLETE_DOC
+# The default value is: NO.
 
 WARN_NO_PARAMDOC       = NO
 
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
-# be obtained via FILE_VERSION_FILTER)
+# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
+# undocumented enumeration values. If set to NO, doxygen will accept
+# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: NO.
+
+WARN_IF_UNDOC_ENUM_VAL = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
+# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
+# at the end of the doxygen process doxygen will return with a non-zero status.
+# Possible values are: NO, YES and FAIL_ON_WARNINGS.
+# The default value is: NO.
+
+WARN_AS_ERROR          = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# See also: WARN_LINE_FORMAT
+# The default value is: $file:$line: $text.
 
 WARN_FORMAT            = "$file:$line: $text"
 
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
+# In the $text part of the WARN_FORMAT command it is possible that a reference
+# to a more specific place is given. To make it easier to jump to this place
+# (outside of doxygen) the user can define a custom "cut" / "paste" string.
+# Example:
+# WARN_LINE_FORMAT = "'vi $file +$line'"
+# See also: WARN_FORMAT
+# The default value is: at line $line of file $file.
+
+WARN_LINE_FORMAT       = "at line $line of file $file"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr). In case the file specified cannot be opened for writing the
+# warning and error messages are written to standard error. When as file - is
+# specified the warning and error messages are written to standard output
+# (stdout).
 
 WARN_LOGFILE           =
 
 #---------------------------------------------------------------------------
-# configuration options related to the input files
+# Configuration options related to the input files
 #---------------------------------------------------------------------------
 
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
 
-INPUT                  = ../hidapi
+INPUT                  = ../hidapi \
+                         ./main_page.md
 
 # This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
-# the list of possible encodings.
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see:
+# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
+# See also: INPUT_FILE_ENCODING
+# The default value is: UTF-8.
 
 INPUT_ENCODING         = UTF-8
 
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
+# character encoding on a per file pattern basis. Doxygen will compare the file
+# name with each pattern and apply the encoding instead of the default
+# INPUT_ENCODING) if there is a match. The character encodings are a list of the
+# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
+# "INPUT_ENCODING" for further information on supported encodings.
+
+INPUT_FILE_ENCODING    =
+
 # If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
-# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# Note the list of default checked file patterns might differ from the list of
+# default file extension mappings.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
+# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
+# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
+# *.vhdl, *.ucf, *.qsf and *.ice.
 
 FILE_PATTERNS          =
 
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
 
 RECURSIVE              = NO
 
-# The EXCLUDE tag can be used to specify files and/or directories that should
+# The EXCLUDE tag can be used to specify files and/or directories that should be
 # excluded from the INPUT source files. This way you can easily exclude a
 # subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
 
 EXCLUDE                =
 
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
-# directories that are symbolic links (a Unix filesystem feature) are excluded
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
 # from the input.
+# The default value is: NO.
 
 EXCLUDE_SYMLINKS       = NO
 
 # If the value of the INPUT tag contains directories, you can use the
 # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
-# for example use the pattern */test/*
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
 
 EXCLUDE_PATTERNS       =
 
@@ -630,689 +985,1278 @@
 # (namespaces, classes, functions, etc.) that should be excluded from the
 # output. The symbol name can be a fully qualified name, a word, or if the
 # wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
+# ANamespace::AClass, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
 
-EXCLUDE_SYMBOLS        =
+EXCLUDE_SYMBOLS        = HID_API_AS_STR_IMPL \
+                         HID_API_AS_STR \
+                         HID_API_TO_VERSION_STR
 
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
 
-EXAMPLE_PATH           =
+EXAMPLE_PATH           = ../hidtest
 
 # If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
 
-EXAMPLE_PATTERNS       =
+EXAMPLE_PATTERNS       = *.c
 
 # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
 
 EXAMPLE_RECURSIVE      = NO
 
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
 
 IMAGE_PATH             =
 
 # The INPUT_FILTER tag can be used to specify a program that doxygen should
 # invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
-# If FILTER_PATTERNS is specified, this tag will be
-# ignored.
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that doxygen will use the data processed and written to standard output
+# for further processing, therefore nothing else, like debug statements or used
+# commands (so in case of a Windows batch file always use @echo OFF), should be
+# written to standard output.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
 
 INPUT_FILTER           =
 
 # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis.
-# Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match.
-# The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
-# is applied to all files.
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
 
 FILTER_PATTERNS        =
 
 # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
 
 FILTER_SOURCE_FILES    = NO
 
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = main_page.md
+
+# The Fortran standard specifies that for fixed formatted Fortran code all
+# characters from position 72 are to be considered as comment. A common
+# extension is to allow longer lines before the automatic comment starts. The
+# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
+# be processed before the automatic comment starts.
+# Minimum value: 7, maximum value: 10000, default value: 72.
+
+FORTRAN_COMMENT_AFTER  = 72
+
 #---------------------------------------------------------------------------
-# configuration options related to source browsing
+# Configuration options related to source browsing
 #---------------------------------------------------------------------------
 
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
 
 SOURCE_BROWSER         = NO
 
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
 
 INLINE_SOURCES         = NO
 
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
 
 STRIP_CODE_COMMENTS    = YES
 
-# If the REFERENCED_BY_RELATION tag is set to YES
-# then for each documented function all documented
-# functions referencing it will be listed.
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
 
 REFERENCED_BY_RELATION = NO
 
-# If the REFERENCES_RELATION tag is set to YES
-# then for each documented function all documented entities
-# called/used by that function will be listed.
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
 
 REFERENCES_RELATION    = NO
 
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code.
-# Otherwise they will link to the documentation.
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
 
 REFERENCES_LINK_SOURCE = YES
 
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
-# will need version 4.8.6 or higher.
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
 
 USE_HTAGS              = NO
 
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
 
 VERBATIM_HEADERS       = YES
 
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see:
+# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
+# performance. This can be particularly helpful with template rich C++ code for
+# which doxygen's built-in parser lacks the necessary type information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS
+# tag is set to YES then doxygen will add the directory of each input to the
+# include path.
+# The default value is: YES.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_ADD_INC_PATHS    = YES
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+# If clang assisted parsing is enabled you can provide the clang parser with the
+# path to the directory containing a file called compile_commands.json. This
+# file is the compilation database (see:
+# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
+# options used when the source files were built. This is equivalent to
+# specifying the -p option to a clang tool, such as clang-check. These options
+# will then be passed to the parser. Any options specified with CLANG_OPTIONS
+# will be added as well.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse_libclang=ON option for CMake.
+
+CLANG_DATABASE_PATH    =
+
 #---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
+# Configuration options related to the alphabetical class index
 #---------------------------------------------------------------------------
 
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
 
 ALPHABETICAL_INDEX     = YES
 
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
-
-COLS_IN_ALPHA_INDEX    = 5
-
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
+# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
+# that should be ignored while generating the index headers. The IGNORE_PREFIX
+# tag works for classes, function and member names. The entity will be placed in
+# the alphabetical list under the first letter of the entity name that remains
+# after removing the prefix.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
 
 IGNORE_PREFIX          =
 
 #---------------------------------------------------------------------------
-# configuration options related to the HTML output
+# Configuration options related to the HTML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
 
 GENERATE_HTML          = YES
 
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_OUTPUT            = html
 
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_FILE_EXTENSION    = .html
 
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
 # standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_HEADER            =
 
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_FOOTER            =
 
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# stylesheet in the HTML output directory as well, or it will be erased!
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_STYLESHEET        =
 
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
-# Doxygen will adjust the colors in the stylesheet and background images
-# according to this color. Hue is specified as an angle on a colorwheel,
-# see http://en.wikipedia.org/wiki/Hue for more information.
-# For instance the value 0 represents red, 60 is yellow, 120 is green,
-# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
-# The allowed range is 0 to 359.
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# Note: Since the styling of scrollbars can currently not be overruled in
+# Webkit/Chromium, the styling will be left out of the default doxygen.css if
+# one or more extra stylesheets have been specified. So if scrollbar
+# customization is desired it has to be added explicitly. For an example see the
+# documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
+# should be rendered with a dark or light theme.
+# Possible values are: LIGHT always generate light mode output, DARK always
+# generate dark mode output, AUTO_LIGHT automatically set the mode according to
+# the user preference, use light mode if no preference is set (the default),
+# AUTO_DARK automatically set the mode according to the user preference, use
+# dark mode if no preference is set and TOGGLE allow to user to switch between
+# light and dark mode via a button.
+# The default value is: AUTO_LIGHT.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE        = AUTO_LIGHT
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a color-wheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_COLORSTYLE_HUE    = 220
 
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
-# the colors in the HTML output. For a value of 0 the output will use
-# grayscales only. A value of 255 will produce the most vivid colors.
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use gray-scales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_COLORSTYLE_SAT    = 100
 
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
-# the luminance component of the colors in the HTML output. Values below
-# 100 gradually make the output lighter, whereas values above 100 make
-# the output darker. The value divided by 100 is the actual gamma applied,
-# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
-# and 100 does not change the gamma.
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_COLORSTYLE_GAMMA  = 80
 
 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting
-# this to NO can help when comparing the output of multiple runs.
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_TIMESTAMP         = YES
 
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via JavaScript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have JavaScript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
-HTML_ALIGN_MEMBERS     = YES
+HTML_DYNAMIC_MENUS     = YES
 
 # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
 # documentation will contain sections that can be hidden and shown after the
-# page has loaded. For this to work a browser that supports
-# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
-# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_DYNAMIC_SECTIONS  = NO
 
-# If the GENERATE_DOCSET tag is set to YES, additional index files
-# will be generated that can be used as input for Apple's Xcode 3
-# integrated development environment, introduced with OSX 10.5 (Leopard).
-# To create a documentation set, doxygen will generate a Makefile in the
-# HTML output directory. Running make will produce the docset in that
-# directory and running "make install" will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
-# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see:
+# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
+# create a documentation set, doxygen will generate a Makefile in the HTML
+# output directory. Running make will produce the docset in that directory and
+# running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 GENERATE_DOCSET        = NO
 
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
-# can be grouped.
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
 
 DOCSET_FEEDNAME        = "Doxygen generated docs"
 
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
-# will append .docset to the name.
+# This tag determines the URL of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDURL         =
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
 
 DOCSET_BUNDLE_ID       = org.doxygen.Project
 
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
 # the documentation publisher. This should be a reverse domain-name style
 # string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
 
 DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
 
-# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
 
 DOCSET_PUBLISHER_NAME  = Publisher
 
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
-# of the generated HTML documentation.
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# on Windows. In the beginning of 2021 Microsoft took the original page, with
+# a.o. the download links, offline the HTML help workshop was already many years
+# in maintenance mode). You can download the HTML help workshop from the web
+# archives at Installation executable (see:
+# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
+# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 GENERATE_HTMLHELP      = NO
 
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
 # written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 CHM_FILE               =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 HHC_LOCATION           =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the main .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 GENERATE_CHI           = NO
 
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 CHM_INDEX_ENCODING     =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 BINARY_TOC             = NO
 
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 TOC_EXPAND             = NO
 
 # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
-# that can be used as input for Qt's qhelpgenerator to generate a
-# Qt Compressed Help (.qch) of the generated HTML documentation.
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 GENERATE_QHP           = NO
 
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
-# be used to specify the file name of the resulting .qch file.
-# The path specified is relative to the HTML output folder.
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
 
 QCH_FILE               =
 
-# The QHP_NAMESPACE tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#namespace
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
 
 QHP_NAMESPACE          = org.doxygen.Project
 
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
 
 QHP_VIRTUAL_FOLDER     = doc
 
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
 
 QHP_CUST_FILTER_NAME   =
 
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
-# Qt Help Project / Custom Filters</a>.
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
 
 QHP_CUST_FILTER_ATTRS  =
 
 # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's
-# filter section matches.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
-# Qt Help Project / Filter Attributes</a>.
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
 
 QHP_SECT_FILTER_ATTRS  =
 
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
-# be used to specify the location of Qt's qhelpgenerator.
-# If non-empty doxygen will try to run qhelpgenerator on the generated
-# .qhp file.
+# The QHG_LOCATION tag can be used to specify the location (absolute path
+# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
+# run qhelpgenerator on the generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
 
 QHG_LOCATION           =
 
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
-#  will be generated, which together with the HTML files, form an Eclipse help
-# plugin. To install this plugin and make it available under the help contents
-# menu in Eclipse, the contents of the directory containing the HTML and XML
-# files needs to be copied into the plugins directory of eclipse. The name of
-# the directory within the plugins directory should be the same as
-# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
-# the help appears.
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 GENERATE_ECLIPSEHELP   = NO
 
-# A unique identifier for the eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have
-# this name.
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
 
 ECLIPSE_DOC_ID         = org.doxygen.Project
 
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 DISABLE_INDEX          = NO
 
-# This tag can be used to set the number of enum values (range [1..20])
-# that doxygen will group on one line in the generated HTML documentation.
-
-ENUM_VALUES_PER_LINE   = 4
-
 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information.
-# If the tag value is set to YES, a side panel will be generated
-# containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
-# Windows users are probably better off using the HTML help feature.
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine tune the look of the index (see "Fine-tuning the output"). As an
+# example, the default style sheet generated by doxygen has an example that
+# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
+# Since the tree basically has the same information as the tab index, you could
+# consider setting DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 GENERATE_TREEVIEW      = NO
 
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
+# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
+# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
+# area (value NO) or if it should extend to the full height of the window (value
+# YES). Setting this to YES gives a layout similar to
+# https://docs.readthedocs.io with more room for contents, but less room for the
+# project logo, title, and description. If either GENERATE_TREEVIEW or
+# DISABLE_INDEX is set to NO, this option has no effect.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
-USE_INLINE_TREES       = NO
+FULL_SIDEBAR           = NO
 
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 TREEVIEW_WIDTH         = 250
 
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
-# links to external symbols imported via tag files in a separate window.
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 EXT_LINKS_IN_WINDOW    = NO
 
-# Use this tag to change the font size of Latex formulas included
-# as images in the HTML documentation. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
-# to force them to be regenerated.
+# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
+# addresses.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+OBFUSCATE_EMAILS       = YES
+
+# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
+# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
+# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
+# the HTML output. These images will generally look nicer at scaled resolutions.
+# Possible values are: png (the default) and svg (looks nicer but requires the
+# pdf2svg or inkscape tool).
+# The default value is: png.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FORMULA_FORMAT    = png
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 FORMULA_FONTSIZE       = 10
 
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are
-# not supported properly for IE 6.0, but are supported on all modern browsers.
-# Note that when changing this option you need to delete any form_*.png files
-# in the HTML output before the changes have effect.
+# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
+# to create new LaTeX commands to be used in formulas as building blocks. See
+# the section "Including formulas" for details.
 
-FORMULA_TRANSPARENT    = YES
+FORMULA_MACROFILE      =
 
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box
-# for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using
-# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
-# (GENERATE_DOCSET) there is already a search function so this one should
-# typically be disabled. For large projects the javascript based search engine
-# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side JavaScript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
+# Note that the different versions of MathJax have different requirements with
+# regards to the different settings, so it is possible that also other MathJax
+# settings have to be changed when switching between the different MathJax
+# versions.
+# Possible values are: MathJax_2 and MathJax_3.
+# The default value is: MathJax_2.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_VERSION        = MathJax_2
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. For more details about the output format see MathJax
+# version 2 (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
+# (see:
+# http://docs.mathjax.org/en/latest/web/components/output.html).
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility. This is the name for Mathjax version 2, for MathJax version 3
+# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
+# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
+# is the name for Mathjax version 3, for MathJax version 2 this will be
+# translated into HTML-CSS) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment. The default value is:
+# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
+# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# for MathJax version 2 (see
+# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# For example for MathJax version 3 (see
+# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
+# MATHJAX_EXTENSIONS = ams
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see:
+# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 SEARCHENGINE           = YES
 
 # When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a PHP enabled web server instead of at the web client
-# using Javascript. Doxygen will generate the search PHP script and index
-# file to put on the web server. The advantage of the server
-# based approach is that it scales better to large projects and allows
-# full text search. The disadvances is that it is more difficult to setup
-# and does not have live searching capabilities.
+# implemented using a web server instead of a web client using JavaScript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
 
 SERVER_BASED_SEARCH    = NO
 
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see:
+# https://xapian.org/). See the section "External Indexing and Searching" for
+# details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
 #---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
+# Configuration options related to the LaTeX output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
 
 GENERATE_LATEX         = NO
 
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 LATEX_OUTPUT           = latex
 
 # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-# Note that when enabling USE_PDFLATEX this option is only used for
-# generating bitmaps for formulas in the HTML output, but not in the
-# Makefile that is written to the output directory.
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 LATEX_CMD_NAME         = latex
 
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 MAKEINDEX_CMD_NAME     = makeindex
 
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD    = \makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 COMPACT_LATEX          = NO
 
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, a4wide, letter, legal and
-# executive. If left blank a4wide will be used.
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
-PAPER_TYPE             = a4wide
+PAPER_TYPE             = a4
 
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 EXTRA_PACKAGES         =
 
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
+# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
+# the generated LaTeX document. The header should contain everything until the
+# first chapter. If it is left blank doxygen will generate a standard header. It
+# is highly recommended to start with a default header using
+# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
+# and then modify the file new_header.tex. See also section "Doxygen usage" for
+# information on how to generate the default header that doxygen normally uses.
+#
+# Note: Only use a user-defined header if you know what you are doing!
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. The following
+# commands have a special meaning inside the header (and footer): For a
+# description of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 LATEX_HEADER           =
 
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
+# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
+# the generated LaTeX document. The footer should contain everything after the
+# last chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer. See also section "Doxygen
+# usage" for information on how to generate the default footer that doxygen
+# normally uses. Note: Only use a user-defined footer if you know what you are
+# doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 PDF_HYPERLINKS         = YES
 
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
-# higher quality PDF documentation.
+# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
+# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
+# files. Set this option to YES, to get a higher quality PDF documentation.
+#
+# See also section LATEX_CMD_NAME for selecting the engine.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 USE_PDFLATEX           = YES
 
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 LATEX_BATCHMODE        = NO
 
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 LATEX_HIDE_INDICES     = NO
 
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include
-# source code with syntax highlighting in the LaTeX output.
-# Note that which sources are shown also depends on other settings
-# such as SOURCE_BROWSER.
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
-LATEX_SOURCE_CODE      = NO
+LATEX_BIB_STYLE        = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP        = NO
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY  =
 
 #---------------------------------------------------------------------------
-# configuration options related to the RTF output
+# Configuration options related to the RTF output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
 
 GENERATE_RTF           = NO
 
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
 
 RTF_OUTPUT             = rtf
 
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
 
 COMPACT_RTF            = NO
 
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
 
 RTF_HYPERLINKS         = NO
 
 # Load stylesheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
+# configuration file, i.e. a series of assignments. You only have to provide
 # replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
 
 RTF_STYLESHEET_FILE    =
 
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
 
 RTF_EXTENSIONS_FILE    =
 
 #---------------------------------------------------------------------------
-# configuration options related to the man page output
+# Configuration options related to the man page output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
 
 GENERATE_MAN           = NO
 
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
 
 MAN_OUTPUT             = man
 
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
 
 MAN_EXTENSION          = .3
 
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
 
 MAN_LINKS              = NO
 
 #---------------------------------------------------------------------------
-# configuration options related to the XML output
+# Configuration options related to the XML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
 
 GENERATE_XML           = NO
 
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
 
 XML_OUTPUT             = xml
 
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_SCHEMA             =
-
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
-
-XML_DTD                =
-
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
 
 XML_PROGRAMLISTING     = YES
 
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
 #---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
+# Configuration options related to the DOCBOOK output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
 
 GENERATE_AUTOGEN_DEF   = NO
 
 #---------------------------------------------------------------------------
-# configuration options related to the Perl module output
+# Configuration options related to the Perl module output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
 
 GENERATE_PERLMOD       = NO
 
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
 
 PERLMOD_LATEX          = NO
 
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader.
-# This is useful
-# if you want to understand what is going on.
-# On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
 
 PERLMOD_PRETTY         = YES
 
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
 
 PERLMOD_MAKEVAR_PREFIX =
 
@@ -1320,311 +2264,461 @@
 # Configuration options related to the preprocessor
 #---------------------------------------------------------------------------
 
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
 
 ENABLE_PREPROCESSING   = YES
 
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 MACRO_EXPANSION        = NO
 
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_DEFINED tags.
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 EXPAND_ONLY_PREDEF     = NO
 
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 SEARCH_INCLUDES        = YES
 
 # The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
+# contain include files that are not input files but should be processed by the
+# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
+# RECURSIVE has no effect here.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
 
 INCLUDE_PATH           =
 
 # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
 # patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 INCLUDE_FILE_PATTERNS  =
 
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
-# instead of the = operator.
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 PREDEFINED             =
 
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition.
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 EXPAND_AS_DEFINED      =
 
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all function-like macros that are alone
-# on a line, have an all uppercase name, and do not end with a semicolon. Such
-# function macros are typically used for boiler-plate code, and will confuse
-# the parser if not removed.
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 SKIP_FUNCTION_MACROS   = YES
 
 #---------------------------------------------------------------------------
-# Configuration::additions related to external references
+# Configuration options related to external references
 #---------------------------------------------------------------------------
 
-# The TAGFILES option can be used to specify one or more tagfiles.
-# Optionally an initial location of the external documentation
-# can be added for each tagfile. The format of a tag file without
-# this location is as follows:
-#
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
 # TAGFILES = file1 file2 ...
 # Adding location for the tag files is done as follows:
-#
 # TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths or
-# URLs. If a location is present for each tag, the installdox tool
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen
-# is run, you must also specify the path to the tagfile here.
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
 
 TAGFILES               =
 
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
 
 GENERATE_TAGFILE       =
 
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
 
 ALLEXTERNALS           = NO
 
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
 
 EXTERNAL_GROUPS        = YES
 
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
 
-PERL_PATH              = /usr/bin/perl
+EXTERNAL_PAGES         = YES
 
 #---------------------------------------------------------------------------
 # Configuration options related to the dot tool
 #---------------------------------------------------------------------------
 
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option is superseded by the HAVE_DOT option below. This is only a
-# fallback. It is recommended to install and use dot, since it yields more
-# powerful graphs.
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
 
-CLASS_DIAGRAMS         = YES
+DIA_PATH               =
 
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH            =
-
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
 
 HIDE_UNDOC_RELATIONS   = YES
 
 # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
 
 HAVE_DOT               = NO
 
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) doxygen will
-# base this on the number of processors available in the system. You can set it
-# explicitly to a value larger than 0 to get control over the balance
-# between CPU load and processing speed.
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_NUM_THREADS        = 0
 
-# By default doxygen will write a font called FreeSans.ttf to the output
-# directory and reference it in all dot files that doxygen generates. This
-# font does not include all possible unicode characters however, so when you need
-# these (or just want a differently looking font) you can specify the font name
-# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
-# which can be done by putting it in a standard location or by setting the
-# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
-# containing the font.
+# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
+# subgraphs. When you want a differently looking font in the dot files that
+# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
+# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
+# Edge and Graph Attributes specification</a> You need to make sure dot is able
+# to find the font, which can be done by putting it in a standard location or by
+# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font. Default graphviz fontsize is 14.
+# The default value is: fontname=Helvetica,fontsize=10.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
-DOT_FONTNAME           = FreeSans.ttf
+DOT_COMMON_ATTR        = "fontname=FreeSans.ttf,fontsize=10"
 
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
-# The default size is 10pt.
+# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
+# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
+# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
+# arrows shapes.</a>
+# The default value is: labelfontname=Helvetica,labelfontsize=10.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
-DOT_FONTSIZE           = 10
+DOT_EDGE_ATTR          = "labelfontname=FreeSans.ttf,labelfontsize=10"
 
-# By default doxygen will tell dot to use the output directory to look for the
-# FreeSans.ttf font (which doxygen will put there itself). If you specify a
-# different font using DOT_FONTNAME you can set the path where dot
-# can find it using this tag.
+# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
+# around nodes set 'shape=plain' or 'shape=plaintext' <a
+# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
+# The default value is: shape=box,height=0.2,width=0.4.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NODE_ATTR          = "shape=box,height=0.2,width=0.4"
+
+# You can set the path where dot can find font specified with fontname in
+# DOT_COMMON_ATTR and others dot attributes.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_FONTPATH           =
 
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
+# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
+# graph for each documented class showing the direct and indirect inheritance
+# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
+# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
+# to TEXT the direct and indirect inheritance relations will be shown as texts /
+# links.
+# Possible values are: NO, YES, TEXT and GRAPH.
+# The default value is: YES.
 
 CLASS_GRAPH            = YES
 
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 COLLABORATION_GRAPH    = YES
 
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies. See also the chapter Grouping
+# in the manual.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 GROUP_GRAPHS           = YES
 
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
 # collaboration diagrams in a style similar to the OMG's Unified Modeling
 # Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 UML_LOOK               = NO
 
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
+# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
+# tag is set to YES, doxygen will add type and arguments for attributes and
+# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
+# will not generate fields with class member information in the UML graphs. The
+# class diagrams will look similar to the default class diagrams but using UML
+# notation for the relationships.
+# Possible values are: NO, YES and NONE.
+# The default value is: NO.
+# This tag requires that the tag UML_LOOK is set to YES.
+
+DOT_UML_DETAILS        = NO
+
+# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
+# to display on a single line. If the actual line length exceeds this threshold
+# significantly it will wrapped across multiple lines. Some heuristics are apply
+# to avoid ugly line breaks.
+# Minimum value: 0, maximum value: 1000, default value: 17.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_WRAP_THRESHOLD     = 17
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 TEMPLATE_RELATIONS     = NO
 
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 INCLUDE_GRAPH          = YES
 
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 INCLUDED_BY_GRAPH      = YES
 
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
-# for selected functions only using the \callgraph command.
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 CALL_GRAPH             = NO
 
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
-# graphs for selected functions only using the \callergraph command.
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 CALLER_GRAPH           = NO
 
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will graphical hierarchy of all classes instead of a textual one.
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 GRAPHICAL_HIERARCHY    = YES
 
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DIRECTORY_GRAPH        = YES
 
+# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
+# of child directories generated in directory dependency graphs by dot.
+# Minimum value: 1, maximum value: 25, default value: 1.
+# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
+
+DIR_GRAPH_MAX_DEPTH    = 1
+
 # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are png, jpg, or gif
-# If left blank png will be used.
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_IMAGE_FORMAT       = png
 
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
 # found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_PATH               =
 
 # The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOTFILE_DIRS           =
 
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file or to the filename of jar file
+# to be used. If left blank, it is assumed PlantUML is not used or called during
+# a preprocessing step. Doxygen will generate a warning when it encounters a
+# \startuml command in this case and will not generate output for the diagram.
+
+PLANTUML_JAR_PATH      =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH  =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_GRAPH_MAX_NODES    = 50
 
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that the size of a graph can be further restricted by
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
 # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 MAX_DOT_GRAPH_DEPTH    = 0
 
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not
-# seem to support this out of the box. Warning: Depending on the platform used,
-# enabling this option may lead to badly anti-aliased labels on the edges of
-# a graph (i.e. they become hard to read).
-
-DOT_TRANSPARENT        = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
 # files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
-# support this, this feature is disabled by default.
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_MULTI_TARGETS      = YES
 
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
+# graphical representation for inheritance and collaboration diagrams is used.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 GENERATE_LEGEND        = YES
 
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
+# files that are used to generate the various graphs.
+#
+# Note: This setting is not only used for dot files but also for msc temporary
+# files.
+# The default value is: YES.
 
 DOT_CLEANUP            = YES
diff --git a/src/hidapi/doxygen/main_page.md b/src/hidapi/doxygen/main_page.md
new file mode 100644
index 0000000..ff11e9a
--- /dev/null
+++ b/src/hidapi/doxygen/main_page.md
@@ -0,0 +1,13 @@
+# 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.
diff --git a/src/hidapi/hidapi/hidapi.h b/src/hidapi/hidapi/hidapi.h
index 9fb8da4..744ceb0 100644
--- a/src/hidapi/hidapi/hidapi.h
+++ b/src/hidapi/hidapi/hidapi.h
@@ -5,9 +5,9 @@
  Alan Ott
  Signal 11 Software
 
- 8/22/2009
+ libusb/hidapi Team
 
- Copyright 2009, All Rights Reserved.
+ Copyright 2023, All Rights Reserved.
 
  At the discretion of the user of this library,
  this software may be licensed under the terms of the
@@ -29,36 +29,123 @@
 
 #include <wchar.h>
 
-#ifdef SDL_hidapi_h_
-#define SDL_HIDAPI_IMPLEMENTATION
-#define hid_device_info SDL_hid_device_info
-#endif
-
-#if defined(_WIN32) && !defined(NAMESPACE) && !defined(SDL_HIDAPI_IMPLEMENTATION) /* SDL: don't export hidapi syms */
+/* #480: this is to be refactored properly for v1.0 */
+#ifdef _WIN32
+   #ifndef HID_API_NO_EXPORT_DEFINE
       #define HID_API_EXPORT __declspec(dllexport)
-      #define HID_API_CALL
-#else
+   #endif
+#endif
 #ifndef HID_API_EXPORT
-      #define HID_API_EXPORT /**< API export macro */
+   #define HID_API_EXPORT /**< API export macro */
 #endif
-#ifndef HID_API_CALL
-      #define HID_API_CALL /**< API call macro */
-#endif
-#endif
+/* To be removed in v1.0 */
+#define HID_API_CALL /**< API call macro */
 
 #define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/
 
-#if defined(__cplusplus) && !defined(NAMESPACE)
+/** @brief Static/compile-time major version of the library.
+
+	@ingroup API
+*/
+#define HID_API_VERSION_MAJOR 0
+/** @brief Static/compile-time minor version of the library.
+
+	@ingroup API
+*/
+#define HID_API_VERSION_MINOR 14
+/** @brief Static/compile-time patch version of the library.
+
+	@ingroup API
+*/
+#define HID_API_VERSION_PATCH 0
+
+/* Helper macros */
+#define HID_API_AS_STR_IMPL(x) #x
+#define HID_API_AS_STR(x) HID_API_AS_STR_IMPL(x)
+#define HID_API_TO_VERSION_STR(v1, v2, v3) HID_API_AS_STR(v1.v2.v3)
+
+/** @brief Coverts a version as Major/Minor/Patch into a number:
+	<8 bit major><16 bit minor><8 bit patch>.
+
+	This macro was added in version 0.12.0.
+
+	Convenient function to be used for compile-time checks, like:
+	@code{.c}
+	#if HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
+	@endcode
+
+	@ingroup API
+*/
+#define HID_API_MAKE_VERSION(mj, mn, p) (((mj) << 24) | ((mn) << 8) | (p))
+
+/** @brief Static/compile-time version of the library.
+
+	This macro was added in version 0.12.0.
+
+	@see @ref HID_API_MAKE_VERSION.
+
+	@ingroup API
+*/
+#define HID_API_VERSION HID_API_MAKE_VERSION(HID_API_VERSION_MAJOR, HID_API_VERSION_MINOR, HID_API_VERSION_PATCH)
+
+/** @brief Static/compile-time string version of the library.
+
+	@ingroup API
+*/
+#define HID_API_VERSION_STR HID_API_TO_VERSION_STR(HID_API_VERSION_MAJOR, HID_API_VERSION_MINOR, HID_API_VERSION_PATCH)
+
+/** @brief Maximum expected HID Report descriptor size in bytes.
+
+	Since version 0.13.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 13, 0)
+
+	@ingroup API
+*/
+#define HID_API_MAX_REPORT_DESCRIPTOR_SIZE 4096
+
+#ifdef __cplusplus
 extern "C" {
 #endif
-#ifdef NAMESPACE
-namespace NAMESPACE {
-#endif
+		/** A structure to hold the version numbers. */
+		struct hid_api_version {
+			int major; /**< major version number */
+			int minor; /**< minor version number */
+			int patch; /**< patch version number */
+		};
 
 		struct hid_device_;
 		typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
 
-#ifndef SDL_HIDAPI_IMPLEMENTATION
+		/** @brief HID underlying bus types.
+
+			@ingroup API
+		*/
+		typedef enum {
+			/** Unknown bus type */
+			HID_API_BUS_UNKNOWN = 0x00,
+
+			/** USB bus
+			   Specifications:
+			   https://usb.org/hid */
+			HID_API_BUS_USB = 0x01,
+
+			/** Bluetooth or Bluetooth LE bus
+			   Specifications:
+			   https://www.bluetooth.com/specifications/specs/human-interface-device-profile-1-1-1/
+			   https://www.bluetooth.com/specifications/specs/hid-service-1-0/
+			   https://www.bluetooth.com/specifications/specs/hid-over-gatt-profile-1-0/ */
+			HID_API_BUS_BLUETOOTH = 0x02,
+
+			/** I2C bus
+			   Specifications:
+			   https://docs.microsoft.com/previous-versions/windows/hardware/design/dn642101(v=vs.85) */
+			HID_API_BUS_I2C = 0x03,
+
+			/** SPI bus
+			   Specifications:
+			   https://www.microsoft.com/download/details.aspx?id=103325 */
+			HID_API_BUS_SPI = 0x04,
+		} hid_bus_type;
+
 		/** hidapi info structure */
 		struct hid_device_info {
 			/** Platform-specific device path */
@@ -77,29 +164,27 @@
 			/** Product string */
 			wchar_t *product_string;
 			/** Usage Page for this Device/Interface
-			    (Windows/Mac only). */
+			    (Windows/Mac/hidraw only) */
 			unsigned short usage_page;
 			/** Usage for this Device/Interface
-			    (Windows/Mac only).*/
+			    (Windows/Mac/hidraw only) */
 			unsigned short usage;
 			/** The USB interface which this logical device
 			    represents.
 
-				* Valid on both Linux implementations in all cases.
-				* Valid on the Windows implementation only if the device
-				  contains more than one interface. */
+			    Valid only if the device is a USB HID device.
+			    Set to -1 in all other cases.
+			*/
 			int interface_number;
 
-			/** Additional information about the USB interface.
-			    Valid on libusb and Android implementations. */
-			int interface_class;
-			int interface_subclass;
-			int interface_protocol;
-
 			/** Pointer to the next device */
 			struct hid_device_info *next;
+
+			/** Underlying bus type
+			    Since version 0.13.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 13, 0)
+			*/
+			hid_bus_type bus_type;
 		};
-#endif /* !SDL_HIDAPI_IMPLEMENTATION */
 
 
 		/** @brief Initialize the HIDAPI library.
@@ -115,6 +200,7 @@
 
 			@returns
 				This function returns 0 on success and -1 on error.
+				Call hid_error(NULL) to get the failure reason.
 		*/
 		int HID_API_EXPORT HID_API_CALL hid_init(void);
 
@@ -126,7 +212,7 @@
 
 			@ingroup API
 
-		    @returns
+			@returns
 				This function returns 0 on success and -1 on error.
 		*/
 		int HID_API_EXPORT HID_API_CALL hid_exit(void);
@@ -146,21 +232,25 @@
 			@param product_id The Product ID (PID) of the types of
 				device to open.
 
-		    @returns
-		    	This function returns a pointer to a linked list of type
-		    	struct #hid_device_info, containing information about the HID devices
-		    	attached to the system, or NULL in the case of failure. Free
-		    	this linked list by calling hid_free_enumeration().
+			@returns
+				This function returns a pointer to a linked list of type
+				struct #hid_device_info, containing information about the HID devices
+				attached to the system,
+				or NULL in the case of failure or if no HID devices present in the system.
+				Call hid_error(NULL) to get the failure reason.
+
+			@note The returned value by this function must to be freed by calling hid_free_enumeration(),
+			      when not needed anymore.
 		*/
 		struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
 
 		/** @brief Free an enumeration Linked List
 
-		    This function frees a linked list created by hid_enumerate().
+			This function frees a linked list created by hid_enumerate().
 
 			@ingroup API
-		    @param devs Pointer to a list of struct_device returned from
-		    	      hid_enumerate().
+			@param devs Pointer to a list of struct_device returned from
+			            hid_enumerate().
 		*/
 		void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
 
@@ -174,11 +264,15 @@
 			@param vendor_id The Vendor ID (VID) of the device to open.
 			@param product_id The Product ID (PID) of the device to open.
 			@param serial_number The Serial Number of the device to open
-				               (Optionally NULL).
+			                     (Optionally NULL).
 
 			@returns
 				This function returns a pointer to a #hid_device object on
 				success or NULL on failure.
+				Call hid_error(NULL) to get the failure reason.
+
+			@note The returned object must be freed by calling hid_close(),
+			      when not needed anymore.
 		*/
 		HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);
 
@@ -189,13 +283,17 @@
 			Linux).
 
 			@ingroup API
-		    @param path The path name of the device to open
+			@param path The path name of the device to open
 
 			@returns
 				This function returns a pointer to a #hid_device object on
 				success or NULL on failure.
+				Call hid_error(NULL) to get the failure reason.
+
+			@note The returned object must be freed by calling hid_close(),
+			      when not needed anymore.
 		*/
-		HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path, int bExclusive /* = false */);
+		HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);
 
 		/** @brief Write an Output report to a HID device.
 
@@ -222,6 +320,7 @@
 			@returns
 				This function returns the actual number of bytes written and
 				-1 on error.
+				Call hid_error(dev) to get the failure reason.
 		*/
 		int  HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length);
 
@@ -241,7 +340,9 @@
 
 			@returns
 				This function returns the actual number of bytes read and
-				-1 on error. If no packet was available to be read within
+				-1 on error.
+				Call hid_error(dev) to get the failure reason.
+				If no packet was available to be read within
 				the timeout period, this function returns 0.
 		*/
 		int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
@@ -249,7 +350,7 @@
 		/** @brief Read an Input report from a HID device.
 
 			Input reports are returned
-		    to the host through the INTERRUPT IN endpoint. The first byte will
+			to the host through the INTERRUPT IN endpoint. The first byte will
 			contain the Report number if the device uses numbered reports.
 
 			@ingroup API
@@ -261,7 +362,9 @@
 
 			@returns
 				This function returns the actual number of bytes read and
-				-1 on error. If no packet was available to be read and
+				-1 on error.
+				Call hid_error(dev) to get the failure reason.
+				If no packet was available to be read and
 				the handle is in non-blocking mode, this function returns 0.
 		*/
 		int  HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length);
@@ -283,6 +386,7 @@
 
 			@returns
 				This function returns 0 on success and -1 on error.
+				Call hid_error(dev) to get the failure reason.
 		*/
 		int  HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock);
 
@@ -311,6 +415,7 @@
 			@returns
 				This function returns the actual number of bytes written and
 				-1 on error.
+				Call hid_error(dev) to get the failure reason.
 		*/
 		int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length);
 
@@ -336,9 +441,38 @@
 				This function returns the number of bytes read plus
 				one for the report ID (which is still in the first
 				byte), or -1 on error.
+				Call hid_error(dev) to get the failure reason.
 		*/
 		int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length);
 
+		/** @brief Get a input report from a HID device.
+
+			Since version 0.10.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 10, 0)
+
+			Set the first byte of @p data[] to the Report ID of the
+			report to be read. Make sure to allow space for this
+			extra byte in @p data[]. Upon return, the first byte will
+			still contain the Report ID, and the report data will
+			start in data[1].
+
+			@ingroup API
+			@param dev A device handle returned from hid_open().
+			@param data A buffer to put the read data into, including
+				the Report ID. Set the first byte of @p data[] to the
+				Report ID of the report to be read, or set it to zero
+				if your device does not use numbered reports.
+			@param length The number of bytes to read, including an
+				extra byte for the report ID. The buffer can be longer
+				than the actual report.
+
+			@returns
+				This function returns the number of bytes read plus
+				one for the report ID (which is still in the first
+				byte), or -1 on error.
+				Call hid_error(dev) to get the failure reason.
+		*/
+		int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length);
+
 		/** @brief Close a HID device.
 
 			@ingroup API
@@ -355,6 +489,7 @@
 
 			@returns
 				This function returns 0 on success and -1 on error.
+				Call hid_error(dev) to get the failure reason.
 		*/
 		int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen);
 
@@ -367,6 +502,7 @@
 
 			@returns
 				This function returns 0 on success and -1 on error.
+				Call hid_error(dev) to get the failure reason.
 		*/
 		int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen);
 
@@ -379,9 +515,27 @@
 
 			@returns
 				This function returns 0 on success and -1 on error.
+				Call hid_error(dev) to get the failure reason.
 		*/
 		int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen);
 
+		/** @brief Get The struct #hid_device_info from a HID device.
+
+			Since version 0.13.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 13, 0)
+
+			@ingroup API
+			@param dev A device handle returned from hid_open().
+
+			@returns
+				This function returns a pointer to the struct #hid_device_info
+				for this hid_device, or NULL in the case of failure.
+				Call hid_error(dev) to get the failure reason.
+				This struct is valid until the device is closed with hid_close().
+
+			@note The returned object is owned by the @p dev, and SHOULD NOT be freed by the user.
+		*/
+		struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_get_device_info(hid_device *dev);
+
 		/** @brief Get a string from a HID device, based on its string index.
 
 			@ingroup API
@@ -392,30 +546,79 @@
 
 			@returns
 				This function returns 0 on success and -1 on error.
+				Call hid_error(dev) to get the failure reason.
 		*/
 		int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen);
 
-		/** @brief Get a string describing the last error which occurred.
+		/** @brief Get a report descriptor from a HID device.
+
+			Since version 0.14.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 14, 0)
+
+			User has to provide a preallocated buffer where descriptor will be copied to.
+			The recommended size for preallocated buffer is @ref HID_API_MAX_REPORT_DESCRIPTOR_SIZE bytes.
 
 			@ingroup API
 			@param dev A device handle returned from hid_open().
+			@param buf The buffer to copy descriptor into.
+			@param buf_size The size of the buffer in bytes.
 
 			@returns
-				This function returns a string containing the last error
-				which occurred or NULL if none has occurred.
+				This function returns non-negative number of bytes actually copied, or -1 on error.
+		*/
+		int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size);
+
+		/** @brief Get a string describing the last error which occurred.
+
+			This function is intended for logging/debugging purposes.
+
+			This function guarantees to never return NULL.
+			If there was no error in the last function call -
+			the returned string clearly indicates that.
+
+			Any HIDAPI function that can explicitly indicate an execution failure
+			(e.g. by an error code, or by returning NULL) - may set the error string,
+			to be returned by this function.
+
+			Strings returned from hid_error() must not be freed by the user,
+			i.e. owned by HIDAPI library.
+			Device-specific error string may remain allocated at most until hid_close() is called.
+			Global error string may remain allocated at most until hid_exit() is called.
+
+			@ingroup API
+			@param dev A device handle returned from hid_open(),
+			  or NULL to get the last non-device-specific error
+			  (e.g. for errors in hid_open() or hid_enumerate()).
+
+			@returns
+				A string describing the last error (if any).
 		*/
 		HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *dev);
 
-#if defined(__IOS__) || defined(__TVOS__)
-		HID_API_EXPORT void HID_API_CALL hid_ble_scan(int active);
-#endif
+		/** @brief Get a runtime version of the library.
 
-#if defined(__cplusplus) && !defined(NAMESPACE)
-}
-#endif
-#ifdef NAMESPACE
+			This function is thread-safe.
+
+			@ingroup API
+
+			@returns
+				Pointer to statically allocated struct, that contains version.
+		*/
+		HID_API_EXPORT const  struct hid_api_version* HID_API_CALL hid_version(void);
+
+
+		/** @brief Get a runtime version string of the library.
+
+			This function is thread-safe.
+
+			@ingroup API
+
+			@returns
+				Pointer to statically allocated string, that contains version string.
+		*/
+		HID_API_EXPORT const char* HID_API_CALL hid_version_str(void);
+
+#ifdef __cplusplus
 }
 #endif
 
 #endif
-
diff --git a/src/hidapi/hidtest/.gitignore b/src/hidapi/hidtest/.gitignore
new file mode 100644
index 0000000..a9ce7a2
--- /dev/null
+++ b/src/hidapi/hidtest/.gitignore
@@ -0,0 +1,17 @@
+Debug
+Release
+*.exp
+*.ilk
+*.lib
+*.suo
+*.vcproj.*
+*.ncb
+*.suo
+*.dll
+*.pdb
+*.o
+.deps/
+.libs/
+hidtest-hidraw
+hidtest-libusb
+hidtest
diff --git a/src/hidapi/hidtest/CMakeLists.txt b/src/hidapi/hidtest/CMakeLists.txt
new file mode 100644
index 0000000..701a4fb
--- /dev/null
+++ b/src/hidapi/hidtest/CMakeLists.txt
@@ -0,0 +1,40 @@
+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}"
+)
diff --git a/src/hidapi/hidtest/Makefile.am b/src/hidapi/hidtest/Makefile.am
index d278644..b601307 100644
--- a/src/hidapi/hidtest/Makefile.am
+++ b/src/hidapi/hidtest/Makefile.am
@@ -4,17 +4,25 @@
 if OS_LINUX
 noinst_PROGRAMS = hidtest-libusb hidtest-hidraw
 
-hidtest_hidraw_SOURCES = hidtest.cpp
+hidtest_hidraw_SOURCES = test.c
 hidtest_hidraw_LDADD = $(top_builddir)/linux/libhidapi-hidraw.la
 
-hidtest_libusb_SOURCES = hidtest.cpp
+hidtest_libusb_SOURCES = test.c
 hidtest_libusb_LDADD = $(top_builddir)/libusb/libhidapi-libusb.la
 else
 
 # Other OS's
 noinst_PROGRAMS = hidtest
 
-hidtest_SOURCES = hidtest.cpp
+hidtest_SOURCES = test.c
 hidtest_LDADD = $(top_builddir)/$(backend)/libhidapi.la
 
 endif
+
+if OS_DARWIN
+AM_CPPFLAGS += -I$(top_srcdir)/mac/
+endif
+
+if OS_WINDOWS
+AM_CPPFLAGS += -I$(top_srcdir)/windows/
+endif
diff --git a/src/hidapi/hidtest/hidtest.cpp b/src/hidapi/hidtest/hidtest.cpp
deleted file mode 100644
index 94f0a5c..0000000
--- a/src/hidapi/hidtest/hidtest.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/*******************************************************
- Windows HID simplification
-
- Alan Ott
- Signal 11 Software
-
- 8/22/2009
-
- Copyright 2009
- 
- 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
-
-int main(int argc, char* argv[])
-{
-	int res;
-	unsigned char buf[256];
-	#define MAX_STR 255
-	wchar_t wstr[MAX_STR];
-	hid_device *handle;
-	int i;
-
-#ifdef WIN32
-	UNREFERENCED_PARAMETER(argc);
-	UNREFERENCED_PARAMETER(argv);
-#endif
-
-	struct hid_device_info *devs, *cur_dev;
-	
-	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("\n");
-		cur_dev = cur_dev->next;
-	}
-	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");
- 		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", wstr[0], wstr);
-	printf("\n");
-
-	// 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 shoud 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.\n");
-		printf("%ls", hid_error(handle));
-	}
-	else {
-		// Print out the returned buffer.
-		printf("Feature Report\n   ");
-		for (i = 0; i < res; i++)
-			printf("%02hhx ", 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()\n");
-		printf("Error: %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)\n");
-
-	// 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;
-	while (res == 0) {
-		res = hid_read(handle, buf, sizeof(buf));
-		if (res == 0)
-			printf("waiting...\n");
-		if (res < 0)
-			printf("Unable to read()\n");
-		#ifdef WIN32
-		Sleep(500);
-		#else
-		usleep(500*1000);
-		#endif
-	}
-
-	printf("Data read:\n   ");
-	// Print out the returned buffer.
-	for (i = 0; i < res; i++)
-		printf("%02hhx ", buf[i]);
-	printf("\n");
-
-	hid_close(handle);
-
-	/* Free static HIDAPI objects. */
-	hid_exit();
-
-#ifdef WIN32
-	system("pause");
-#endif
-
-	return 0;
-}
diff --git a/src/hidapi/hidtest/test.c b/src/hidapi/hidtest/test.c
new file mode 100644
index 0000000..94bbf37
--- /dev/null
+++ b/src/hidapi/hidtest/test.c
@@ -0,0 +1,316 @@
+/*******************************************************
+ 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;
+}
diff --git a/src/hidapi/ios/Makefile-manual b/src/hidapi/ios/Makefile-manual
deleted file mode 100644
index 939a077..0000000
--- a/src/hidapi/ios/Makefile-manual
+++ /dev/null
@@ -1,32 +0,0 @@
-###########################################
-# Simple Makefile for HIDAPI test program
-#
-# Alan Ott
-# Signal 11 Software
-# 2010-07-03
-###########################################
-
-all: hidtest
-
-CC=gcc
-CXX=g++
-COBJS=hid.o
-CPPOBJS=../hidtest/hidtest.o
-OBJS=$(COBJS) $(CPPOBJS)
-CFLAGS+=-I../hidapi -Wall -g -c 
-LIBS=-framework CoreBluetooth -framework CoreFoundation
-
-
-hidtest: $(OBJS)
-	g++ -Wall -g $^ $(LIBS) -o hidtest
-
-$(COBJS): %.o: %.c
-	$(CC) $(CFLAGS) $< -o $@
-
-$(CPPOBJS): %.o: %.cpp
-	$(CXX) $(CFLAGS) $< -o $@
-
-clean:
-	rm -f *.o hidtest $(CPPOBJS)
-
-.PHONY: clean
diff --git a/src/hidapi/ios/Makefile.am b/src/hidapi/ios/Makefile.am
deleted file mode 100644
index 1f8f2ce..0000000
--- a/src/hidapi/ios/Makefile.am
+++ /dev/null
@@ -1,9 +0,0 @@
-lib_LTLIBRARIES = libhidapi.la
-libhidapi_la_SOURCES = hid.m
-libhidapi_la_LDFLAGS = $(LTLDFLAGS)
-AM_CPPFLAGS = -I$(top_srcdir)/hidapi/
-
-hdrdir = $(includedir)/hidapi
-hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h
-
-EXTRA_DIST = Makefile-manual
diff --git a/src/hidapi/ios/hid.m b/src/hidapi/ios/hid.m
deleted file mode 100644
index 2748d8c..0000000
--- a/src/hidapi/ios/hid.m
+++ /dev/null
@@ -1,996 +0,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 2021 Valve Corporation
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-#include "SDL_internal.h"
-
-#ifndef SDL_HIDAPI_DISABLED
-
-
-#define hid_init                        PLATFORM_hid_init
-#define hid_exit                        PLATFORM_hid_exit
-#define hid_enumerate                   PLATFORM_hid_enumerate
-#define hid_free_enumeration            PLATFORM_hid_free_enumeration
-#define hid_open                        PLATFORM_hid_open
-#define hid_open_path                   PLATFORM_hid_open_path
-#define hid_write                       PLATFORM_hid_write
-#define hid_read_timeout                PLATFORM_hid_read_timeout
-#define hid_read                        PLATFORM_hid_read
-#define hid_set_nonblocking             PLATFORM_hid_set_nonblocking
-#define hid_send_feature_report         PLATFORM_hid_send_feature_report
-#define hid_get_feature_report          PLATFORM_hid_get_feature_report
-#define hid_close                       PLATFORM_hid_close
-#define hid_get_manufacturer_string     PLATFORM_hid_get_manufacturer_string
-#define hid_get_product_string          PLATFORM_hid_get_product_string
-#define hid_get_serial_number_string    PLATFORM_hid_get_serial_number_string
-#define hid_get_indexed_string          PLATFORM_hid_get_indexed_string
-#define hid_error                       PLATFORM_hid_error
-
-#include <CoreBluetooth/CoreBluetooth.h>
-#include <QuartzCore/QuartzCore.h>
-#import <UIKit/UIKit.h>
-#import <mach/mach_time.h>
-#include <pthread.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include "../hidapi/hidapi.h"
-
-#define VALVE_USB_VID       0x28DE
-#define D0G_BLE2_PID        0x1106
-
-typedef uint32_t uint32;
-typedef uint64_t uint64;
-
-// enables detailed NSLog logging of feature reports
-#define FEATURE_REPORT_LOGGING	0
-
-#define REPORT_SEGMENT_DATA_FLAG	0x80
-#define REPORT_SEGMENT_LAST_FLAG	0x40
-
-#define VALVE_SERVICE		@"100F6C32-1735-4313-B402-38567131E5F3"
-
-// (READ/NOTIFICATIONS)
-#define VALVE_INPUT_CHAR	@"100F6C33-1735-4313-B402-38567131E5F3"
-
-//  (READ/WRITE)
-#define VALVE_REPORT_CHAR	@"100F6C34-1735-4313-B402-38567131E5F3"
-
-// TODO: create CBUUID's in __attribute__((constructor)) rather than doing [CBUUID UUIDWithString:...] everywhere
-
-#pragma pack(push,1)
-
-typedef struct
-{
-	uint8_t		segmentHeader;
-	uint8_t		featureReportMessageID;
-	uint8_t		length;
-	uint8_t		settingIdentifier;
-	union {
-		uint16_t	usPayload;
-		uint32_t	uPayload;
-		uint64_t	ulPayload;
-		uint8_t		ucPayload[15];
-	};
-} bluetoothSegment;
-
-typedef struct {
-	uint8_t		id;
-	union {
-		bluetoothSegment segment;
-		struct {
-			uint8_t		segmentHeader;
-			uint8_t		featureReportMessageID;
-			uint8_t		length;
-			uint8_t		settingIdentifier;
-			union {
-				uint16_t	usPayload;
-				uint32_t	uPayload;
-				uint64_t	ulPayload;
-				uint8_t		ucPayload[15];
-			};
-		};
-	};
-} hidFeatureReport;
-
-#pragma pack(pop)
-
-size_t GetBluetoothSegmentSize(bluetoothSegment *segment)
-{
-    return segment->length + 3;
-}
-
-#define RingBuffer_cbElem   19
-#define RingBuffer_nElem    4096
-
-typedef struct {
-	int _first, _last;
-	uint8_t _data[ ( RingBuffer_nElem * RingBuffer_cbElem ) ];
-	pthread_mutex_t accessLock;
-} RingBuffer;
-
-static void RingBuffer_init( RingBuffer *this )
-{
-    this->_first = -1;
-    this->_last = 0;
-    pthread_mutex_init( &this->accessLock, 0 );
-}
-
-static bool RingBuffer_write( RingBuffer *this, const uint8_t *src )
-{
-    pthread_mutex_lock( &this->accessLock );
-    memcpy( &this->_data[ this->_last ], src, RingBuffer_cbElem );
-    if ( this->_first == -1 )
-    {
-        this->_first = this->_last;
-    }
-    this->_last = ( this->_last + RingBuffer_cbElem ) % (RingBuffer_nElem * RingBuffer_cbElem);
-    if ( this->_last == this->_first )
-    {
-        this->_first = ( this->_first + RingBuffer_cbElem ) % (RingBuffer_nElem * RingBuffer_cbElem);
-        pthread_mutex_unlock( &this->accessLock );
-        return false;
-    }
-    pthread_mutex_unlock( &this->accessLock );
-    return true;
-}
-
-static bool RingBuffer_read( RingBuffer *this, uint8_t *dst )
-{
-    pthread_mutex_lock( &this->accessLock );
-    if ( this->_first == -1 )
-    {
-        pthread_mutex_unlock( &this->accessLock );
-        return false;
-    }
-    memcpy( dst, &this->_data[ this->_first ], RingBuffer_cbElem );
-    this->_first = ( this->_first + RingBuffer_cbElem ) % (RingBuffer_nElem * RingBuffer_cbElem);
-    if ( this->_first == this->_last )
-    {
-        this->_first = -1;
-    }
-    pthread_mutex_unlock( &this->accessLock );
-    return true;
-}
-
-
-#pragma mark HIDBLEDevice Definition
-
-typedef enum
-{
-	BLEDeviceWaitState_None,
-	BLEDeviceWaitState_Waiting,
-	BLEDeviceWaitState_Complete,
-	BLEDeviceWaitState_Error
-} BLEDeviceWaitState;
-
-@interface HIDBLEDevice : NSObject <CBPeripheralDelegate>
-{
-	RingBuffer _inputReports;
-	uint8_t	_featureReport[20];
-	BLEDeviceWaitState	_waitStateForReadFeatureReport;
-	BLEDeviceWaitState	_waitStateForWriteFeatureReport;
-}
-
-@property (nonatomic, readwrite) bool connected;
-@property (nonatomic, readwrite) bool ready;
-
-@property (nonatomic, strong) CBPeripheral     *bleSteamController;
-@property (nonatomic, strong) CBCharacteristic *bleCharacteristicInput;
-@property (nonatomic, strong) CBCharacteristic *bleCharacteristicReport;
-
-- (id)initWithPeripheral:(CBPeripheral *)peripheral;
-
-@end
-
-
-@interface HIDBLEManager : NSObject <CBCentralManagerDelegate>
-
-@property (nonatomic) int nPendingScans;
-@property (nonatomic) int nPendingPairs;
-@property (nonatomic, strong) CBCentralManager *centralManager;
-@property (nonatomic, strong) NSMapTable<CBPeripheral *, HIDBLEDevice *> *deviceMap;
-@property (nonatomic, retain) dispatch_queue_t bleSerialQueue;
-
-+ (instancetype)sharedInstance;
-- (void)startScan:(int)duration;
-- (void)stopScan;
-- (int)updateConnectedSteamControllers:(BOOL) bForce;
-- (void)appWillResignActiveNotification:(NSNotification *)note;
-- (void)appDidBecomeActiveNotification:(NSNotification *)note;
-
-@end
-
-
-// singleton class - access using HIDBLEManager.sharedInstance
-@implementation HIDBLEManager
-
-+ (instancetype)sharedInstance
-{
-	static HIDBLEManager *sharedInstance = nil;
-	static dispatch_once_t onceToken;
-	dispatch_once(&onceToken, ^{
-		sharedInstance = [HIDBLEManager new];
-		sharedInstance.nPendingScans = 0;
-		sharedInstance.nPendingPairs = 0;
-
-        // Bluetooth is currently only used for Steam Controllers, so check that hint
-        // before initializing Bluetooth, which will prompt the user for permission.
-		if ( SDL_GetHintBoolean( SDL_HINT_JOYSTICK_HIDAPI_STEAM, SDL_FALSE ) )
-		{
-			[[NSNotificationCenter defaultCenter] addObserver:sharedInstance selector:@selector(appWillResignActiveNotification:) name: UIApplicationWillResignActiveNotification object:nil];
-			[[NSNotificationCenter defaultCenter] addObserver:sharedInstance selector:@selector(appDidBecomeActiveNotification:) name:UIApplicationDidBecomeActiveNotification object:nil];
-
-			// receive reports on a high-priority serial-queue. optionally put writes on the serial queue to avoid logical
-			// race conditions talking to the controller from multiple threads, although BLE fragmentation/assembly means
-			// that we can still screw this up.
-			// most importantly we need to consume reports at a high priority to avoid the OS thinking we aren't really
-			// listening to the BLE device, as iOS on slower devices may stop delivery of packets to the app WITHOUT ACTUALLY
-			// DISCONNECTING FROM THE DEVICE if we don't react quickly enough to their delivery.
-			// see also the error-handling states in the peripheral delegate to re-open the device if it gets closed
-			sharedInstance.bleSerialQueue = dispatch_queue_create( "com.valvesoftware.steamcontroller.ble", DISPATCH_QUEUE_SERIAL );
-			dispatch_set_target_queue( sharedInstance.bleSerialQueue, dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_HIGH, 0 ) );
-
-			// creating a CBCentralManager will always trigger a future centralManagerDidUpdateState:
-			// where any scanning gets started or connecting to existing peripherals happens, it's never already in a
-			// powered-on state for a newly launched application.
-			sharedInstance.centralManager = [[CBCentralManager alloc] initWithDelegate:sharedInstance queue:sharedInstance.bleSerialQueue];
-		}
-		sharedInstance.deviceMap = [[NSMapTable alloc] initWithKeyOptions:NSMapTableWeakMemory valueOptions:NSMapTableStrongMemory capacity:4];
-	});
-	return sharedInstance;
-}
-
-// called for NSNotification UIApplicationWillResignActiveNotification
-- (void)appWillResignActiveNotification:(NSNotification *)note
-{
-	// we'll get resign-active notification if pairing is happening.
-	if ( self.nPendingPairs > 0 )
-		return;
-
-	for ( CBPeripheral *peripheral in self.deviceMap )
-	{
-		HIDBLEDevice *steamController = [self.deviceMap objectForKey:peripheral];
-		if ( steamController )
-		{
-			steamController.connected = NO;
-			steamController.ready = NO;
-			[self.centralManager cancelPeripheralConnection:peripheral];
-		}
-	}
-	[self.deviceMap removeAllObjects];
-}
-
-// called for NSNotification UIApplicationDidBecomeActiveNotification
-//  whenever the application comes back from being inactive, trigger a 20s pairing scan and reconnect
-//  any devices that may have paired while we were inactive.
-- (void)appDidBecomeActiveNotification:(NSNotification *)note
-{
-	[self updateConnectedSteamControllers:true];
-	[self startScan:20];
-}
-
-- (int)updateConnectedSteamControllers:(BOOL) bForce
-{
-	static uint64_t s_unLastUpdateTick = 0;
-	static mach_timebase_info_data_t s_timebase_info;
-
-	if ( self.centralManager == nil )
-    {
-		return 0;
-    }
-
-	if (s_timebase_info.denom == 0)
-	{
-		mach_timebase_info( &s_timebase_info );
-	}
-
-	uint64_t ticksNow = mach_approximate_time();
-	if ( !bForce && ( ( (ticksNow - s_unLastUpdateTick) * s_timebase_info.numer ) / s_timebase_info.denom ) < (5ull * NSEC_PER_SEC) )
-		return (int)self.deviceMap.count;
-
-	// we can see previously connected BLE peripherals but can't connect until the CBCentralManager
-	// is fully powered up - only do work when we are in that state
-	if ( self.centralManager.state != CBManagerStatePoweredOn )
-		return (int)self.deviceMap.count;
-
-	// only update our last-check-time if we actually did work, otherwise there can be a long delay during initial power-up
-	s_unLastUpdateTick = mach_approximate_time();
-
-	// if a pair is in-flight, the central manager may still give it back via retrieveConnected... and
-	// cause the SDL layer to attempt to initialize it while some of its endpoints haven't yet been established
-	if ( self.nPendingPairs > 0 )
-		return (int)self.deviceMap.count;
-
-	NSArray<CBPeripheral *> *peripherals = [self.centralManager retrieveConnectedPeripheralsWithServices: @[ [CBUUID UUIDWithString:@"180A"]]];
-	for ( CBPeripheral *peripheral in peripherals )
-	{
-		// we already know this peripheral
-		if ( [self.deviceMap objectForKey: peripheral] != nil )
-			continue;
-
-		NSLog( @"connected peripheral: %@", peripheral );
-		if ( [peripheral.name isEqualToString:@"SteamController"] )
-		{
-			self.nPendingPairs += 1;
-			HIDBLEDevice *steamController = [[HIDBLEDevice alloc] initWithPeripheral:peripheral];
-			[self.deviceMap setObject:steamController forKey:peripheral];
-			[self.centralManager connectPeripheral:peripheral options:nil];
-		}
-	}
-
-	return (int)self.deviceMap.count;
-}
-
-// manual API for folks to start & stop scanning
-- (void)startScan:(int)duration
-{
-	if ( self.centralManager == nil )
-	{
-		return;
-	}
-
-	NSLog( @"BLE: requesting scan for %d seconds", duration );
-	@synchronized (self)
-	{
-		if ( _nPendingScans++ == 0 )
-		{
-			[self.centralManager scanForPeripheralsWithServices:nil options:nil];
-		}
-	}
-
-	if ( duration != 0 )
-	{
-		dispatch_after( dispatch_time( DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
-			[self stopScan];
-		});
-	}
-}
-
-- (void)stopScan
-{
-	if ( self.centralManager == nil )
-	{
-		return;
-	}
-
-	NSLog( @"BLE: stopping scan" );
-	@synchronized (self)
-	{
-		if ( --_nPendingScans <= 0 )
-		{
-			_nPendingScans = 0;
-			[self.centralManager stopScan];
-		}
-	}
-}
-
-
-#pragma mark CBCentralManagerDelegate Implementation
-
-// called whenever the BLE hardware state changes.
-- (void)centralManagerDidUpdateState:(CBCentralManager *)central
-{
-	switch ( central.state )
-	{
-		case CBCentralManagerStatePoweredOn:
-		{
-			NSLog( @"CoreBluetooth BLE hardware is powered on and ready" );
-
-			// at startup, if we have no already attached peripherals, do a 20s scan for new unpaired devices,
-			// otherwise callers should occaisionally do additional scans. we don't want to continuously be
-			// scanning because it drains battery, causes other nearby people to have a hard time pairing their
-			// Steam Controllers, and may also trigger firmware weirdness when a device attempts to start
-			// the pairing sequence multiple times concurrently
-			if ( [self updateConnectedSteamControllers:false] == 0 )
-			{
-				// TODO: we could limit our scan to only peripherals supporting the SteamController service, but
-				//  that service doesn't currently fit in the base advertising packet, we'd need to put it into an
-				//  extended scan packet. Useful optimization downstream, but not currently necessary
-				//	NSArray *services = @[[CBUUID UUIDWithString:VALVE_SERVICE]];
-				[self startScan:20];
-			}
-			break;
-		}
-
-		case CBCentralManagerStatePoweredOff:
-			NSLog( @"CoreBluetooth BLE hardware is powered off" );
-			break;
-
-		case CBCentralManagerStateUnauthorized:
-			NSLog( @"CoreBluetooth BLE state is unauthorized" );
-			break;
-
-		case CBCentralManagerStateUnknown:
-			NSLog( @"CoreBluetooth BLE state is unknown" );
-			break;
-
-		case CBCentralManagerStateUnsupported:
-			NSLog( @"CoreBluetooth BLE hardware is unsupported on this platform" );
-			break;
-
-		case CBCentralManagerStateResetting:
-			NSLog( @"CoreBluetooth BLE manager is resetting" );
-			break;
-	}
-}
-
-- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
-{
-	HIDBLEDevice *steamController = [_deviceMap objectForKey:peripheral];
-	steamController.connected = YES;
-	self.nPendingPairs -= 1;
-}
-
-- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
-{
-	NSLog( @"Failed to connect: %@", error );
-	[_deviceMap removeObjectForKey:peripheral];
-	self.nPendingPairs -= 1;
-}
-
-- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
-{
-	NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
-	NSString *log = [NSString stringWithFormat:@"Found '%@'", localName];
-
-	if ( [localName isEqualToString:@"SteamController"] )
-	{
-		NSLog( @"%@ : %@ - %@", log, peripheral, advertisementData );
-		self.nPendingPairs += 1;
-		HIDBLEDevice *steamController = [[HIDBLEDevice alloc] initWithPeripheral:peripheral];
-		[self.deviceMap setObject:steamController forKey:peripheral];
-		[self.centralManager connectPeripheral:peripheral options:nil];
-	}
-}
-
-- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
-{
-	HIDBLEDevice *steamController = [self.deviceMap objectForKey:peripheral];
-	if ( steamController )
-	{
-		steamController.connected = NO;
-		steamController.ready = NO;
-		[self.deviceMap removeObjectForKey:peripheral];
-	}
-}
-
-@end
-
-
-// Core Bluetooth devices calling back on event boundaries of their run-loops. so annoying.
-static void process_pending_events()
-{
-	CFRunLoopRunResult res;
-	do
-	{
-		res = CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0.001, FALSE );
-	}
-	while( res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut );
-}
-
-@implementation HIDBLEDevice
-
-- (id)init
-{
-	if ( self = [super init] )
-	{
-        RingBuffer_init( &_inputReports );
-		self.bleSteamController = nil;
-		self.bleCharacteristicInput = nil;
-		self.bleCharacteristicReport = nil;
-		_connected = NO;
-		_ready = NO;
-	}
-	return self;
-}
-
-- (id)initWithPeripheral:(CBPeripheral *)peripheral
-{
-	if ( self = [super init] )
-	{
-        RingBuffer_init( &_inputReports );
-		_connected = NO;
-		_ready = NO;
-		self.bleSteamController = peripheral;
-		if ( peripheral )
-		{
-			peripheral.delegate = self;
-		}
-		self.bleCharacteristicInput = nil;
-		self.bleCharacteristicReport = nil;
-	}
-	return self;
-}
-
-- (void)setConnected:(bool)connected
-{
-	_connected = connected;
-	if ( _connected )
-	{
-		[_bleSteamController discoverServices:nil];
-	}
-	else
-	{
-		NSLog( @"Disconnected" );
-	}
-}
-
-- (size_t)read_input_report:(uint8_t *)dst
-{
-	if ( RingBuffer_read( &_inputReports, dst+1 ) )
-	{
-		*dst = 0x03;
-		return 20;
-	}
-	return 0;
-}
-
-- (int)send_report:(const uint8_t *)data length:(size_t)length
-{
-	[_bleSteamController writeValue:[NSData dataWithBytes:data length:length] forCharacteristic:_bleCharacteristicReport type:CBCharacteristicWriteWithResponse];
-	return (int)length;
-}
-
-- (int)send_feature_report:(hidFeatureReport *)report
-{
-#if FEATURE_REPORT_LOGGING
-	uint8_t *reportBytes = (uint8_t *)report;
-
-	NSLog( @"HIDBLE:send_feature_report (%02zu/19) [%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x]", GetBluetoothSegmentSize( report->segment ),
-		  reportBytes[1], reportBytes[2], reportBytes[3], reportBytes[4], reportBytes[5], reportBytes[6],
-		  reportBytes[7], reportBytes[8], reportBytes[9], reportBytes[10], reportBytes[11], reportBytes[12],
-		  reportBytes[13], reportBytes[14], reportBytes[15], reportBytes[16], reportBytes[17], reportBytes[18],
-		  reportBytes[19] );
-#endif
-
-	int sendSize = (int)GetBluetoothSegmentSize( &report->segment );
-	if ( sendSize > 20 )
-		sendSize = 20;
-
-#if 1
-	// fire-and-forget - we are going to not wait for the response here because all Steam Controller BLE send_feature_report's are ignored,
-	//  except errors.
-	[_bleSteamController writeValue:[NSData dataWithBytes:&report->segment length:sendSize] forCharacteristic:_bleCharacteristicReport type:CBCharacteristicWriteWithResponse];
-
-	// pretend we received a result anybody cares about
-	return 19;
-
-#else
-	// this is technically the correct send_feature_report logic if you want to make sure it gets through and is
-	// acknowledged or errors out
-	_waitStateForWriteFeatureReport = BLEDeviceWaitState_Waiting;
-	[_bleSteamController writeValue:[NSData dataWithBytes:&report->segment length:sendSize
-									 ] forCharacteristic:_bleCharacteristicReport type:CBCharacteristicWriteWithResponse];
-
-	while ( _waitStateForWriteFeatureReport == BLEDeviceWaitState_Waiting )
-	{
-		process_pending_events();
-	}
-
-	if ( _waitStateForWriteFeatureReport == BLEDeviceWaitState_Error )
-	{
-		_waitStateForWriteFeatureReport = BLEDeviceWaitState_None;
-		return -1;
-	}
-
-	_waitStateForWriteFeatureReport = BLEDeviceWaitState_None;
-	return 19;
-#endif
-}
-
-- (int)get_feature_report:(uint8_t)feature into:(uint8_t *)buffer
-{
-	_waitStateForReadFeatureReport = BLEDeviceWaitState_Waiting;
-	[_bleSteamController readValueForCharacteristic:_bleCharacteristicReport];
-
-	while ( _waitStateForReadFeatureReport == BLEDeviceWaitState_Waiting )
-		process_pending_events();
-
-	if ( _waitStateForReadFeatureReport == BLEDeviceWaitState_Error )
-	{
-		_waitStateForReadFeatureReport = BLEDeviceWaitState_None;
-		return -1;
-	}
-
-	memcpy( buffer, _featureReport, sizeof(_featureReport) );
-
-	_waitStateForReadFeatureReport = BLEDeviceWaitState_None;
-
-#if FEATURE_REPORT_LOGGING
-	NSLog( @"HIDBLE:get_feature_report (19) [%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x]",
-		  buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6],
-		  buffer[7], buffer[8], buffer[9], buffer[10], buffer[11], buffer[12],
-		  buffer[13], buffer[14], buffer[15], buffer[16], buffer[17], buffer[18],
-		  buffer[19] );
-#endif
-
-	return 19;
-}
-
-#pragma mark CBPeripheralDelegate Implementation
-
-- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
-{
-	for (CBService *service in peripheral.services)
-	{
-		NSLog( @"Found Service: %@", service );
-		if ( [service.UUID isEqual:[CBUUID UUIDWithString:VALVE_SERVICE]] )
-		{
-			[peripheral discoverCharacteristics:nil forService:service];
-		}
-	}
-}
-
-- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
-{
-	// nothing yet needed here, enable for logging
-	if ( /* DISABLES CODE */ (0) )
-	{
-		for ( CBDescriptor *descriptor in characteristic.descriptors )
-		{
-			NSLog( @" - Descriptor '%@'", descriptor );
-		}
-	}
-}
-
-- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
-{
-	if ([service.UUID isEqual:[CBUUID UUIDWithString:VALVE_SERVICE]])
-	{
-		for (CBCharacteristic *aChar in service.characteristics)
-		{
-			NSLog( @"Found Characteristic %@", aChar );
-
-			if ( [aChar.UUID isEqual:[CBUUID UUIDWithString:VALVE_INPUT_CHAR]] )
-			{
-				self.bleCharacteristicInput = aChar;
-			}
-			else if ( [aChar.UUID isEqual:[CBUUID UUIDWithString:VALVE_REPORT_CHAR]] )
-			{
-				self.bleCharacteristicReport = aChar;
-				[self.bleSteamController discoverDescriptorsForCharacteristic: aChar];
-			}
-		}
-	}
-}
-
-- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
-{
-	static uint64_t s_ticksLastOverflowReport = 0;
-
-	// receiving an input report is the final indicator that the user accepted a pairing
-	// request and that we successfully established notification. CoreBluetooth has no
-	// notification of the pairing acknowledgement, which is a bad oversight.
-	if ( self.ready == NO )
-	{
-		self.ready = YES;
-		HIDBLEManager.sharedInstance.nPendingPairs -= 1;
-	}
-
-	if ( [characteristic.UUID isEqual:_bleCharacteristicInput.UUID] )
-	{
-		NSData *data = [characteristic value];
-		if ( data.length != 19 )
-		{
-			NSLog( @"HIDBLE: incoming data is %lu bytes should be exactly 19", (unsigned long)data.length );
-		}
-		if ( !RingBuffer_write( &_inputReports, (const uint8_t *)data.bytes ) )
-		{
-			uint64_t ticksNow = mach_approximate_time();
-			if ( ticksNow - s_ticksLastOverflowReport > (5ull * NSEC_PER_SEC / 10) )
-			{
-				NSLog( @"HIDBLE: input report buffer overflow" );
-				s_ticksLastOverflowReport = ticksNow;
-			}
-		}
-	}
-	else if ( [characteristic.UUID isEqual:_bleCharacteristicReport.UUID] )
-	{
-		memset( _featureReport, 0, sizeof(_featureReport) );
-
-		if ( error != nil )
-		{
-			NSLog( @"HIDBLE: get_feature_report error: %@", error );
-			_waitStateForReadFeatureReport = BLEDeviceWaitState_Error;
-		}
-		else
-		{
-			NSData *data = [characteristic value];
-			if ( data.length != 20 )
-			{
-				NSLog( @"HIDBLE: incoming data is %lu bytes should be exactly 20", (unsigned long)data.length );
-			}
-			memcpy( _featureReport, data.bytes, MIN( data.length, sizeof(_featureReport) ) );
-			_waitStateForReadFeatureReport = BLEDeviceWaitState_Complete;
-		}
-	}
-}
-
-- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
-{
-	if ( [characteristic.UUID isEqual:[CBUUID UUIDWithString:VALVE_REPORT_CHAR]] )
-	{
-		if ( error != nil )
-		{
-			NSLog( @"HIDBLE: write_feature_report error: %@", error );
-			_waitStateForWriteFeatureReport = BLEDeviceWaitState_Error;
-		}
-		else
-		{
-			_waitStateForWriteFeatureReport = BLEDeviceWaitState_Complete;
-		}
-	}
-}
-
-- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
-{
-	NSLog( @"didUpdateNotifcationStateForCharacteristic %@ (%@)", characteristic, error );
-}
-
-@end
-
-
-#pragma mark hid_api implementation
-
-struct hid_device_ {
-	void *device_handle;
-	int blocking;
-	hid_device *next;
-};
-
-int HID_API_EXPORT HID_API_CALL hid_init(void)
-{
-	return ( HIDBLEManager.sharedInstance == nil ) ? -1 : 0;
-}
-
-int HID_API_EXPORT HID_API_CALL hid_exit(void)
-{
-	return 0;
-}
-
-void HID_API_EXPORT HID_API_CALL hid_ble_scan( int bStart )
-{
-	HIDBLEManager *bleManager = HIDBLEManager.sharedInstance;
-	if ( bStart )
-	{
-		[bleManager startScan:0];
-	}
-	else
-	{
-		[bleManager stopScan];
-	}
-}
-
-HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
-{
-	return NULL;
-}
-
-HID_API_EXPORT hid_device * HID_API_CALL hid_open_path( const char *path, int bExclusive /* = false */ )
-{
-	hid_device *result = NULL;
-	NSString *nssPath = [NSString stringWithUTF8String:path];
-	HIDBLEManager *bleManager = HIDBLEManager.sharedInstance;
-	NSEnumerator<HIDBLEDevice *> *devices = [bleManager.deviceMap objectEnumerator];
-
-	for ( HIDBLEDevice *device in devices )
-	{
-		// we have the device but it hasn't found its service or characteristics until it is connected
-		if ( !device.ready || !device.connected || !device.bleCharacteristicInput )
-			continue;
-
-		if ( [device.bleSteamController.identifier.UUIDString isEqualToString:nssPath] )
-		{
-			result = (hid_device *)malloc( sizeof( hid_device ) );
-			memset( result, 0, sizeof( hid_device ) );
-			result->device_handle = (void*)CFBridgingRetain( device );
-			result->blocking = NO;
-			// enable reporting input events on the characteristic
-			[device.bleSteamController setNotifyValue:YES forCharacteristic:device.bleCharacteristicInput];
-			return result;
-		}
-	}
-	return result;
-}
-
-void  HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
-{
-	/* This function is identical to the Linux version. Platform independent. */
-	struct hid_device_info *d = devs;
-	while (d) {
-		struct hid_device_info *next = d->next;
-		free(d->path);
-		free(d->serial_number);
-		free(d->manufacturer_string);
-		free(d->product_string);
-		free(d);
-		d = next;
-	}
-}
-
-int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
-{
-	/* All Nonblocking operation is handled by the library. */
-	dev->blocking = !nonblock;
-
-	return 0;
-}
-
-struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
-{ @autoreleasepool {
-	struct hid_device_info *root = NULL;
-	const char *hint = SDL_GetHint(SDL_HINT_HIDAPI_IGNORE_DEVICES);
-
-	/* See if there are any devices we should skip in enumeration */
-	if (hint) {
-		char vendor_match[16], product_match[16];
-		SDL_snprintf(vendor_match, sizeof(vendor_match), "0x%.4x/0x0000", VALVE_USB_VID);
-		SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", VALVE_USB_VID, D0G_BLE2_PID);
-		if (SDL_strcasestr(hint, vendor_match) || SDL_strcasestr(hint, product_match)) {
-			return NULL;
-		}
-	}
-
-	if ( ( vendor_id == 0 && product_id == 0 ) ||
-		 ( vendor_id == VALVE_USB_VID && product_id == D0G_BLE2_PID ) )
-	{
-		HIDBLEManager *bleManager = HIDBLEManager.sharedInstance;
-		[bleManager updateConnectedSteamControllers:false];
-		NSEnumerator<HIDBLEDevice *> *devices = [bleManager.deviceMap objectEnumerator];
-		for ( HIDBLEDevice *device in devices )
-		{
-			// there are several brief windows in connecting to an already paired device and
-			// one long window waiting for users to confirm pairing where we don't want
-			// to consider a device ready - if we hand it back to SDL or another
-			// Steam Controller consumer, their additional SC setup work will fail
-			// in unusual/silent ways and we can actually corrupt the BLE stack for
-			// the entire system and kill the appletv remote's Menu button (!)
-			if ( device.bleSteamController.state != CBPeripheralStateConnected ||
-				 device.connected == NO || device.ready == NO )
-			{
-				if ( device.ready == NO && device.bleCharacteristicInput != nil )
-				{
-					// attempt to register for input reports. this call will silently fail
-					// until the pairing finalizes with user acceptance. oh, apple.
-					[device.bleSteamController setNotifyValue:YES forCharacteristic:device.bleCharacteristicInput];
-				}
-				continue;
-			}
-			struct hid_device_info *device_info = (struct hid_device_info *)malloc( sizeof(struct hid_device_info) );
-			memset( device_info, 0, sizeof(struct hid_device_info) );
-			device_info->next = root;
-			root = device_info;
-			device_info->path = strdup( device.bleSteamController.identifier.UUIDString.UTF8String );
-			device_info->vendor_id = VALVE_USB_VID;
-			device_info->product_id = D0G_BLE2_PID;
-			device_info->product_string = wcsdup( L"Steam Controller" );
-			device_info->manufacturer_string = wcsdup( L"Valve Corporation" );
-		}
-	}
-	return root;
-}}
-
-int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
-{
-	static wchar_t s_wszManufacturer[] = L"Valve Corporation";
-	wcsncpy( string, s_wszManufacturer, sizeof(s_wszManufacturer)/sizeof(s_wszManufacturer[0]) );
-	return 0;
-}
-
-int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
-{
-	static wchar_t s_wszProduct[] = L"Steam Controller";
-	wcsncpy( string, s_wszProduct, sizeof(s_wszProduct)/sizeof(s_wszProduct[0]) );
-	return 0;
-}
-
-int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
-{
-	static wchar_t s_wszSerial[] = L"12345";
-	wcsncpy( string, s_wszSerial, sizeof(s_wszSerial)/sizeof(s_wszSerial[0]) );
-	return 0;
-}
-
-int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
-{
-	return -1;
-}
-
-int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
-{
-    HIDBLEDevice *device_handle = (__bridge HIDBLEDevice *)dev->device_handle;
-
-	if ( !device_handle.connected )
-		return -1;
-
-	return [device_handle send_report:data length:length];
-}
-
-void HID_API_EXPORT hid_close(hid_device *dev)
-{
-    HIDBLEDevice *device_handle = CFBridgingRelease( dev->device_handle );
-
-	// disable reporting input events on the characteristic
-	if ( device_handle.connected ) {
-		[device_handle.bleSteamController setNotifyValue:NO forCharacteristic:device_handle.bleCharacteristicInput];
-	}
-
-	free( dev );
-}
-
-int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
-{
-    HIDBLEDevice *device_handle = (__bridge HIDBLEDevice *)dev->device_handle;
-
-	if ( !device_handle.connected )
-		return -1;
-
-	return [device_handle send_feature_report:(hidFeatureReport *)(void *)data];
-}
-
-int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
-{
-    HIDBLEDevice *device_handle = (__bridge HIDBLEDevice *)dev->device_handle;
-
-	if ( !device_handle.connected )
-		return -1;
-
-	size_t written = [device_handle get_feature_report:data[0] into:data];
-
-	return written == length-1 ? (int)length : (int)written;
-}
-
-int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
-{
-    HIDBLEDevice *device_handle = (__bridge HIDBLEDevice *)dev->device_handle;
-
-	if ( !device_handle.connected )
-		return -1;
-
-	return hid_read_timeout(dev, data, length, 0);
-}
-
-int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
-{
-    HIDBLEDevice *device_handle = (__bridge HIDBLEDevice *)dev->device_handle;
-
-	if ( !device_handle.connected )
-		return -1;
-
-	if ( milliseconds != 0 )
-	{
-		NSLog( @"hid_read_timeout with non-zero wait" );
-	}
-	int result = (int)[device_handle read_input_report:data];
-#if FEATURE_REPORT_LOGGING
-	NSLog( @"HIDBLE:hid_read_timeout (%d) [%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x]", result,
-		  data[1], data[2], data[3], data[4], data[5], data[6],
-		  data[7], data[8], data[9], data[10], data[11], data[12],
-		  data[13], data[14], data[15], data[16], data[17], data[18],
-		  data[19] );
-#endif
-	return result;
-}
-
-HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *dev)
-{
-	return NULL;
-}
-
-#endif /* !SDL_HIDAPI_DISABLED */
diff --git a/src/hidapi/libusb/.gitignore b/src/hidapi/libusb/.gitignore
new file mode 100644
index 0000000..67460db
--- /dev/null
+++ b/src/hidapi/libusb/.gitignore
@@ -0,0 +1,8 @@
+*.o
+*.so
+*.la
+*.lo
+*.a
+.libs
+.deps
+hidtest-libusb
diff --git a/src/hidapi/libusb/CMakeLists.txt b/src/hidapi/libusb/CMakeLists.txt
new file mode 100644
index 0000000..6cd48c4
--- /dev/null
+++ b/src/hidapi/libusb/CMakeLists.txt
@@ -0,0 +1,107 @@
+cmake_minimum_required(VERSION 3.6.3 FATAL_ERROR)
+
+list(APPEND HIDAPI_PUBLIC_HEADERS "hidapi_libusb.h")
+
+add_library(hidapi_libusb
+    ${HIDAPI_PUBLIC_HEADERS}
+    hid.c
+)
+target_link_libraries(hidapi_libusb PUBLIC hidapi_include)
+
+if(TARGET usb-1.0)
+    target_link_libraries(hidapi_libusb PRIVATE usb-1.0)
+else()
+    include(FindPkgConfig)
+    pkg_check_modules(libusb REQUIRED IMPORTED_TARGET libusb-1.0>=1.0.9)
+    target_link_libraries(hidapi_libusb PRIVATE PkgConfig::libusb)
+endif()
+
+find_package(Threads REQUIRED)
+target_link_libraries(hidapi_libusb PRIVATE Threads::Threads)
+
+if(HIDAPI_NO_ICONV)
+    target_compile_definitions(hidapi_libusb PRIVATE NO_ICONV)
+else()
+    if(NOT ANDROID)
+        include(CheckCSourceCompiles)
+
+        if(NOT CMAKE_VERSION VERSION_LESS 3.11)
+            message(STATUS "Check for Iconv")
+            find_package(Iconv)
+            if(Iconv_FOUND)
+                if(NOT Iconv_IS_BUILT_IN)
+                    target_link_libraries(hidapi_libusb PRIVATE Iconv::Iconv)
+                    set(CMAKE_REQUIRED_LIBRARIES "Iconv::Iconv")
+                    if(NOT BUILD_SHARED_LIBS)
+                        set(HIDAPI_NEED_EXPORT_ICONV TRUE PARENT_SCOPE)
+                    endif()
+                endif()
+            else()
+                message(STATUS "Iconv Explicitly check '-liconv'")
+                # Sometime the build environment is not setup
+                # in a way CMake can find Iconv on its own by default.
+                # But if we simply link against iconv (-liconv), the build may succeed
+                # due to other compiler/link flags.
+                set(CMAKE_REQUIRED_LIBRARIES "iconv")
+                check_c_source_compiles("
+                    #include <stddef.h>
+                    #include <iconv.h>
+                    int main() {
+                        char *a, *b;
+                        size_t i, j;
+                        iconv_t ic;
+                        ic = iconv_open(\"to\", \"from\");
+                        iconv(ic, &a, &i, &b, &j);
+                        iconv_close(ic);
+                    }
+                    "
+                    Iconv_EXPLICITLY_AT_ENV)
+                if(Iconv_EXPLICITLY_AT_ENV)
+                    message(STATUS "Iconv Explicitly check '-liconv' - Available")
+                    target_link_libraries(hidapi_libusb PRIVATE iconv)
+                else()
+                    message(FATAL_ERROR "Iconv is not found, make sure to provide it in the build environment")
+                endif()
+            endif()
+        else()
+            # otherwise there is 2 options:
+            # 1) iconv is provided by Standard C library and the build will be just fine
+            # 2) The _user_ has to provide additiona compilation options for this project/target
+        endif()
+
+        # check for error: "conflicting types for 'iconv'"
+        check_c_source_compiles("#include<iconv.h>
+            extern size_t iconv (iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
+            int main() {}"
+        HIDAPI_ICONV_CONST)
+        if(HIDAPI_ICONV_CONST)
+            target_compile_definitions(hidapi_libusb PRIVATE "ICONV_CONST=const")
+        endif()
+    else()
+        # On Android Iconv is disabled on the code level anyway, so no issue;
+    endif()
+endif()
+
+set_target_properties(hidapi_libusb
+    PROPERTIES
+        EXPORT_NAME "libusb"
+        OUTPUT_NAME "hidapi-libusb"
+        VERSION ${PROJECT_VERSION}
+        SOVERSION ${PROJECT_VERSION_MAJOR}
+        PUBLIC_HEADER "${HIDAPI_PUBLIC_HEADERS}"
+)
+
+# compatibility with find_package()
+add_library(hidapi::libusb ALIAS hidapi_libusb)
+# compatibility with raw library link
+add_library(hidapi-libusb ALIAS hidapi_libusb)
+
+if(HIDAPI_INSTALL_TARGETS)
+    install(TARGETS hidapi_libusb EXPORT hidapi
+        LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+        ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+        PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/hidapi"
+    )
+endif()
+
+hidapi_configure_pc("${PROJECT_ROOT}/pc/hidapi-libusb.pc.in")
diff --git a/src/hidapi/libusb/Makefile-manual b/src/hidapi/libusb/Makefile-manual
index c0fe868..0acf707 100644
--- a/src/hidapi/libusb/Makefile-manual
+++ b/src/hidapi/libusb/Makefile-manual
@@ -10,6 +10,10 @@
 	FILE=Makefile.freebsd
 endif
 
+ifeq ($(OS), Haiku)
+	FILE=Makefile.haiku
+endif
+
 ifeq ($(FILE), )
 all:
 	$(error Your platform ${OS} is not supported by hidapi/libusb at this time.)
diff --git a/src/hidapi/libusb/Makefile.am b/src/hidapi/libusb/Makefile.am
index 13c9d35..6964ebb 100644
--- a/src/hidapi/libusb/Makefile.am
+++ b/src/hidapi/libusb/Makefile.am
@@ -21,7 +21,14 @@
 libhidapi_la_LIBADD = $(LIBS_LIBUSB)
 endif
 
+if OS_HAIKU
+lib_LTLIBRARIES = libhidapi.la
+libhidapi_la_SOURCES = hid.c
+libhidapi_la_LDFLAGS = $(LTLDFLAGS)
+libhidapi_la_LIBADD = $(LIBS_LIBUSB)
+endif
+
 hdrdir = $(includedir)/hidapi
-hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h
+hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h hidapi_libusb.h
 
 EXTRA_DIST = Makefile-manual
diff --git a/src/hidapi/libusb/Makefile.freebsd b/src/hidapi/libusb/Makefile.freebsd
index 5e69e77..c52b355 100644
--- a/src/hidapi/libusb/Makefile.freebsd
+++ b/src/hidapi/libusb/Makefile.freebsd
@@ -13,20 +13,16 @@
 CC       ?= cc
 CFLAGS   ?= -Wall -g -fPIC
 
-CXX      ?= c++
-CXXFLAGS ?= -Wall -g
-
-COBJS     = hid.o
-CPPOBJS   = ../hidtest/hidtest.o
-OBJS      = $(COBJS) $(CPPOBJS)
-INCLUDES  = -I../hidapi -I/usr/local/include
+COBJS     = hid.o ../hidtest/test.o
+OBJS      = $(COBJS)
+INCLUDES  = -I../hidapi -I. -I/usr/local/include
 LDFLAGS   = -L/usr/local/lib
 LIBS      = -lusb -liconv -pthread
 
 
 # Console Test Program
 hidtest: $(OBJS)
-	$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
+	$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
 
 # Shared Libs
 libhidapi.so: $(COBJS)
@@ -36,9 +32,6 @@
 $(COBJS): %.o: %.c
 	$(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@
 
-$(CPPOBJS): %.o: %.cpp
-	$(CXX) $(CXXFLAGS) -c $(INCLUDES) $< -o $@
-
 
 clean:
 	rm -f $(OBJS) hidtest libhidapi.so ../hidtest/hidtest.o
diff --git a/src/hidapi/libusb/Makefile.haiku b/src/hidapi/libusb/Makefile.haiku
new file mode 100644
index 0000000..b3622ad
--- /dev/null
+++ b/src/hidapi/libusb/Makefile.haiku
@@ -0,0 +1,39 @@
+###########################################
+# Simple Makefile for HIDAPI test program
+#
+# Alan Ott
+# Signal 11 Software
+# 2010-06-01
+###########################################
+
+all: hidtest libs
+
+libs: libhidapi.so
+
+CC       ?= cc
+CFLAGS   ?= -Wall -g -fPIC
+
+COBJS     = hid.o ../hidtest/test.o
+OBJS      = $(COBJS)
+INCLUDES  = -I../hidapi -I. -I/usr/local/include
+LDFLAGS   = -L/usr/local/lib
+LIBS      = -lusb -liconv -pthread
+
+
+# Console Test Program
+hidtest: $(OBJS)
+    $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
+
+# Shared Libs
+libhidapi.so: $(COBJS)
+    $(CC) $(LDFLAGS) -shared -Wl,-soname,$@.0 $^ -o $@ $(LIBS)
+
+# Objects
+$(COBJS): %.o: %.c
+    $(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@
+
+
+clean:
+    rm -f $(OBJS) hidtest libhidapi.so ../hidtest/hidtest.o
+
+.PHONY: clean libs
diff --git a/src/hidapi/libusb/Makefile.linux b/src/hidapi/libusb/Makefile.linux
index 337b556..527f6b3 100644
--- a/src/hidapi/libusb/Makefile.linux
+++ b/src/hidapi/libusb/Makefile.linux
@@ -13,23 +13,19 @@
 CC       ?= gcc
 CFLAGS   ?= -Wall -g -fpic
 
-CXX      ?= g++
-CXXFLAGS ?= -Wall -g -fpic
-
 LDFLAGS  ?= -Wall -g
 
 COBJS_LIBUSB = hid.o
-COBJS = $(COBJS_LIBUSB)
-CPPOBJS   = ../hidtest/hidtest.o
-OBJS      = $(COBJS) $(CPPOBJS)
+COBJS = $(COBJS_LIBUSB) ../hidtest/test.o
+OBJS      = $(COBJS)
 LIBS_USB  = `pkg-config libusb-1.0 --libs` -lrt -lpthread
 LIBS      = $(LIBS_USB)
-INCLUDES ?= -I../hidapi `pkg-config libusb-1.0 --cflags`
+INCLUDES ?= -I../hidapi -I. `pkg-config libusb-1.0 --cflags`
 
 
 # Console Test Program
-hidtest-libusb: $(COBJS_LIBUSB) $(CPPOBJS)
-	$(CXX) $(LDFLAGS) $^ $(LIBS_USB) -o $@
+hidtest-libusb: $(COBJS)
+	$(CC) $(LDFLAGS) $^ $(LIBS_USB) -o $@
 
 # Shared Libs
 libhidapi-libusb.so: $(COBJS_LIBUSB)
@@ -39,9 +35,6 @@
 $(COBJS): %.o: %.c
 	$(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@
 
-$(CPPOBJS): %.o: %.cpp
-	$(CXX) $(CXXFLAGS) -c $(INCLUDES) $< -o $@
-
 
 clean:
 	rm -f $(OBJS) hidtest-libusb libhidapi-libusb.so ../hidtest/hidtest.o
diff --git a/src/hidapi/libusb/hid.c b/src/hidapi/libusb/hid.c
index f9a8b33..188e536 100644
--- a/src/hidapi/libusb/hid.c
+++ b/src/hidapi/libusb/hid.c
@@ -5,12 +5,9 @@
  Alan Ott
  Signal 11 Software
 
- 8/22/2009
- Linux Version - 6/2/2010
- Libusb Version - 8/13/2010
- FreeBSD Version - 11/1/2011
+ libusb/hidapi Team
 
- Copyright 2009, All Rights Reserved.
+ Copyright 2022, All Rights Reserved.
 
  At the discretion of the user of this library,
  this software may be licensed under the terms of the
@@ -23,124 +20,99 @@
         https://github.com/libusb/hidapi .
 ********************************************************/
 
-/* This file is heavily modified from the original libusb.c, for portability.
- * Last upstream update was from July 25, 2019, Git commit 93dca807.
- */
+#define _GNU_SOURCE /* needed for wcsdup() before glibc 2.10 */
 
-#include "SDL_internal.h"
-#include "../../thread/SDL_systhread.h"
+/* C */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <locale.h>
+#include <errno.h>
 
-#ifdef realloc
-#undef realloc
-#endif
-#define realloc	SDL_realloc
-#ifdef snprintf
-#undef snprintf
-#endif
-#define snprintf SDL_snprintf
-#ifdef strdup
-#undef strdup
-#endif
-#define strdup  SDL_strdup
-#ifdef strncpy
-#undef strncpy
-#endif
-#define strncpy SDL_strlcpy
-#ifdef tolower
-#undef tolower
-#endif
-#define tolower SDL_tolower
-#ifdef wcsncpy
-#undef wcsncpy
-#endif
-#define wcsncpy SDL_wcslcpy
+/* Unix */
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <wchar.h>
 
-#ifndef HAVE_WCSDUP
-#ifdef HAVE__WCSDUP
-#define wcsdup _wcsdup
-#else
-#define wcsdup _dupwcs
-static wchar_t *_dupwcs(const wchar_t *src)
-{
-    wchar_t *dst = NULL;
-    if (src) {
-        size_t len = SDL_wcslen(src) + 1;
-        len *= sizeof(wchar_t);
-        dst = (wchar_t *) malloc(len);
-        if (dst) memcpy(dst, src, len);
-    }
-    return dst;
-}
-#endif
-#endif /* HAVE_WCSDUP */
-
+/* GNU / LibUSB */
 #include <libusb.h>
-#ifndef _WIN32
-#define HAVE_SETLOCALE
-#include <locale.h> /* setlocale */
+#if !defined(__ANDROID__) && !defined(NO_ICONV)
+#include <iconv.h>
+#ifndef ICONV_CONST
+#define ICONV_CONST
+#endif
 #endif
 
-#include "../hidapi/hidapi.h"
+#include "hidapi_libusb.h"
 
-#ifdef NAMESPACE
-namespace NAMESPACE
-{
-#endif
+#if defined(__ANDROID__) && __ANDROID_API__ < __ANDROID_API_N__
 
 /* Barrier implementation because Android/Bionic don't have pthread_barrier.
    This implementation came from Brent Priddy and was posted on
    StackOverflow. It is used with his permission. */
+typedef int pthread_barrierattr_t;
+typedef struct pthread_barrier {
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    int count;
+    int trip_count;
+} pthread_barrier_t;
 
-typedef struct _SDL_ThreadBarrier
+static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
 {
-	SDL_Mutex *mutex;
-	SDL_Condition *cond;
-	Uint32 count;
-	Uint32 trip_count;
-} SDL_ThreadBarrier;
-
-static int SDL_CreateThreadBarrier(SDL_ThreadBarrier *barrier, Uint32 count)
-{
-	SDL_assert(barrier != NULL);
-	SDL_assert(count != 0);
-
-	barrier->mutex = SDL_CreateMutex();
-	if (barrier->mutex == NULL) {
-		return -1; /* Error set by CreateMutex */
-	}
-	barrier->cond = SDL_CreateCondition();
-	if (barrier->cond == NULL) {
-		return -1; /* Error set by CreateCond */
+	if(count == 0) {
+		errno = EINVAL;
+		return -1;
 	}
 
+	if(pthread_mutex_init(&barrier->mutex, 0) < 0) {
+		return -1;
+	}
+	if(pthread_cond_init(&barrier->cond, 0) < 0) {
+		pthread_mutex_destroy(&barrier->mutex);
+		return -1;
+	}
 	barrier->trip_count = count;
 	barrier->count = 0;
 
 	return 0;
 }
 
-static void SDL_DestroyThreadBarrier(SDL_ThreadBarrier *barrier)
+static int pthread_barrier_destroy(pthread_barrier_t *barrier)
 {
-	SDL_DestroyCondition(barrier->cond);
-	SDL_DestroyMutex(barrier->mutex);
-}
-
-static int SDL_WaitThreadBarrier(SDL_ThreadBarrier *barrier)
-{
-	SDL_LockMutex(barrier->mutex);
-	barrier->count += 1;
-	if (barrier->count >= barrier->trip_count) {
-		barrier->count = 0;
-		SDL_BroadcastCondition(barrier->cond);
-		SDL_UnlockMutex(barrier->mutex);
-		return 1;
-	}
-	SDL_WaitCondition(barrier->cond, barrier->mutex);
-	SDL_UnlockMutex(barrier->mutex);
+	pthread_cond_destroy(&barrier->cond);
+	pthread_mutex_destroy(&barrier->mutex);
 	return 0;
 }
 
-#if defined(__cplusplus) && !defined(NAMESPACE)
+static int pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+	pthread_mutex_lock(&barrier->mutex);
+	++(barrier->count);
+	if(barrier->count >= barrier->trip_count)
+	{
+		barrier->count = 0;
+		pthread_cond_broadcast(&barrier->cond);
+		pthread_mutex_unlock(&barrier->mutex);
+		return 1;
+	}
+	else
+	{
+		pthread_cond_wait(&barrier->cond, &(barrier->mutex));
+		pthread_mutex_unlock(&barrier->mutex);
+		return 0;
+	}
+}
+
+#endif
+
+#ifdef __cplusplus
 extern "C" {
 #endif
 
@@ -174,38 +146,49 @@
 	/* Handle to the actual device. */
 	libusb_device_handle *device_handle;
 
+	/* USB Configuration Number of the device */
+	int config_number;
+	/* The interface number of the HID */
+	int interface;
+
+	uint16_t report_descriptor_size;
+
 	/* Endpoint information */
 	int input_endpoint;
 	int output_endpoint;
 	int input_ep_max_packet_size;
 
-	/* The interface number of the HID */
-	int interface;
-	int detached_driver;
-
 	/* Indexes of Strings */
 	int manufacturer_index;
 	int product_index;
 	int serial_index;
+	struct hid_device_info* device_info;
 
 	/* Whether blocking reads are used */
 	int blocking; /* boolean */
 
 	/* Read thread objects */
-	SDL_Thread *thread;
-	SDL_Mutex *mutex; /* Protects input_reports */
-	SDL_Condition *condition;
-	SDL_ThreadBarrier barrier; /* Ensures correct startup sequence */
+	pthread_t thread;
+	pthread_mutex_t mutex; /* Protects input_reports */
+	pthread_cond_t condition;
+	pthread_barrier_t barrier; /* Ensures correct startup sequence */
 	int shutdown_thread;
 	int transfer_loop_finished;
 	struct libusb_transfer *transfer;
 
-	/* Quirks */
-	int skip_output_report_id;
-	int no_output_reports_on_intr_ep;
-
 	/* List of received input reports. */
 	struct input_report *input_reports;
+
+	/* Was kernel driver detached by libusb */
+#ifdef DETACH_KERNEL_DRIVER
+	int is_driver_detached;
+#endif
+};
+
+static struct hid_api_version api_version = {
+	.major = HID_API_VERSION_MAJOR,
+	.minor = HID_API_VERSION_MINOR,
+	.patch = HID_API_VERSION_PATCH
 };
 
 static libusb_context *usb_context = NULL;
@@ -218,9 +201,9 @@
 	hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
 	dev->blocking = 1;
 
-	dev->mutex = SDL_CreateMutex();
-	dev->condition = SDL_CreateCondition();
-	SDL_CreateThreadBarrier(&dev->barrier, 2);
+	pthread_mutex_init(&dev->mutex, NULL);
+	pthread_cond_init(&dev->condition, NULL);
+	pthread_barrier_init(&dev->barrier, NULL, 2);
 
 	return dev;
 }
@@ -228,9 +211,11 @@
 static void free_hid_device(hid_device *dev)
 {
 	/* Clean up the thread objects */
-	SDL_DestroyThreadBarrier(&dev->barrier);
-	SDL_DestroyCondition(dev->condition);
-	SDL_DestroyMutex(dev->mutex);
+	pthread_barrier_destroy(&dev->barrier);
+	pthread_cond_destroy(&dev->condition);
+	pthread_mutex_destroy(&dev->mutex);
+
+	hid_free_enumeration(dev->device_info);
 
 	/* Free the device itself */
 	free(dev);
@@ -240,10 +225,10 @@
 /*TODO: Implement this function on hidapi/libusb.. */
 static void register_error(hid_device *dev, const char *op)
 {
+
 }
 #endif
 
-#ifdef INVASIVE_GET_USAGE
 /* Get bytes from a HID Report Descriptor.
    Only call with a num_bytes of 0, 1, 2, or 4. */
 static uint32_t get_bytes(uint8_t *rpt, size_t len, size_t num_bytes, size_t cur)
@@ -319,7 +304,7 @@
 				/* Can't ever happen since size_code is & 0x3 */
 				data_len = 0;
 				break;
-			}
+			};
 			key_size = 1;
 		}
 
@@ -343,7 +328,6 @@
 
 	return -1; /* failure */
 }
-#endif /* INVASIVE_GET_USAGE */
 
 #if defined(__FreeBSD__) && __FreeBSD__ < 10
 /* The libusb version included in FreeBSD < 10 doesn't have this function. In
@@ -363,6 +347,7 @@
 		(LIBUSB_DT_STRING << 8) | descriptor_index,
 		lang_id, data, (uint16_t) length, 1000);
 }
+
 #endif
 
 
@@ -421,16 +406,15 @@
 	int len;
 	wchar_t *str = NULL;
 
-#ifndef NO_ICONV
+#if !defined(__ANDROID__) && !defined(NO_ICONV) /* we don't use iconv on Android, or when it is explicitly disabled */
 	wchar_t wbuf[256];
-	SDL_iconv_t ic;
+	/* iconv variables */
+	iconv_t ic;
 	size_t inbytes;
 	size_t outbytes;
 	size_t res;
-	const char *inptr;
+	ICONV_CONST char *inptr;
 	char *outptr;
-#else
-	int i;
 #endif
 
 	/* Determine which language to use. */
@@ -445,12 +429,12 @@
 			lang,
 			(unsigned char*)buf,
 			sizeof(buf));
-	if (len < 0)
+	if (len < 2) /* we always skip first 2 bytes */
 		return NULL;
 
-#ifdef NO_ICONV /* original hidapi code for NO_ICONV : */
+#if defined(__ANDROID__) || defined(NO_ICONV)
 
-	/* Bionic does not have wchar_t iconv support, so it
+	/* Bionic does not have iconv support nor wcsdup() function, so it
 	   has to be done manually.  The following code will only work for
 	   code points that can be represented as a single UTF-16 character,
 	   and will incorrectly convert any code points which require more
@@ -459,19 +443,21 @@
 	   Skip over the first character (2-bytes).  */
 	len -= 2;
 	str = (wchar_t*) malloc((len / 2 + 1) * sizeof(wchar_t));
+	int i;
 	for (i = 0; i < len / 2; i++) {
 		str[i] = buf[i * 2 + 2] | (buf[i * 2 + 3] << 8);
 	}
 	str[len / 2] = 0x00000000;
 
 #else
+
 	/* buf does not need to be explicitly NULL-terminated because
 	   it is only passed into iconv() which does not need it. */
 
 	/* Initialize iconv. */
-	ic = SDL_iconv_open("WCHAR_T", "UTF-16LE");
-	if (ic == (SDL_iconv_t)-1) {
-		LOG("SDL_iconv_open() failed\n");
+	ic = iconv_open("WCHAR_T", "UTF-16LE");
+	if (ic == (iconv_t)-1) {
+		LOG("iconv_open() failed\n");
 		return NULL;
 	}
 
@@ -481,9 +467,9 @@
 	inbytes = len-2;
 	outptr = (char*) wbuf;
 	outbytes = sizeof(wbuf);
-	res = SDL_iconv(ic, &inptr, &inbytes, &outptr, &outbytes);
+	res = iconv(ic, &inptr, &inbytes, &outptr, &outbytes);
 	if (res == (size_t)-1) {
-		LOG("SDL_iconv() failed\n");
+		LOG("iconv() failed\n");
 		goto err;
 	}
 
@@ -496,145 +482,73 @@
 	str = wcsdup(wbuf);
 
 err:
-	SDL_iconv_close(ic);
+	iconv_close(ic);
+
 #endif
 
 	return str;
 }
 
-struct usb_string_cache_entry {
-	uint16_t vid;
-	uint16_t pid;
-	wchar_t *vendor;
-	wchar_t *product;
-};
-
-static struct usb_string_cache_entry *usb_string_cache = NULL;
-static size_t usb_string_cache_size = 0;
-static size_t usb_string_cache_insert_pos = 0;
-
-static int usb_string_cache_grow()
+/**
+  Max length of the result: "000-000.000.000.000.000.000.000:000.000" (39 chars).
+  64 is used for simplicity/alignment.
+*/
+static void get_path(char (*result)[64], libusb_device *dev, int config_number, int interface_number)
 {
-	struct usb_string_cache_entry *new_cache;
-	size_t allocSize;
-	size_t new_cache_size;
+	char *str = *result;
 
-	new_cache_size = usb_string_cache_size + 8;
-	allocSize = sizeof(struct usb_string_cache_entry) * new_cache_size;
-	new_cache = (struct usb_string_cache_entry *)realloc(usb_string_cache, allocSize);
-	if (!new_cache)
-		return -1;
+	/* Note that USB3 port count limit is 7; use 8 here for alignment */
+	uint8_t port_numbers[8] = {0, 0, 0, 0, 0, 0, 0, 0};
+	int num_ports = libusb_get_port_numbers(dev, port_numbers, 8);
 
-	usb_string_cache = new_cache;
-	usb_string_cache_size = new_cache_size;
-
-	return 0;
+	if (num_ports > 0) {
+		int n = snprintf(str, sizeof("000-000"), "%u-%u", libusb_get_bus_number(dev), port_numbers[0]);
+		for (uint8_t i = 1; i < num_ports; i++) {
+			n += snprintf(&str[n], sizeof(".000"), ".%u", port_numbers[i]);
+		}
+		n += snprintf(&str[n], sizeof(":000.000"), ":%u.%u", (uint8_t)config_number, (uint8_t)interface_number);
+		str[n] = '\0';
+	} else {
+		/* Likely impossible, but check: USB3.0 specs limit number of ports to 7 and buffer size here is 8 */
+		if (num_ports == LIBUSB_ERROR_OVERFLOW) {
+			LOG("make_path() failed. buffer overflow error\n");
+		} else {
+			LOG("make_path() failed. unknown error\n");
+		}
+		str[0] = '\0';
+	}
 }
 
-static void usb_string_cache_destroy()
-{
-	size_t i;
-	for (i = 0; i < usb_string_cache_insert_pos; i++) {
-		free(usb_string_cache[i].vendor);
-		free(usb_string_cache[i].product);
-	}
-	free(usb_string_cache);
-
-	usb_string_cache = NULL;
-	usb_string_cache_size = 0;
-	usb_string_cache_insert_pos = 0;
-}
-
-static struct usb_string_cache_entry *usb_string_cache_insert()
-{
-	struct usb_string_cache_entry *new_entry = NULL;
-	if (usb_string_cache_insert_pos >= usb_string_cache_size) {
-		if (usb_string_cache_grow() < 0)
-			return NULL;
-	}
-	new_entry = &usb_string_cache[usb_string_cache_insert_pos];
-	usb_string_cache_insert_pos++;
-	return new_entry;
-}
-
-static int usb_string_can_cache(uint16_t vid, uint16_t pid)
-{
-	if (!vid || !pid) {
-		/* We can't cache these, they aren't unique */
-		return 0;
-	}
-
-	if (vid == 0x0f0d && pid == 0x00dc) {
-		/* HORI reuses this VID/PID for many different products */
-		return 0;
-	}
-
-	/* We can cache these strings */
-	return 1;
-}
-
-static const struct usb_string_cache_entry *usb_string_cache_find(struct libusb_device_descriptor *desc, struct libusb_device_handle *handle)
-{
-	struct usb_string_cache_entry *entry = NULL;
-	size_t i;
-
-	/* Search for existing string cache entry */
-	for (i = 0; i < usb_string_cache_insert_pos; i++) {
-		entry = &usb_string_cache[i];
-		if (entry->vid != desc->idVendor)
-			continue;
-		if (entry->pid != desc->idProduct)
-			continue;
-		return entry;
-	}
-
-	/* Not found, create one. */
-	entry = usb_string_cache_insert();
-	if (!entry)
-		return NULL;
-
-	entry->vid = desc->idVendor;
-	entry->pid = desc->idProduct;
-	if (desc->iManufacturer > 0)
-		entry->vendor = get_usb_string(handle, desc->iManufacturer);
-	else
-		entry->vendor = NULL;
-	if (desc->iProduct > 0)
-		entry->product = get_usb_string(handle, desc->iProduct);
-	else
-		entry->product = NULL;
-
-	return entry;
-}
-
-static char *make_path(libusb_device *dev, int interface_number)
+static char *make_path(libusb_device *dev, int config_number, int interface_number)
 {
 	char str[64];
-	snprintf(str, sizeof(str), "%04x:%04x:%02x",
-		libusb_get_bus_number(dev),
-		libusb_get_device_address(dev),
-		interface_number);
-	str[sizeof(str)-1] = '\0';
-
+	get_path(&str, dev, config_number, interface_number);
 	return strdup(str);
 }
 
+HID_API_EXPORT const struct hid_api_version* HID_API_CALL hid_version(void)
+{
+	return &api_version;
+}
+
+HID_API_EXPORT const char* HID_API_CALL hid_version_str(void)
+{
+	return HID_API_VERSION_STR;
+}
 
 int HID_API_EXPORT hid_init(void)
 {
 	if (!usb_context) {
+		const char *locale;
+
 		/* Init Libusb */
 		if (libusb_init(&usb_context))
 			return -1;
 
-#ifdef HAVE_SETLOCALE
 		/* Set the locale if it's not set. */
-		{
-			const char *locale = setlocale(LC_CTYPE, NULL);
-			if (!locale)
-				setlocale(LC_CTYPE, "");
-		}
-#endif
+		locale = setlocale(LC_CTYPE, NULL);
+		if (!locale)
+			setlocale(LC_CTYPE, "");
 	}
 
 	return 0;
@@ -642,8 +556,6 @@
 
 int HID_API_EXPORT hid_exit(void)
 {
-	usb_string_cache_destroy();
-
 	if (usb_context) {
 		libusb_exit(usb_context);
 		usb_context = NULL;
@@ -652,116 +564,191 @@
 	return 0;
 }
 
-static int is_xbox360(unsigned short vendor_id, const struct libusb_interface_descriptor *intf_desc)
+static int hid_get_report_descriptor_libusb(libusb_device_handle *handle, int interface_num, uint16_t expected_report_descriptor_size, unsigned char *buf, size_t buf_size)
 {
-	static const int XB360_IFACE_SUBCLASS = 93;
-	static const int XB360_IFACE_PROTOCOL = 1; /* Wired */
-	static const int XB360W_IFACE_PROTOCOL = 129; /* Wireless */
-	static const int SUPPORTED_VENDORS[] = {
-		0x0079, /* GPD Win 2 */
-		0x044f, /* Thrustmaster */
-		0x045e, /* Microsoft */
-		0x046d, /* Logitech */
-		0x056e, /* Elecom */
-		0x06a3, /* Saitek */
-		0x0738, /* Mad Catz */
-		0x07ff, /* Mad Catz */
-		0x0e6f, /* PDP */
-		0x0f0d, /* Hori */
-		0x1038, /* SteelSeries */
-		0x11c9, /* Nacon */
-		0x12ab, /* Unknown */
-		0x1430, /* RedOctane */
-		0x146b, /* BigBen */
-		0x1532, /* Razer Sabertooth */
-		0x15e4, /* Numark */
-		0x162e, /* Joytech */
-		0x1689, /* Razer Onza */
-		0x1949, /* Lab126, Inc. */
-		0x1bad, /* Harmonix */
-		0x20d6, /* PowerA */
-		0x24c6, /* PowerA */
-		0x2c22, /* Qanba */
-		0x2dc8, /* 8BitDo */
-        0x9886, /* ASTRO Gaming */
-	};
+	unsigned char tmp[HID_API_MAX_REPORT_DESCRIPTOR_SIZE];
 
-	if (intf_desc->bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
-	    intf_desc->bInterfaceSubClass == XB360_IFACE_SUBCLASS &&
-	    (intf_desc->bInterfaceProtocol == XB360_IFACE_PROTOCOL ||
-	     intf_desc->bInterfaceProtocol == XB360W_IFACE_PROTOCOL)) {
-		int i;
-		for (i = 0; i < sizeof(SUPPORTED_VENDORS)/sizeof(SUPPORTED_VENDORS[0]); ++i) {
-			if (vendor_id == SUPPORTED_VENDORS[i]) {
-				return 1;
-			}
-		}
+	if (expected_report_descriptor_size > HID_API_MAX_REPORT_DESCRIPTOR_SIZE)
+		expected_report_descriptor_size = HID_API_MAX_REPORT_DESCRIPTOR_SIZE;
+
+	/* Get the HID Report Descriptor.
+	   See USB HID Specificatin, sectin 7.1.1
+	*/
+	int res = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8), interface_num, tmp, expected_report_descriptor_size, 5000);
+	if (res < 0) {
+		LOG("libusb_control_transfer() for getting the HID Report descriptor failed with %d: %s\n", res, libusb_error_name(res));
+		return -1;
 	}
-	return 0;
+
+	if (res > (int)buf_size)
+		res = (int)buf_size;
+
+	memcpy(buf, tmp, (size_t)res);
+	return res;
 }
 
-static int is_xboxone(unsigned short vendor_id, const struct libusb_interface_descriptor *intf_desc)
+/**
+ * Requires an opened device with *claimed interface*.
+ */
+static void fill_device_info_usage(struct hid_device_info *cur_dev, libusb_device_handle *handle, int interface_num, uint16_t expected_report_descriptor_size)
 {
-	static const int XB1_IFACE_SUBCLASS = 71;
-	static const int XB1_IFACE_PROTOCOL = 208;
-	static const int SUPPORTED_VENDORS[] = {
-		0x044f, /* Thrustmaster */
-		0x045e, /* Microsoft */
-		0x0738, /* Mad Catz */
-		0x0e6f, /* PDP */
-		0x0f0d, /* Hori */
-        0x10f5, /* Turtle Beach */
-		0x1532, /* Razer Wildcat */
-		0x20d6, /* PowerA */
-		0x24c6, /* PowerA */
-		0x2dc8, /* 8BitDo */
-		0x2e24, /* Hyperkin */
-        0x3537, /* GameSir */
-	};
+	unsigned char hid_report_descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE];
+	unsigned short page = 0, usage = 0;
 
-	if (intf_desc->bInterfaceNumber == 0 &&
-	    intf_desc->bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
-	    intf_desc->bInterfaceSubClass == XB1_IFACE_SUBCLASS &&
-	    intf_desc->bInterfaceProtocol == XB1_IFACE_PROTOCOL) {
-		int i;
-		for (i = 0; i < sizeof(SUPPORTED_VENDORS)/sizeof(SUPPORTED_VENDORS[0]); ++i) {
-			if (vendor_id == SUPPORTED_VENDORS[i]) {
-				return 1;
-			}
-		}
+	int res = hid_get_report_descriptor_libusb(handle, interface_num, expected_report_descriptor_size, hid_report_descriptor, sizeof(hid_report_descriptor));
+	if (res >= 0) {
+		/* Parse the usage and usage page
+		   out of the report descriptor. */
+		get_usage(hid_report_descriptor, res,  &page, &usage);
 	}
-	return 0;
+
+	cur_dev->usage_page = page;
+	cur_dev->usage = usage;
 }
 
-static int should_enumerate_interface(unsigned short vendor_id, const struct libusb_interface_descriptor *intf_desc)
+#ifdef INVASIVE_GET_USAGE
+static void invasive_fill_device_info_usage(struct hid_device_info *cur_dev, libusb_device_handle *handle, int interface_num, uint16_t report_descriptor_size)
 {
-	//printf("Checking interface 0x%x %d/%d/%d/%d\n", vendor_id, intf_desc->bInterfaceNumber, intf_desc->bInterfaceClass, intf_desc->bInterfaceSubClass, intf_desc->bInterfaceProtocol);
+	int res = 0;
 
-	if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID)
-		return 1;
+#ifdef DETACH_KERNEL_DRIVER
+	int detached = 0;
+	/* Usage Page and Usage */
+	res = libusb_kernel_driver_active(handle, interface_num);
+	if (res == 1) {
+		res = libusb_detach_kernel_driver(handle, interface_num);
+		if (res < 0)
+			LOG("Couldn't detach kernel driver, even though a kernel driver was attached.\n");
+		else
+			detached = 1;
+	}
+#endif
 
-	/* Also enumerate Xbox 360 controllers */
-	if (is_xbox360(vendor_id, intf_desc))
-		return 1;
+	res = libusb_claim_interface(handle, interface_num);
+	if (res >= 0) {
+		fill_device_info_usage(cur_dev, handle, interface_num, report_descriptor_size);
 
-	/* Also enumerate Xbox One controllers */
-	if (is_xboxone(vendor_id, intf_desc))
-		return 1;
+		/* Release the interface */
+		res = libusb_release_interface(handle, interface_num);
+		if (res < 0)
+			LOG("Can't release the interface.\n");
+	}
+	else
+		LOG("Can't claim interface: (%d) %s\n", res, libusb_error_name(res));
 
-	return 0;
+#ifdef DETACH_KERNEL_DRIVER
+	/* Re-attach kernel driver if necessary. */
+	if (detached) {
+		res = libusb_attach_kernel_driver(handle, interface_num);
+		if (res < 0)
+			LOG("Couldn't re-attach kernel driver.\n");
+	}
+#endif
+}
+#endif /* INVASIVE_GET_USAGE */
+
+/**
+ * Create and fill up most of hid_device_info fields.
+ * usage_page/usage is not filled up.
+ */
+static struct hid_device_info * create_device_info_for_device(libusb_device *device, libusb_device_handle *handle, struct libusb_device_descriptor *desc, int config_number, int interface_num)
+{
+	struct hid_device_info *cur_dev = calloc(1, sizeof(struct hid_device_info));
+	if (cur_dev == NULL) {
+		return NULL;
+	}
+
+	/* VID/PID */
+	cur_dev->vendor_id = desc->idVendor;
+	cur_dev->product_id = desc->idProduct;
+
+	cur_dev->release_number = desc->bcdDevice;
+
+	cur_dev->interface_number = interface_num;
+
+	cur_dev->bus_type = HID_API_BUS_USB;
+
+	cur_dev->path = make_path(device, config_number, interface_num);
+
+	if (!handle) {
+		return cur_dev;
+	}
+
+	if (desc->iSerialNumber > 0)
+		cur_dev->serial_number = get_usb_string(handle, desc->iSerialNumber);
+
+	/* Manufacturer and Product strings */
+	if (desc->iManufacturer > 0)
+		cur_dev->manufacturer_string = get_usb_string(handle, desc->iManufacturer);
+	if (desc->iProduct > 0)
+		cur_dev->product_string = get_usb_string(handle, desc->iProduct);
+
+	return cur_dev;
+}
+
+static uint16_t get_report_descriptor_size_from_interface_descriptors(const struct libusb_interface_descriptor *intf_desc)
+{
+	int i = 0;
+	int found_hid_report_descriptor = 0;
+	uint16_t result = HID_API_MAX_REPORT_DESCRIPTOR_SIZE;
+	const unsigned char *extra = intf_desc->extra;
+	int extra_length = intf_desc->extra_length;
+
+	/*
+	 "extra" contains a HID descriptor
+	 See section 6.2.1 of HID 1.1 specification.
+	*/
+
+	while (extra_length >= 2) { /* Descriptor header: bLength/bDescriptorType */
+		if (extra[1] == LIBUSB_DT_HID) { /* bDescriptorType */
+			if (extra_length < 6) {
+				LOG("Broken HID descriptor: not enough data\n");
+				break;
+			}
+			unsigned char bNumDescriptors = extra[5];
+			if (extra_length < (6 + 3 * bNumDescriptors)) {
+				LOG("Broken HID descriptor: not enough data for Report metadata\n");
+				break;
+			}
+			for (i = 0; i < bNumDescriptors; i++) {
+				if (extra[6 + 3 * i] == LIBUSB_DT_REPORT) {
+					result = (uint16_t)extra[6 + 3 * i + 2] << 8 | extra[6 + 3 * i + 1];
+					found_hid_report_descriptor = 1;
+					break;
+				}
+			}
+
+			if (!found_hid_report_descriptor) {
+				/* We expect to find exactly 1 HID descriptor (LIBUSB_DT_HID)
+				   which should contain exactly one HID Report Descriptor metadata (LIBUSB_DT_REPORT). */
+				LOG("Broken HID descriptor: missing Report descriptor\n");
+			}
+			break;
+		}
+
+		if (extra[0] == 0) { /* bLength */
+			LOG("Broken HID Interface descriptors: zero-sized descriptor\n");
+			break;
+		}
+
+		/* Iterate over to the next Descriptor */
+		extra_length -= extra[0];
+		extra += extra[0];
+	}
+
+	return result;
 }
 
 struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
 {
 	libusb_device **devs;
 	libusb_device *dev;
-	libusb_device_handle *handle;
+	libusb_device_handle *handle = NULL;
 	ssize_t num_devs;
 	int i = 0;
 
 	struct hid_device_info *root = NULL; /* return object */
 	struct hid_device_info *cur_dev = NULL;
-	const char *hint = SDL_GetHint(SDL_HINT_HIDAPI_IGNORE_DEVICES);
 
 	if(hid_init() < 0)
 		return NULL;
@@ -773,85 +760,48 @@
 		struct libusb_device_descriptor desc;
 		struct libusb_config_descriptor *conf_desc = NULL;
 		int j, k;
-		int interface_num = 0;
 
 		int res = libusb_get_device_descriptor(dev, &desc);
 		unsigned short dev_vid = desc.idVendor;
 		unsigned short dev_pid = desc.idProduct;
 
-		/* See if there are any devices we should skip in enumeration */
-		if (hint) {
-			char vendor_match[16], product_match[16];
-			SDL_snprintf(vendor_match, sizeof(vendor_match), "0x%.4x/0x0000", dev_vid);
-			SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", dev_vid, dev_pid);
-			if (SDL_strcasestr(hint, vendor_match) || SDL_strcasestr(hint, product_match)) {
-				continue;
-			}
+		if ((vendor_id != 0x0 && vendor_id != dev_vid) ||
+		    (product_id != 0x0 && product_id != dev_pid)) {
+			continue;
 		}
 
 		res = libusb_get_active_config_descriptor(dev, &conf_desc);
 		if (res < 0)
 			libusb_get_config_descriptor(dev, 0, &conf_desc);
 		if (conf_desc) {
-
 			for (j = 0; j < conf_desc->bNumInterfaces; j++) {
 				const struct libusb_interface *intf = &conf_desc->interface[j];
 				for (k = 0; k < intf->num_altsetting; k++) {
 					const struct libusb_interface_descriptor *intf_desc;
 					intf_desc = &intf->altsetting[k];
-					if (should_enumerate_interface(dev_vid, intf_desc)) {
-						interface_num = intf_desc->bInterfaceNumber;
+					if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) {
+						struct hid_device_info *tmp;
 
-						/* Check the VID/PID against the arguments */
-						if ((vendor_id == 0x0 || vendor_id == dev_vid) &&
-						    (product_id == 0x0 || product_id == dev_pid)) {
-							res = libusb_open(dev, &handle);
+						res = libusb_open(dev, &handle);
 
-							if (res >= 0) {
-								struct hid_device_info *tmp;
-								const struct usb_string_cache_entry *string_cache;
+#ifdef __ANDROID__
+						if (handle) {
+							/* There is (a potential) libusb Android backend, in which
+							   device descriptor is not accurate up until the device is opened.
+							   https://github.com/libusb/libusb/pull/874#discussion_r632801373
+							   A workaround is to re-read the descriptor again.
+							   Even if it is not going to be accepted into libusb master,
+							   having it here won't do any harm, since reading the device descriptor
+							   is as cheap as copy 18 bytes of data. */
+							libusb_get_device_descriptor(dev, &desc);
+						}
+#endif
 
-								/* VID/PID match. Create the record. */
-								tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
-								if (cur_dev) {
-									cur_dev->next = tmp;
-								}
-								else {
-									root = tmp;
-								}
-								cur_dev = tmp;
-
-								/* Fill out the record */
-								cur_dev->next = NULL;
-								cur_dev->path = make_path(dev, interface_num);
-
-								/* Serial Number */
-								if (desc.iSerialNumber > 0)
-									cur_dev->serial_number =
-										get_usb_string(handle, desc.iSerialNumber);
-
-								/* Manufacturer and Product strings */
-								if (usb_string_can_cache(dev_vid, dev_pid)) {
-									string_cache = usb_string_cache_find(&desc, handle);
-									if (string_cache) {
-										if (string_cache->vendor) {
-											cur_dev->manufacturer_string = wcsdup(string_cache->vendor);
-										}
-										if (string_cache->product) {
-											cur_dev->product_string = wcsdup(string_cache->product);
-										}
-									}
-								} else {
-									if (desc.iManufacturer > 0)
-										cur_dev->manufacturer_string =
-											get_usb_string(handle, desc.iManufacturer);
-									if (desc.iProduct > 0)
-										cur_dev->product_string =
-											get_usb_string(handle, desc.iProduct);
-								}
-
+						tmp = create_device_info_for_device(dev, handle, &desc, conf_desc->bConfigurationValue, intf_desc->bInterfaceNumber);
+						if (tmp) {
 #ifdef INVASIVE_GET_USAGE
-{
+							/* TODO: have a runtime check for this section. */
+
 							/*
 							This section is removed because it is too
 							invasive on the system. Getting a Usage Page
@@ -864,72 +814,28 @@
 							app has them claimed) and the re-attachment of
 							the driver will sometimes change /dev entry names.
 							It is for these reasons that this section is
-							#if 0. For composite devices, use the interface
+							optional. For composite devices, use the interface
 							field in the hid_device_info struct to distinguish
 							between interfaces. */
-								unsigned char data[256];
-#ifdef DETACH_KERNEL_DRIVER
-								int detached = 0;
-								/* Usage Page and Usage */
-								res = libusb_kernel_driver_active(handle, interface_num);
-								if (res == 1) {
-									res = libusb_detach_kernel_driver(handle, interface_num);
-									if (res < 0)
-										LOG("Couldn't detach kernel driver, even though a kernel driver was attached.");
-									else
-										detached = 1;
-								}
-#endif
-								res = libusb_claim_interface(handle, interface_num);
-								if (res >= 0) {
-									/* Get the HID Report Descriptor. */
-									res = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8)|interface_num, 0, data, sizeof(data), 5000);
-									if (res >= 0) {
-										unsigned short page=0, usage=0;
-										/* Parse the usage and usage page
-										   out of the report descriptor. */
-										get_usage(data, res,  &page, &usage);
-										cur_dev->usage_page = page;
-										cur_dev->usage = usage;
-									}
-									else
-										LOG("libusb_control_transfer() for getting the HID report failed with %d\n", res);
+							if (handle) {
+								uint16_t report_descriptor_size = get_report_descriptor_size_from_interface_descriptors(intf_desc);
 
-									/* Release the interface */
-									res = libusb_release_interface(handle, interface_num);
-									if (res < 0)
-										LOG("Can't release the interface.\n");
-								}
-								else
-									LOG("Can't claim interface %d\n", res);
-#ifdef DETACH_KERNEL_DRIVER
-								/* Re-attach kernel driver if necessary. */
-								if (detached) {
-									res = libusb_attach_kernel_driver(handle, interface_num);
-									if (res < 0)
-										LOG("Couldn't re-attach kernel driver.\n");
-								}
-#endif
-}
+								invasive_fill_device_info_usage(tmp, handle, intf_desc->bInterfaceNumber, report_descriptor_size);
+							}
 #endif /* INVASIVE_GET_USAGE */
 
-								libusb_close(handle);
+							if (cur_dev) {
+								cur_dev->next = tmp;
+							}
+							else {
+								root = tmp;
+							}
+							cur_dev = tmp;
+						}
 
-								/* VID/PID */
-								cur_dev->vendor_id = dev_vid;
-								cur_dev->product_id = dev_pid;
-
-								/* Release Number */
-								cur_dev->release_number = desc.bcdDevice;
-
-								/* Interface Number */
-								cur_dev->interface_number = interface_num;
-								cur_dev->interface_class = intf_desc->bInterfaceClass;
-								cur_dev->interface_subclass = intf_desc->bInterfaceSubClass;
-								cur_dev->interface_protocol = intf_desc->bInterfaceProtocol;
-
-							} else
-								LOG("Can't open device 0x%.4x/0x%.4x during enumeration: %d\n", dev_vid, dev_pid, res);
+						if (res >= 0) {
+							libusb_close(handle);
+							handle = NULL;
 						}
 					}
 				} /* altsettings */
@@ -985,7 +891,7 @@
 
 	if (path_to_open) {
 		/* Open the device */
-		handle = hid_open_path(path_to_open, 0);
+		handle = hid_open_path(path_to_open);
 	}
 
 	hid_free_enumeration(devs);
@@ -993,9 +899,9 @@
 	return handle;
 }
 
-static void LIBUSB_CALL read_callback(struct libusb_transfer *transfer)
+static void read_callback(struct libusb_transfer *transfer)
 {
-	hid_device *dev = (hid_device *)transfer->user_data;
+	hid_device *dev = transfer->user_data;
 	int res;
 
 	if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
@@ -1006,13 +912,13 @@
 		rpt->len = transfer->actual_length;
 		rpt->next = NULL;
 
-		SDL_LockMutex(dev->mutex);
+		pthread_mutex_lock(&dev->mutex);
 
 		/* Attach the new report object to the end of the list. */
 		if (dev->input_reports == NULL) {
 			/* The list is empty. Put it at the root. */
 			dev->input_reports = rpt;
-			SDL_SignalCondition(dev->condition);
+			pthread_cond_signal(&dev->condition);
 		}
 		else {
 			/* Find the end of the list and attach. */
@@ -1031,7 +937,7 @@
 				return_data(dev, NULL, 0);
 			}
 		}
-		SDL_UnlockMutex(dev->mutex);
+		pthread_mutex_unlock(&dev->mutex);
 	}
 	else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
 		dev->shutdown_thread = 1;
@@ -1054,17 +960,17 @@
 	/* Re-submit the transfer object. */
 	res = libusb_submit_transfer(transfer);
 	if (res != 0) {
-		LOG("Unable to submit URB. libusb error code: %d\n", res);
+		LOG("Unable to submit URB: (%d) %s\n", res, libusb_error_name(res));
 		dev->shutdown_thread = 1;
 		dev->transfer_loop_finished = 1;
 	}
 }
 
 
-static int SDLCALL read_thread(void *param)
+static void *read_thread(void *param)
 {
 	int res;
-	hid_device *dev = (hid_device *)param;
+	hid_device *dev = param;
 	uint8_t *buf;
 	const size_t length = dev->input_ep_max_packet_size;
 
@@ -1090,14 +996,14 @@
 	}
 
 	/* Notify the main thread that the read thread is up and running. */
-	SDL_WaitThreadBarrier(&dev->barrier);
+	pthread_barrier_wait(&dev->barrier);
 
 	/* Handle all the events. */
 	while (!dev->shutdown_thread) {
 		res = libusb_handle_events(usb_context);
 		if (res < 0) {
 			/* There was an error. */
-			LOG("read_thread(): libusb reports error # %d\n", res);
+			LOG("read_thread(): (%d) %s\n", res, libusb_error_name(res));
 
 			/* Break out of this loop only on fatal error.*/
 			if (res != LIBUSB_ERROR_BUSY &&
@@ -1122,9 +1028,9 @@
 	   make sure that a thread which is about to go to sleep waiting on
 	   the condition actually will go to sleep before the condition is
 	   signaled. */
-	SDL_LockMutex(dev->mutex);
-	SDL_BroadcastCondition(dev->condition);
-	SDL_UnlockMutex(dev->mutex);
+	pthread_mutex_lock(&dev->mutex);
+	pthread_cond_broadcast(&dev->condition);
+	pthread_mutex_unlock(&dev->mutex);
 
 	/* The dev->transfer->buffer and dev->transfer objects are cleaned up
 	   in hid_close(). They are not cleaned up here because this thread
@@ -1134,88 +1040,109 @@
 	   since hid_close() calls libusb_cancel_transfer(), on these objects,
 	   they can not be cleaned up here. */
 
-	return 0;
+	return NULL;
 }
 
-static void init_xbox360(libusb_device_handle *device_handle, unsigned short idVendor, unsigned short idProduct, struct libusb_config_descriptor *conf_desc)
+
+static int hidapi_initialize_device(hid_device *dev, int config_number, const struct libusb_interface_descriptor *intf_desc)
 {
-	if ((idVendor == 0x05ac && idProduct == 0x055b) /* Gamesir-G3w */ ||
-	    idVendor == 0x0f0d /* Hori Xbox controllers */) {
-		unsigned char data[20];
+	int i =0;
+	int res = 0;
+	struct libusb_device_descriptor desc;
+	libusb_get_device_descriptor(libusb_get_device(dev->device_handle), &desc);
 
-		/* The HORIPAD FPS for Nintendo Switch requires this to enable input reports.
-		   This VID/PID is also shared with other HORI controllers, but they all seem
-		   to be fine with this as well.
-		 */
-		libusb_control_transfer(device_handle, 0xC1, 0x01, 0x100, 0x0, data, sizeof(data), 100);
-	}
-}
-
-static void init_xboxone(libusb_device_handle *device_handle, unsigned short idVendor, unsigned short idProduct, struct libusb_config_descriptor *conf_desc)
-{
-	static const int VENDOR_MICROSOFT = 0x045e;
-	static const int XB1_IFACE_SUBCLASS = 71;
-	static const int XB1_IFACE_PROTOCOL = 208;
-	int j, k, res;
-
-	for (j = 0; j < conf_desc->bNumInterfaces; j++) {
-		const struct libusb_interface *intf = &conf_desc->interface[j];
-		for (k = 0; k < intf->num_altsetting; k++) {
-			const struct libusb_interface_descriptor *intf_desc = &intf->altsetting[k];
-			if (intf_desc->bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
-			    intf_desc->bInterfaceSubClass == XB1_IFACE_SUBCLASS &&
-			    intf_desc->bInterfaceProtocol == XB1_IFACE_PROTOCOL) {
-				int bSetAlternateSetting = 0;
-
-				/* Newer Microsoft Xbox One controllers have a high speed alternate setting */
-				if (idVendor == VENDOR_MICROSOFT &&
-				    intf_desc->bInterfaceNumber == 0 && intf_desc->bAlternateSetting == 1) {
-					bSetAlternateSetting = 1;
-				} else if (intf_desc->bInterfaceNumber != 0 && intf_desc->bAlternateSetting == 0) {
-					bSetAlternateSetting = 1;
-				}
-
-				if (bSetAlternateSetting) {
-					res = libusb_claim_interface(device_handle, intf_desc->bInterfaceNumber);
-					if (res < 0) {
-						LOG("can't claim interface %d: %d\n", intf_desc->bInterfaceNumber, res);
-						continue;
-					}
-
-					LOG("Setting alternate setting for VID/PID 0x%x/0x%x interface %d to %d\n",  idVendor, idProduct, intf_desc->bInterfaceNumber, intf_desc->bAlternateSetting);
-
-					res = libusb_set_interface_alt_setting(device_handle, intf_desc->bInterfaceNumber, intf_desc->bAlternateSetting);
-					if (res < 0) {
-						LOG("xbox init: can't set alt setting %d: %d\n", intf_desc->bInterfaceNumber, res);
-					}
-
-					libusb_release_interface(device_handle, intf_desc->bInterfaceNumber);
-				}
-			}
+#ifdef DETACH_KERNEL_DRIVER
+	/* Detach the kernel driver, but only if the
+	   device is managed by the kernel */
+	dev->is_driver_detached = 0;
+	if (libusb_kernel_driver_active(dev->device_handle, intf_desc->bInterfaceNumber) == 1) {
+		res = libusb_detach_kernel_driver(dev->device_handle, intf_desc->bInterfaceNumber);
+		if (res < 0) {
+			LOG("Unable to detach Kernel Driver: (%d) %s\n", res, libusb_error_name(res));
+			return 0;
+		}
+		else {
+			dev->is_driver_detached = 1;
+			LOG("Driver successfully detached from kernel.\n");
 		}
 	}
-}
+#endif
+	res = libusb_claim_interface(dev->device_handle, intf_desc->bInterfaceNumber);
+	if (res < 0) {
+		LOG("can't claim interface %d: (%d) %s\n", intf_desc->bInterfaceNumber, res, libusb_error_name(res));
 
-static void calculate_device_quirks(hid_device *dev, unsigned short idVendor, unsigned short idProduct)
-{
-	static const int VENDOR_SONY = 0x054c;
-	static const int PRODUCT_PS3_CONTROLLER = 0x0268;
-	static const int PRODUCT_NAVIGATION_CONTROLLER = 0x042f;
-
-	if (idVendor == VENDOR_SONY &&
-	    (idProduct == PRODUCT_PS3_CONTROLLER || idProduct == PRODUCT_NAVIGATION_CONTROLLER)) {
-		dev->skip_output_report_id = 1;
-		dev->no_output_reports_on_intr_ep = 1;
+#ifdef DETACH_KERNEL_DRIVER
+		if (dev->is_driver_detached) {
+			res = libusb_attach_kernel_driver(dev->device_handle, intf_desc->bInterfaceNumber);
+			if (res < 0)
+				LOG("Failed to reattach the driver to kernel: (%d) %s\n", res, libusb_error_name(res));
+		}
+#endif
+		return 0;
 	}
+
+	/* Store off the string descriptor indexes */
+	dev->manufacturer_index = desc.iManufacturer;
+	dev->product_index      = desc.iProduct;
+	dev->serial_index       = desc.iSerialNumber;
+
+	/* Store off the USB information */
+	dev->config_number = config_number;
+	dev->interface = intf_desc->bInterfaceNumber;
+
+	dev->report_descriptor_size = get_report_descriptor_size_from_interface_descriptors(intf_desc);
+
+	dev->input_endpoint = 0;
+	dev->input_ep_max_packet_size = 0;
+	dev->output_endpoint = 0;
+
+	/* Find the INPUT and OUTPUT endpoints. An
+	   OUTPUT endpoint is not required. */
+	for (i = 0; i < intf_desc->bNumEndpoints; i++) {
+		const struct libusb_endpoint_descriptor *ep
+			= &intf_desc->endpoint[i];
+
+		/* Determine the type and direction of this
+		   endpoint. */
+		int is_interrupt =
+			(ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK)
+		      == LIBUSB_TRANSFER_TYPE_INTERRUPT;
+		int is_output =
+			(ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
+		      == LIBUSB_ENDPOINT_OUT;
+		int is_input =
+			(ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
+		      == LIBUSB_ENDPOINT_IN;
+
+		/* Decide whether to use it for input or output. */
+		if (dev->input_endpoint == 0 &&
+		    is_interrupt && is_input) {
+			/* Use this endpoint for INPUT */
+			dev->input_endpoint = ep->bEndpointAddress;
+			dev->input_ep_max_packet_size = ep->wMaxPacketSize;
+		}
+		if (dev->output_endpoint == 0 &&
+		    is_interrupt && is_output) {
+			/* Use this endpoint for OUTPUT */
+			dev->output_endpoint = ep->bEndpointAddress;
+		}
+	}
+
+	pthread_create(&dev->thread, NULL, read_thread, dev);
+
+	/* Wait here for the read thread to be initialized. */
+	pthread_barrier_wait(&dev->barrier);
+	return 1;
 }
 
-hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
+
+hid_device * HID_API_EXPORT hid_open_path(const char *path)
 {
 	hid_device *dev = NULL;
 
-	libusb_device **devs;
-	libusb_device *usb_dev;
-	int res;
+	libusb_device **devs = NULL;
+	libusb_device *usb_dev = NULL;
+	int res = 0;
 	int d = 0;
 	int good_open = 0;
 
@@ -1225,129 +1152,36 @@
 	dev = new_hid_device();
 
 	libusb_get_device_list(usb_context, &devs);
-	while ((usb_dev = devs[d++]) != NULL) {
-		struct libusb_device_descriptor desc;
+	while ((usb_dev = devs[d++]) != NULL && !good_open) {
 		struct libusb_config_descriptor *conf_desc = NULL;
-		int i,j,k;
+		int j,k;
 
-		libusb_get_device_descriptor(usb_dev, &desc);
-
-		res = libusb_get_active_config_descriptor(usb_dev, &conf_desc);
-		if (res < 0)
-			libusb_get_config_descriptor(usb_dev, 0, &conf_desc);
-		if (!conf_desc)
+		if (libusb_get_active_config_descriptor(usb_dev, &conf_desc) < 0)
 			continue;
 		for (j = 0; j < conf_desc->bNumInterfaces && !good_open; j++) {
 			const struct libusb_interface *intf = &conf_desc->interface[j];
 			for (k = 0; k < intf->num_altsetting && !good_open; k++) {
-				const struct libusb_interface_descriptor *intf_desc;
-				intf_desc = &intf->altsetting[k];
-				if (should_enumerate_interface(desc.idVendor, intf_desc)) {
-					char *dev_path = make_path(usb_dev, intf_desc->bInterfaceNumber);
+				const struct libusb_interface_descriptor *intf_desc = &intf->altsetting[k];
+				if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) {
+					char dev_path[64];
+					get_path(&dev_path, usb_dev, conf_desc->bConfigurationValue, intf_desc->bInterfaceNumber);
 					if (!strcmp(dev_path, path)) {
-						int detached_driver = 0;
-
 						/* Matched Paths. Open this device */
 
 						/* OPEN HERE */
 						res = libusb_open(usb_dev, &dev->device_handle);
 						if (res < 0) {
 							LOG("can't open device\n");
-							free(dev_path);
 							break;
 						}
-						good_open = 1;
-
-#ifdef DETACH_KERNEL_DRIVER
-						/* Detach the kernel driver, but only if the
-						   device is managed by the kernel */
-						if (libusb_kernel_driver_active(dev->device_handle, intf_desc->bInterfaceNumber) == 1) {
-							res = libusb_detach_kernel_driver(dev->device_handle, intf_desc->bInterfaceNumber);
-							if (res < 0) {
-								libusb_close(dev->device_handle);
-								LOG("Unable to detach Kernel Driver\n");
-								free(dev_path);
-								good_open = 0;
-								break;
-							}
-							detached_driver = 1;
-						}
-#endif
-
-						res = libusb_claim_interface(dev->device_handle, intf_desc->bInterfaceNumber);
-						if (res < 0) {
-							LOG("can't claim interface %d: %d\n", intf_desc->bInterfaceNumber, res);
-							free(dev_path);
+						good_open = hidapi_initialize_device(dev, conf_desc->bConfigurationValue, intf_desc);
+						if (!good_open)
 							libusb_close(dev->device_handle);
-							good_open = 0;
-							break;
-						}
-
-						/* Initialize XBox 360 controllers */
-						if (is_xbox360(desc.idVendor, intf_desc)) {
-							init_xbox360(dev->device_handle, desc.idVendor, desc.idProduct, conf_desc);
-						}
-
-						/* Initialize XBox One controllers */
-						if (is_xboxone(desc.idVendor, intf_desc)) {
-							init_xboxone(dev->device_handle, desc.idVendor, desc.idProduct, conf_desc);
-						}
-
-						/* Store off the string descriptor indexes */
-						dev->manufacturer_index = desc.iManufacturer;
-						dev->product_index      = desc.iProduct;
-						dev->serial_index       = desc.iSerialNumber;
-
-						/* Store off the interface number */
-						dev->interface = intf_desc->bInterfaceNumber;
-						dev->detached_driver = detached_driver;
-
-						/* Find the INPUT and OUTPUT endpoints. An
-						   OUTPUT endpoint is not required. */
-						for (i = 0; i < intf_desc->bNumEndpoints; i++) {
-							const struct libusb_endpoint_descriptor *ep
-								= &intf_desc->endpoint[i];
-
-							/* Determine the type and direction of this
-							   endpoint. */
-							int is_interrupt =
-								(ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK)
-							      == LIBUSB_TRANSFER_TYPE_INTERRUPT;
-							int is_output =
-								(ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
-							      == LIBUSB_ENDPOINT_OUT;
-							int is_input =
-								(ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)
-							      == LIBUSB_ENDPOINT_IN;
-
-							/* Decide whether to use it for input or output. */
-							if (dev->input_endpoint == 0 &&
-							    is_interrupt && is_input) {
-								/* Use this endpoint for INPUT */
-								dev->input_endpoint = ep->bEndpointAddress;
-								dev->input_ep_max_packet_size = ep->wMaxPacketSize;
-							}
-							if (dev->output_endpoint == 0 &&
-							    is_interrupt && is_output) {
-								/* Use this endpoint for OUTPUT */
-								dev->output_endpoint = ep->bEndpointAddress;
-							}
-						}
-
-						calculate_device_quirks(dev, desc.idVendor, desc.idProduct);
-
-						dev->thread = SDL_CreateThreadInternal(read_thread, "libusb", 0, dev);
-
-						/* Wait here for the read thread to be initialized. */
-						SDL_WaitThreadBarrier(&dev->barrier);
-
 					}
-					free(dev_path);
 				}
 			}
 		}
 		libusb_free_config_descriptor(conf_desc);
-
 	}
 
 	libusb_free_device_list(devs, 1);
@@ -1364,20 +1198,100 @@
 }
 
 
+HID_API_EXPORT hid_device * HID_API_CALL hid_libusb_wrap_sys_device(intptr_t sys_dev, int interface_num)
+{
+/* 0x01000107 is a LIBUSB_API_VERSION for 1.0.23 - version when libusb_wrap_sys_device was introduced */
+#if (!defined(HIDAPI_TARGET_LIBUSB_API_VERSION) || HIDAPI_TARGET_LIBUSB_API_VERSION >= 0x01000107) && (LIBUSB_API_VERSION >= 0x01000107)
+	hid_device *dev = NULL;
+	struct libusb_config_descriptor *conf_desc = NULL;
+	const struct libusb_interface_descriptor *selected_intf_desc = NULL;
+	int res = 0;
+	int j = 0, k = 0;
+
+	if(hid_init() < 0)
+		return NULL;
+
+	dev = new_hid_device();
+
+	res = libusb_wrap_sys_device(usb_context, sys_dev, &dev->device_handle);
+	if (res < 0) {
+		LOG("libusb_wrap_sys_device failed: %d %s\n", res, libusb_error_name(res));
+		goto err;
+	}
+
+	res = libusb_get_active_config_descriptor(libusb_get_device(dev->device_handle), &conf_desc);
+	if (res < 0)
+		libusb_get_config_descriptor(libusb_get_device(dev->device_handle), 0, &conf_desc);
+
+	if (!conf_desc) {
+		LOG("Failed to get configuration descriptor: %d %s\n", res, libusb_error_name(res));
+		goto err;
+	}
+
+	/* find matching HID interface */
+	for (j = 0; j < conf_desc->bNumInterfaces && !selected_intf_desc; j++) {
+		const struct libusb_interface *intf = &conf_desc->interface[j];
+		for (k = 0; k < intf->num_altsetting; k++) {
+			const struct libusb_interface_descriptor *intf_desc = &intf->altsetting[k];
+			if (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) {
+				if (interface_num < 0 || interface_num == intf_desc->bInterfaceNumber) {
+					selected_intf_desc = intf_desc;
+					break;
+				}
+			}
+		}
+	}
+
+	if (!selected_intf_desc) {
+		if (interface_num < 0) {
+			LOG("Sys USB device doesn't contain a HID interface\n");
+		}
+		else {
+			LOG("Sys USB device doesn't contain a HID interface with number %d\n", interface_num);
+		}
+		goto err;
+	}
+
+	if (!hidapi_initialize_device(dev, conf_desc->bConfigurationValue, selected_intf_desc))
+		goto err;
+
+	return dev;
+
+err:
+	if (conf_desc)
+		libusb_free_config_descriptor(conf_desc);
+	if (dev->device_handle)
+		libusb_close(dev->device_handle);
+	free_hid_device(dev);
+#else
+	(void)sys_dev;
+	(void)interface_num;
+	LOG("libusb_wrap_sys_device is not available\n");
+#endif
+	return NULL;
+}
+
+
 int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
 {
 	int res;
+	int report_number;
+	int skipped_report_id = 0;
 
-	if (dev->output_endpoint <= 0 || dev->no_output_reports_on_intr_ep) {
-		int report_number = data[0];
-		int skipped_report_id = 0;
+	if (!data || (length ==0)) {
+		return -1;
+	}
 
-		if (report_number == 0x0 || dev->skip_output_report_id) {
-			data++;
-			length--;
-			skipped_report_id = 1;
-		}
+	report_number = data[0];
 
+	if (report_number == 0x0) {
+		data++;
+		length--;
+		skipped_report_id = 1;
+	}
+
+
+	if (dev->output_endpoint <= 0) {
 		/* No interrupt out endpoint. Use the Control Endpoint */
 		res = libusb_control_transfer(dev->device_handle,
 			LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT,
@@ -1407,6 +1321,9 @@
 		if (res < 0)
 			return -1;
 
+		if (skipped_report_id)
+			actual_length++;
+
 		return actual_length;
 	}
 }
@@ -1419,7 +1336,7 @@
 	   return buffer (data), and delete the liked list item. */
 	struct input_report *rpt = dev->input_reports;
 	size_t len = (length < rpt->len)? length: rpt->len;
-	if (data && len > 0)
+	if (len > 0)
 		memcpy(data, rpt->data, len);
 	dev->input_reports = rpt->next;
 	free(rpt->data);
@@ -1427,13 +1344,12 @@
 	return len;
 }
 
-#if 0 /* TODO: pthread_cleanup SDL? */
 static void cleanup_mutex(void *param)
 {
-	hid_device *dev = (hid_device *)param;
-	SDL_UnlockMutex(dev->mutex);
+	hid_device *dev = param;
+	pthread_mutex_unlock(&dev->mutex);
 }
-#endif
+
 
 int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
 {
@@ -1443,10 +1359,12 @@
 	LOG("transferred: %d\n", transferred);
 	return transferred;
 #endif
-	int bytes_read;
+	/* by initialising this variable right here, GCC gives a compilation warning/error: */
+	/* error: variable ‘bytes_read’ might be clobbered by ‘longjmp’ or ‘vfork’ [-Werror=clobbered] */
+	int bytes_read; /* = -1; */
 
-	SDL_LockMutex(dev->mutex);
-	/* TODO: pthread_cleanup SDL? */
+	pthread_mutex_lock(&dev->mutex);
+	pthread_cleanup_push(&cleanup_mutex, dev);
 
 	bytes_read = -1;
 
@@ -1467,7 +1385,7 @@
 	if (milliseconds == -1) {
 		/* Blocking */
 		while (!dev->input_reports && !dev->shutdown_thread) {
-			SDL_WaitCondition(dev->condition, dev->mutex);
+			pthread_cond_wait(&dev->condition, &dev->mutex);
 		}
 		if (dev->input_reports) {
 			bytes_read = return_data(dev, data, length);
@@ -1476,9 +1394,17 @@
 	else if (milliseconds > 0) {
 		/* Non-blocking, but called with timeout. */
 		int res;
+		struct timespec ts;
+		clock_gettime(CLOCK_REALTIME, &ts);
+		ts.tv_sec += milliseconds / 1000;
+		ts.tv_nsec += (milliseconds % 1000) * 1000000;
+		if (ts.tv_nsec >= 1000000000L) {
+			ts.tv_sec++;
+			ts.tv_nsec -= 1000000000L;
+		}
 
 		while (!dev->input_reports && !dev->shutdown_thread) {
-			res = SDL_WaitConditionTimeout(dev->condition, dev->mutex, milliseconds);
+			res = pthread_cond_timedwait(&dev->condition, &dev->mutex, &ts);
 			if (res == 0) {
 				if (dev->input_reports) {
 					bytes_read = return_data(dev, data, length);
@@ -1489,7 +1415,7 @@
 				   or the read thread was shutdown. Run the
 				   loop again (ie: don't break). */
 			}
-			else if (res == SDL_MUTEX_TIMEDOUT) {
+			else if (res == ETIMEDOUT) {
 				/* Timed out. */
 				bytes_read = 0;
 				break;
@@ -1507,8 +1433,8 @@
 	}
 
 ret:
-	SDL_UnlockMutex(dev->mutex);
-	/* TODO: pthread_cleanup SDL? */
+	pthread_mutex_unlock(&dev->mutex);
+	pthread_cleanup_pop(0);
 
 	return bytes_read;
 }
@@ -1586,11 +1512,38 @@
 	return res;
 }
 
+int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length)
+{
+	int res = -1;
+	int skipped_report_id = 0;
+	int report_number = data[0];
+
+	if (report_number == 0x0) {
+		/* Offset the return buffer by 1, so that the report ID
+		   will remain in byte 0. */
+		data++;
+		length--;
+		skipped_report_id = 1;
+	}
+	res = libusb_control_transfer(dev->device_handle,
+		LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN,
+		0x01/*HID get_report*/,
+		(1/*HID Input*/ << 8) | report_number,
+		dev->interface,
+		(unsigned char *)data, length,
+		1000/*timeout millis*/);
+
+	if (res < 0)
+		return -1;
+
+	if (skipped_report_id)
+		res++;
+
+	return res;
+}
 
 void HID_API_EXPORT hid_close(hid_device *dev)
 {
-	int status;
-
 	if (!dev)
 		return;
 
@@ -1599,7 +1552,7 @@
 	libusb_cancel_transfer(dev->transfer);
 
 	/* Wait for read_thread() to end. */
-	SDL_WaitThread(dev->thread, &status);
+	pthread_join(dev->thread, NULL);
 
 	/* Clean up the Transfer objects allocated in read_thread(). */
 	free(dev->transfer->buffer);
@@ -1609,12 +1562,12 @@
 	/* release the interface */
 	libusb_release_interface(dev->device_handle, dev->interface);
 
+	/* reattach the kernel driver if it was detached */
 #ifdef DETACH_KERNEL_DRIVER
-	/* Re-attach kernel driver if necessary. */
-	if (dev->detached_driver) {
+	if (dev->is_driver_detached) {
 		int res = libusb_attach_kernel_driver(dev->device_handle, dev->interface);
 		if (res < 0)
-			LOG("Couldn't re-attach kernel driver.\n");
+			LOG("Failed to reattach the driver to kernel.\n");
 	}
 #endif
 
@@ -1622,11 +1575,11 @@
 	libusb_close(dev->device_handle);
 
 	/* Clear out the queue of received reports. */
-	SDL_LockMutex(dev->mutex);
+	pthread_mutex_lock(&dev->mutex);
 	while (dev->input_reports) {
 		return_data(dev, NULL, 0);
 	}
-	SDL_UnlockMutex(dev->mutex);
+	pthread_mutex_unlock(&dev->mutex);
 
 	free_hid_device(dev);
 }
@@ -1647,6 +1600,23 @@
 	return hid_get_indexed_string(dev, dev->serial_index, string, maxlen);
 }
 
+HID_API_EXPORT struct hid_device_info *HID_API_CALL hid_get_device_info(hid_device *dev) {
+	if (!dev->device_info) {
+		struct libusb_device_descriptor desc;
+		libusb_device *usb_device = libusb_get_device(dev->device_handle);
+		libusb_get_device_descriptor(usb_device, &desc);
+
+		dev->device_info = create_device_info_for_device(usb_device, dev->device_handle, &desc, dev->config_number, dev->interface);
+		// device error already set by create_device_info_for_device, if any
+
+		if (dev->device_info) {
+			fill_device_info_usage(dev->device_info, dev->device_handle, dev->interface, dev->report_descriptor_size);
+		}
+	}
+
+	return dev->device_info;
+}
+
 int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
 {
 	wchar_t *str;
@@ -1663,9 +1633,16 @@
 }
 
 
+int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size)
+{
+	return hid_get_report_descriptor_libusb(dev->device_handle, dev->interface, dev->report_descriptor_size, buf, buf_size);
+}
+
+
 HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)
 {
-	return NULL;
+	(void)dev;
+	return L"hid_error is not implemented yet";
 }
 
 
@@ -1754,7 +1731,7 @@
 	LANG("Lithuanian", "lt", 0x0427),
 	LANG("F.Y.R.O. Macedonia", "mk", 0x042F),
 	LANG("Malay - Malaysia", "ms_my", 0x043E),
-	LANG("Malay ??? Brunei", "ms_bn", 0x083E),
+	LANG("Malay – Brunei", "ms_bn", 0x083E),
 	LANG("Maltese", "mt", 0x043A),
 	LANG("Marathi", "mr", 0x044E),
 	LANG("Norwegian - Bokml", "no_no", 0x0414),
@@ -1805,7 +1782,7 @@
 	LANG("Ukrainian", "uk", 0x0422),
 	LANG("Urdu", "ur", 0x0420),
 	LANG("Uzbek - Cyrillic", "uz_uz", 0x0843),
-	LANG("Uzbek ??? Latin", "uz_uz", 0x0443),
+	LANG("Uzbek – Latin", "uz_uz", 0x0443),
 	LANG("Vietnamese", "vi", 0x042A),
 	LANG("Xhosa", "xh", 0x0434),
 	LANG("Yiddish", "yi", 0x043D),
@@ -1815,15 +1792,13 @@
 
 uint16_t get_usb_code_for_current_locale(void)
 {
-	char *locale = NULL;
+	char *locale;
 	char search_string[64];
 	char *ptr;
 	struct lang_map_entry *lang;
 
 	/* Get the current locale. */
-#ifdef HAVE_SETLOCALE
 	locale = setlocale(0, NULL);
-#endif
 	if (!locale)
 		return 0x0;
 
@@ -1878,10 +1853,6 @@
 	return 0x0;
 }
 
-#if defined(__cplusplus) && !defined(NAMESPACE)
-}
-#endif
-
-#ifdef NAMESPACE
+#ifdef __cplusplus
 }
 #endif
diff --git a/src/hidapi/libusb/hidapi_libusb.h b/src/hidapi/libusb/hidapi_libusb.h
new file mode 100644
index 0000000..2920768
--- /dev/null
+++ b/src/hidapi/libusb/hidapi_libusb.h
@@ -0,0 +1,56 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ libusb/hidapi Team
+
+ Copyright 2021, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+        https://github.com/libusb/hidapi .
+********************************************************/
+
+/** @file
+ * @defgroup API hidapi API
+
+ * Since version 0.11.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 11, 0).
+ */
+
+#ifndef HIDAPI_LIBUSB_H__
+#define HIDAPI_LIBUSB_H__
+
+#include <stdint.h>
+
+#include "hidapi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+		/** @brief Open a HID device using libusb_wrap_sys_device.
+			See https://libusb.sourceforge.io/api-1.0/group__libusb__dev.html#ga98f783e115ceff4eaf88a60e6439563c,
+			for details on libusb_wrap_sys_device.
+
+			@ingroup API
+			@param sys_dev Platform-specific file descriptor that can be recognised by libusb.
+			@param interface_num USB interface number of the device to be used as HID interface.
+			Pass -1 to select first HID interface of the device.
+
+			@returns
+				This function returns a pointer to a #hid_device object on
+				success or NULL on failure.
+		*/
+		HID_API_EXPORT hid_device * HID_API_CALL hid_libusb_wrap_sys_device(intptr_t sys_dev, int interface_num);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/hidapi/libusb/hidusb.cpp b/src/hidapi/libusb/hidusb.cpp
deleted file mode 100644
index 5006306..0000000
--- a/src/hidapi/libusb/hidusb.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-
-#define NAMESPACE HIDUSB
-#include "hid.c"
diff --git a/src/hidapi/linux/.gitignore b/src/hidapi/linux/.gitignore
new file mode 100644
index 0000000..127bf37
--- /dev/null
+++ b/src/hidapi/linux/.gitignore
@@ -0,0 +1,18 @@
+Debug
+Release
+*.exp
+*.ilk
+*.lib
+*.suo
+*.vcproj.*
+*.ncb
+*.suo
+*.dll
+*.pdb
+*.o
+*.so
+hidtest-hidraw
+.deps
+.libs
+*.lo
+*.la
diff --git a/src/hidapi/linux/CMakeLists.txt b/src/hidapi/linux/CMakeLists.txt
new file mode 100644
index 0000000..0970ac3
--- /dev/null
+++ b/src/hidapi/linux/CMakeLists.txt
@@ -0,0 +1,38 @@
+cmake_minimum_required(VERSION 3.6.3 FATAL_ERROR)
+
+add_library(hidapi_hidraw
+    ${HIDAPI_PUBLIC_HEADERS}
+    hid.c
+)
+target_link_libraries(hidapi_hidraw PUBLIC hidapi_include)
+
+find_package(Threads REQUIRED)
+
+include(FindPkgConfig)
+pkg_check_modules(libudev REQUIRED IMPORTED_TARGET libudev)
+
+target_link_libraries(hidapi_hidraw PRIVATE PkgConfig::libudev Threads::Threads)
+
+set_target_properties(hidapi_hidraw
+    PROPERTIES
+        EXPORT_NAME "hidraw"
+        OUTPUT_NAME "hidapi-hidraw"
+        VERSION ${PROJECT_VERSION}
+        SOVERSION ${PROJECT_VERSION_MAJOR}
+        PUBLIC_HEADER "${HIDAPI_PUBLIC_HEADERS}"
+)
+
+# compatibility with find_package()
+add_library(hidapi::hidraw ALIAS hidapi_hidraw)
+# compatibility with raw library link
+add_library(hidapi-hidraw ALIAS hidapi_hidraw)
+
+if(HIDAPI_INSTALL_TARGETS)
+    install(TARGETS hidapi_hidraw EXPORT hidapi
+        LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+        ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+        PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/hidapi"
+    )
+endif()
+
+hidapi_configure_pc("${PROJECT_ROOT}/pc/hidapi-hidraw.pc.in")
diff --git a/src/hidapi/linux/Makefile-manual b/src/hidapi/linux/Makefile-manual
index 04ce1de..81d28cf 100644
--- a/src/hidapi/linux/Makefile-manual
+++ b/src/hidapi/linux/Makefile-manual
@@ -13,23 +13,19 @@
 CC       ?= gcc
 CFLAGS   ?= -Wall -g -fpic
 
-CXX      ?= g++
-CXXFLAGS ?= -Wall -g -fpic
-
 LDFLAGS  ?= -Wall -g
 
 
-COBJS     = hid.o
-CPPOBJS   = ../hidtest/hidtest.o
-OBJS      = $(COBJS) $(CPPOBJS)
+COBJS     = hid.o ../hidtest/test.o
+OBJS      = $(COBJS)
 LIBS_UDEV = `pkg-config libudev --libs` -lrt
 LIBS      = $(LIBS_UDEV)
 INCLUDES ?= -I../hidapi `pkg-config libusb-1.0 --cflags`
 
 
 # Console Test Program
-hidtest-hidraw: $(COBJS) $(CPPOBJS)
-	$(CXX) $(LDFLAGS) $^ $(LIBS_UDEV) -o $@
+hidtest-hidraw: $(COBJS)
+	$(CC) $(LDFLAGS) $^ $(LIBS_UDEV) -o $@
 
 # Shared Libs
 libhidapi-hidraw.so: $(COBJS)
@@ -39,11 +35,8 @@
 $(COBJS): %.o: %.c
 	$(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@
 
-$(CPPOBJS): %.o: %.cpp
-	$(CXX) $(CXXFLAGS) -c $(INCLUDES) $< -o $@
-
 
 clean:
-	rm -f $(OBJS) hidtest-hidraw libhidapi-hidraw.so ../hidtest/hidtest.o
+	rm -f $(OBJS) hidtest-hidraw libhidapi-hidraw.so $(COBJS)
 
 .PHONY: clean libs
diff --git a/src/hidapi/linux/README.txt b/src/hidapi/linux/README.txt
deleted file mode 100644
index c187590..0000000
--- a/src/hidapi/linux/README.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-
-There are two implementations of HIDAPI for Linux. One (linux/hid.c) uses the
-Linux hidraw driver, and the other (libusb/hid.c) uses libusb. Which one you
-use depends on your application. Complete functionality of the hidraw
-version depends on patches to the Linux kernel which are not currently in
-the mainline. These patches have to do with sending and receiving feature
-reports. The libusb implementation uses libusb to talk directly to the
-device, bypassing any Linux HID driver. The disadvantage of the libusb
-version is that it will only work with USB devices, while the hidraw
-implementation will work with Bluetooth devices as well.
-
-To use HIDAPI, simply drop either linux/hid.c or libusb/hid.c into your
-application and build using the build parameters in the Makefile.
-
-
-Libusb Implementation notes
-----------------------------
-For the libusb implementation, libusb-1.0 must be installed. Libusb 1.0 is
-different than the legacy libusb 0.1 which is installed on many systems. To
-install libusb-1.0 on Ubuntu and other Debian-based systems, run:
-	sudo apt-get install libusb-1.0-0-dev
-
-
-Hidraw Implementation notes
-----------------------------
-For the hidraw implementation, libudev headers and libraries are required to
-build hidapi programs.  To install libudev libraries on Ubuntu,
-and other Debian-based systems, run:
-	sudo apt-get install libudev-dev
-
-On Redhat-based systems, run the following as root:
-	yum install libudev-devel
-
-Unfortunately, the hidraw driver, which the linux version of hidapi is based
-on, contains bugs in kernel versions < 2.6.36, which the client application
-should be aware of.
-
-Bugs (hidraw implementation only):
------------------------------------
-On Kernel versions < 2.6.34, if your device uses numbered reports, an extra
-byte will be returned at the beginning of all reports returned from read()
-for hidraw devices. This is worked around in the library. No action should be
-necessary in the client library.
-
-On Kernel versions < 2.6.35, reports will only be sent using a Set_Report
-transfer on the CONTROL endpoint. No data will ever be sent on an Interrupt
-Out endpoint if one exists. This is fixed in 2.6.35. In 2.6.35, OUTPUT
-reports will be sent to the device on the first INTERRUPT OUT endpoint if it
-exists; If it does not exist, OUTPUT reports will be sent on the CONTROL
-endpoint.
-
-On Kernel versions < 2.6.36, add an extra byte containing the report number
-to sent reports if numbered reports are used, and the device does not
-contain an INTERRPUT OUT endpoint for OUTPUT transfers.  For example, if
-your device uses numbered reports and wants to send {0x2 0xff 0xff 0xff} to
-the device (0x2 is the report number), you must send {0x2 0x2 0xff 0xff
-0xff}. If your device has the optional Interrupt OUT endpoint, this does not
-apply (but really on 2.6.35 only, because 2.6.34 won't use the interrupt
-out endpoint).
diff --git a/src/hidapi/linux/hid.c b/src/hidapi/linux/hid.c
index ee8ccef..a499f04 100644
--- a/src/hidapi/linux/hid.c
+++ b/src/hidapi/linux/hid.c
@@ -5,10 +5,9 @@
  Alan Ott
  Signal 11 Software
 
- 8/22/2009
- Linux Version - 6/2/2009
+ libusb/hidapi Team
 
- Copyright 2009, All Rights Reserved.
+ Copyright 2022, All Rights Reserved.
 
  At the discretion of the user of this library,
  this software may be licensed under the terms of the
@@ -20,12 +19,6 @@
  code repository located at:
         https://github.com/libusb/hidapi .
 ********************************************************/
-#include "SDL_internal.h"
-
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE /* needed for wcsdup() before glibc 2.10 */
-#endif
 
 /* C */
 #include <stdio.h>
@@ -49,15 +42,15 @@
 #include <linux/input.h>
 #include <libudev.h>
 
-#include "../hidapi/hidapi.h"
+#include "hidapi.h"
 
-#ifdef NAMESPACE
-namespace NAMESPACE
-{
-#endif
-
-/* Definitions from linux/hidraw.h. Since these are new, some distros
-   may not have header files which contain them. */
+#ifdef HIDAPI_ALLOW_BUILD_WORKAROUND_KERNEL_2_6_39
+/* This definitions first appeared in Linux Kernel 2.6.39 in linux/hidraw.h.
+    hidapi doesn't support kernels older than that,
+    so we don't define macros below explicitly, to fail builds on old kernels.
+    For those who really need this as a workaround (e.g. to be able to build on old build machines),
+    can workaround by defining the macro above.
+*/
 #ifndef HIDIOCSFEATURE
 #define HIDIOCSFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
 #endif
@@ -65,60 +58,43 @@
 #define HIDIOCGFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
 #endif
 
-/* USB HID device property names */
-const char *device_string_names[] = {
-	"manufacturer",
-	"product",
-	"serial",
-};
+#endif
 
-/* Symbolic names for the properties above */
-enum device_string_id {
-	DEVICE_STRING_MANUFACTURER,
-	DEVICE_STRING_PRODUCT,
-	DEVICE_STRING_SERIAL,
 
-	DEVICE_STRING_COUNT,
-};
+// HIDIOCGINPUT is not defined in Linux kernel headers < 5.11.
+// This definition is from hidraw.h in Linux >= 5.11.
+// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f43d3870cafa2a0f3854c1819c8385733db8f9ae
+#ifndef HIDIOCGINPUT
+#define HIDIOCGINPUT(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x0A, len)
+#endif
 
 struct hid_device_ {
 	int device_handle;
 	int blocking;
-	int uses_numbered_reports;
-	int needs_ble_hack;
+	wchar_t *last_error_str;
+	struct hid_device_info* device_info;
 };
 
+static struct hid_api_version api_version = {
+	.major = HID_API_VERSION_MAJOR,
+	.minor = HID_API_VERSION_MINOR,
+	.patch = HID_API_VERSION_PATCH
+};
 
-static __u32 kernel_version = 0;
+static wchar_t *last_global_error_str = NULL;
 
-static __u32 detect_kernel_version(void)
-{
-	struct utsname name;
-	int major, minor, release;
-	int ret;
-
-	uname(&name);
-	ret = sscanf(name.release, "%d.%d.%d", &major, &minor, &release);
-	if (ret == 3) {
-		return KERNEL_VERSION(major, minor, release);
-	}
-
-	ret = sscanf(name.release, "%d.%d", &major, &minor);
-	if (ret == 2) {
-		return KERNEL_VERSION(major, minor, 0);
-	}
-
-	printf("Couldn't determine kernel version from version string \"%s\"\n", name.release);
-	return 0;
-}
 
 static hid_device *new_hid_device(void)
 {
-	hid_device *dev = (hid_device *)calloc(1, sizeof(hid_device));
+	hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
+	if (dev == NULL) {
+		return NULL;
+	}
+
 	dev->device_handle = -1;
 	dev->blocking = 1;
-	dev->uses_numbered_reports = 0;
-	dev->needs_ble_hack = 0;
+	dev->last_error_str = NULL;
+	dev->device_info = NULL;
 
 	return dev;
 }
@@ -134,7 +110,11 @@
 		if ((size_t) -1 == wlen) {
 			return wcsdup(L"");
 		}
-		ret = (wchar_t *)calloc(wlen+1, sizeof(wchar_t));
+		ret = (wchar_t*) calloc(wlen+1, sizeof(wchar_t));
+		if (ret == NULL) {
+			/* as much as we can do at this point */
+			return NULL;
+		}
 		mbstowcs(ret, utf8, wlen+1);
 		ret[wlen] = 0x0000;
 	}
@@ -142,6 +122,64 @@
 	return ret;
 }
 
+
+/* Makes a copy of the given error message (and decoded according to the
+ * currently locale) into the wide string pointer pointed by error_str.
+ * The last stored error string is freed.
+ * Use register_error_str(NULL) to free the error message completely. */
+static void register_error_str(wchar_t **error_str, const char *msg)
+{
+	free(*error_str);
+	*error_str = utf8_to_wchar_t(msg);
+}
+
+/* Semilar to register_error_str, but allows passing a format string with va_list args into this function. */
+static void register_error_str_vformat(wchar_t **error_str, const char *format, va_list args)
+{
+	char msg[256];
+	vsnprintf(msg, sizeof(msg), format, args);
+
+	register_error_str(error_str, msg);
+}
+
+/* Set the last global error to be reported by hid_error(NULL).
+ * The given error message will be copied (and decoded according to the
+ * currently locale, so do not pass in string constants).
+ * The last stored global error message is freed.
+ * Use register_global_error(NULL) to indicate "no error". */
+static void register_global_error(const char *msg)
+{
+	register_error_str(&last_global_error_str, msg);
+}
+
+/* Similar to register_global_error, but allows passing a format string into this function. */
+static void register_global_error_format(const char *format, ...)
+{
+	va_list args;
+	va_start(args, format);
+	register_error_str_vformat(&last_global_error_str, format, args);
+	va_end(args);
+}
+
+/* Set the last error for a device to be reported by hid_error(dev).
+ * The given error message will be copied (and decoded according to the
+ * currently locale, so do not pass in string constants).
+ * The last stored device error message is freed.
+ * Use register_device_error(dev, NULL) to indicate "no error". */
+static void register_device_error(hid_device *dev, const char *msg)
+{
+	register_error_str(&dev->last_error_str, msg);
+}
+
+/* Similar to register_device_error, but you can pass a format string into this function. */
+static void register_device_error_format(hid_device *dev, const char *format, ...)
+{
+	va_list args;
+	va_start(args, format);
+	register_error_str_vformat(&dev->last_error_str, format, args);
+	va_end(args);
+}
+
 /* Get an attribute value from a udev_device and return it as a whar_t
    string. The returned string must be freed with free() when done.*/
 static wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name)
@@ -149,78 +187,337 @@
 	return utf8_to_wchar_t(udev_device_get_sysattr_value(dev, udev_name));
 }
 
-/* uses_numbered_reports() returns 1 if report_descriptor describes a device
-   which contains numbered reports. */
-static int uses_numbered_reports(__u8 *report_descriptor, __u32 size) {
-	unsigned int i = 0;
+/*
+ * Gets the size of the HID item at the given position
+ * Returns 1 if successful, 0 if an invalid key
+ * Sets data_len and key_size when successful
+ */
+static int get_hid_item_size(__u8 *report_descriptor, unsigned int pos, __u32 size, int *data_len, int *key_size)
+{
+	int key = report_descriptor[pos];
 	int size_code;
-	int data_len, key_size;
 
-	while (i < size) {
-		int key = report_descriptor[i];
-
-		/* Check for the Report ID key */
-		if (key == 0x85/*Report ID*/) {
-			/* This device has a Report ID, which means it uses
-			   numbered reports. */
+	/*
+	 * This is a Long Item. The next byte contains the
+	 * length of the data section (value) for this key.
+	 * See the HID specification, version 1.11, section
+	 * 6.2.2.3, titled "Long Items."
+	 */
+	if ((key & 0xf0) == 0xf0) {
+		if (pos + 1 < size)
+		{
+			*data_len = report_descriptor[pos + 1];
+			*key_size = 3;
 			return 1;
 		}
-
-		//printf("key: %02hhx\n", key);
-
-		if ((key & 0xf0) == 0xf0) {
-			/* This is a Long Item. The next byte contains the
-			   length of the data section (value) for this key.
-			   See the HID specification, version 1.11, section
-			   6.2.2.3, titled "Long Items." */
-			if (i+1 < size)
-				data_len = report_descriptor[i+1];
-			else
-				data_len = 0; /* malformed report */
-			key_size = 3;
-		}
-		else {
-			/* This is a Short Item. The bottom two bits of the
-			   key contain the size code for the data section
-			   (value) for this key.  Refer to the HID
-			   specification, version 1.11, section 6.2.2.2,
-			   titled "Short Items." */
-			size_code = key & 0x3;
-			switch (size_code) {
-			case 0:
-			case 1:
-			case 2:
-				data_len = size_code;
-				break;
-			case 3:
-				data_len = 4;
-				break;
-			default:
-				/* Can't ever happen since size_code is & 0x3 */
-				data_len = 0;
-				break;
-			}
-			key_size = 1;
-		}
-
-		/* Skip over this key and it's associated data */
-		i += data_len + key_size;
+		*data_len = 0; /* malformed report */
+		*key_size = 0;
 	}
 
-	/* Didn't find a Report ID key. Device doesn't use numbered reports. */
+	/*
+	 * This is a Short Item. The bottom two bits of the
+	 * key contain the size code for the data section
+	 * (value) for this key. Refer to the HID
+	 * specification, version 1.11, section 6.2.2.2,
+	 * titled "Short Items."
+	 */
+	size_code = key & 0x3;
+	switch (size_code) {
+	case 0:
+	case 1:
+	case 2:
+		*data_len = size_code;
+		*key_size = 1;
+		return 1;
+	case 3:
+		*data_len = 4;
+		*key_size = 1;
+		return 1;
+	default:
+		/* Can't ever happen since size_code is & 0x3 */
+		*data_len = 0;
+		*key_size = 0;
+		break;
+	};
+
+	/* malformed report */
 	return 0;
 }
 
 /*
+ * Get bytes from a HID Report Descriptor.
+ * Only call with a num_bytes of 0, 1, 2, or 4.
+ */
+static __u32 get_hid_report_bytes(__u8 *rpt, size_t len, size_t num_bytes, size_t cur)
+{
+	/* Return if there aren't enough bytes. */
+	if (cur + num_bytes >= len)
+		return 0;
+
+	if (num_bytes == 0)
+		return 0;
+	else if (num_bytes == 1)
+		return rpt[cur + 1];
+	else if (num_bytes == 2)
+		return (rpt[cur + 2] * 256 + rpt[cur + 1]);
+	else if (num_bytes == 4)
+		return (
+			rpt[cur + 4] * 0x01000000 +
+			rpt[cur + 3] * 0x00010000 +
+			rpt[cur + 2] * 0x00000100 +
+			rpt[cur + 1] * 0x00000001
+		);
+	else
+		return 0;
+}
+
+/*
+ * Retrieves the device's Usage Page and Usage from the report descriptor.
+ * The algorithm returns the current Usage Page/Usage pair whenever a new
+ * Collection is found and a Usage Local Item is currently in scope.
+ * Usage Local Items are consumed by each Main Item (See. 6.2.2.8).
+ * The algorithm should give similar results as Apple's:
+ *   https://developer.apple.com/documentation/iokit/kiohiddeviceusagepairskey?language=objc
+ * Physical Collections are also matched (macOS does the same).
+ *
+ * This function can be called repeatedly until it returns non-0
+ * Usage is found. pos is the starting point (initially 0) and will be updated
+ * to the next search position.
+ *
+ * The return value is 0 when a pair is found.
+ * 1 when finished processing descriptor.
+ * -1 on a malformed report.
+ */
+static int get_next_hid_usage(__u8 *report_descriptor, __u32 size, unsigned int *pos, unsigned short *usage_page, unsigned short *usage)
+{
+	int data_len, key_size;
+	int initial = *pos == 0; /* Used to handle case where no top-level application collection is defined */
+	int usage_pair_ready = 0;
+
+	/* Usage is a Local Item, it must be set before each Main Item (Collection) before a pair is returned */
+	int usage_found = 0;
+
+	while (*pos < size) {
+		int key = report_descriptor[*pos];
+		int key_cmd = key & 0xfc;
+
+		/* Determine data_len and key_size */
+		if (!get_hid_item_size(report_descriptor, *pos, size, &data_len, &key_size))
+			return -1; /* malformed report */
+
+		switch (key_cmd) {
+		case 0x4: /* Usage Page 6.2.2.7 (Global) */
+			*usage_page = get_hid_report_bytes(report_descriptor, size, data_len, *pos);
+			break;
+
+		case 0x8: /* Usage 6.2.2.8 (Local) */
+			*usage = get_hid_report_bytes(report_descriptor, size, data_len, *pos);
+			usage_found = 1;
+			break;
+
+		case 0xa0: /* Collection 6.2.2.4 (Main) */
+			/* A Usage Item (Local) must be found for the pair to be valid */
+			if (usage_found)
+				usage_pair_ready = 1;
+
+			/* Usage is a Local Item, unset it */
+			usage_found = 0;
+			break;
+
+		case 0x80: /* Input 6.2.2.4 (Main) */
+		case 0x90: /* Output 6.2.2.4 (Main) */
+		case 0xb0: /* Feature 6.2.2.4 (Main) */
+		case 0xc0: /* End Collection 6.2.2.4 (Main) */
+			/* Usage is a Local Item, unset it */
+			usage_found = 0;
+			break;
+		}
+
+		/* Skip over this key and its associated data */
+		*pos += data_len + key_size;
+
+		/* Return usage pair */
+		if (usage_pair_ready)
+			return 0;
+	}
+
+	/* If no top-level application collection is found and usage page/usage pair is found, pair is valid
+	   https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/top-level-collections */
+	if (initial && usage_found)
+		return 0; /* success */
+
+	return 1; /* finished processing */
+}
+
+/*
+ * Retrieves the hidraw report descriptor from a file.
+ * When using this form, <sysfs_path>/device/report_descriptor, elevated priviledges are not required.
+ */
+static int get_hid_report_descriptor(const char *rpt_path, struct hidraw_report_descriptor *rpt_desc)
+{
+	int rpt_handle;
+	ssize_t res;
+
+	rpt_handle = open(rpt_path, O_RDONLY | O_CLOEXEC);
+	if (rpt_handle < 0) {
+		register_global_error_format("open failed (%s): %s", rpt_path, strerror(errno));
+		return -1;
+	}
+
+	/*
+	 * Read in the Report Descriptor
+	 * The sysfs file has a maximum size of 4096 (which is the same as HID_MAX_DESCRIPTOR_SIZE) so we should always
+	 * be ok when reading the descriptor.
+	 * In practice if the HID descriptor is any larger I suspect many other things will break.
+	 */
+	memset(rpt_desc, 0x0, sizeof(*rpt_desc));
+	res = read(rpt_handle, rpt_desc->value, HID_MAX_DESCRIPTOR_SIZE);
+	if (res < 0) {
+		register_global_error_format("read failed (%s): %s", rpt_path, strerror(errno));
+	}
+	rpt_desc->size = (__u32) res;
+
+	close(rpt_handle);
+	return (int) res;
+}
+
+/* return size of the descriptor, or -1 on failure */
+static int get_hid_report_descriptor_from_sysfs(const char *sysfs_path, struct hidraw_report_descriptor *rpt_desc)
+{
+	int res = -1;
+	/* Construct <sysfs_path>/device/report_descriptor */
+	size_t rpt_path_len = strlen(sysfs_path) + 25 + 1;
+	char* rpt_path = (char*) calloc(1, rpt_path_len);
+	snprintf(rpt_path, rpt_path_len, "%s/device/report_descriptor", sysfs_path);
+
+	res = get_hid_report_descriptor(rpt_path, rpt_desc);
+	free(rpt_path);
+
+	return res;
+}
+
+/* return non-zero if successfully parsed */
+static int parse_hid_vid_pid_from_uevent(const char *uevent, unsigned *bus_type, unsigned short *vendor_id, unsigned short *product_id)
+{
+	char tmp[1024];
+	size_t uevent_len = strlen(uevent);
+	if (uevent_len > sizeof(tmp) - 1)
+		uevent_len = sizeof(tmp) - 1;
+	memcpy(tmp, uevent, uevent_len);
+	tmp[uevent_len] = '\0';
+
+	char *saveptr = NULL;
+	char *line;
+	char *key;
+	char *value;
+
+	line = strtok_r(tmp, "\n", &saveptr);
+	while (line != NULL) {
+		/* line: "KEY=value" */
+		key = line;
+		value = strchr(line, '=');
+		if (!value) {
+			goto next_line;
+		}
+		*value = '\0';
+		value++;
+
+		if (strcmp(key, "HID_ID") == 0) {
+			/**
+			 *        type vendor   product
+			 * HID_ID=0003:000005AC:00008242
+			 **/
+			int ret = sscanf(value, "%x:%hx:%hx", bus_type, vendor_id, product_id);
+			if (ret == 3) {
+				return 1;
+			}
+		}
+
+next_line:
+		line = strtok_r(NULL, "\n", &saveptr);
+	}
+
+	register_global_error("Couldn't find/parse HID_ID");
+	return 0;
+}
+
+/* return non-zero if successfully parsed */
+static int parse_hid_vid_pid_from_uevent_path(const char *uevent_path, unsigned *bus_type, unsigned short *vendor_id, unsigned short *product_id)
+{
+	int handle;
+	ssize_t res;
+
+	handle = open(uevent_path, O_RDONLY | O_CLOEXEC);
+	if (handle < 0) {
+		register_global_error_format("open failed (%s): %s", uevent_path, strerror(errno));
+		return 0;
+	}
+
+	char buf[1024];
+	res = read(handle, buf, sizeof(buf) - 1); /* -1 for '\0' at the end */
+	close(handle);
+
+	if (res < 0) {
+		register_global_error_format("read failed (%s): %s", uevent_path, strerror(errno));
+		return 0;
+	}
+
+	buf[res] = '\0';
+	return parse_hid_vid_pid_from_uevent(buf, bus_type, vendor_id, product_id);
+}
+
+/* return non-zero if successfully read/parsed */
+static int parse_hid_vid_pid_from_sysfs(const char *sysfs_path, unsigned *bus_type, unsigned short *vendor_id, unsigned short *product_id)
+{
+	int res = 0;
+	/* Construct <sysfs_path>/device/uevent */
+	size_t uevent_path_len = strlen(sysfs_path) + 14 + 1;
+	char* uevent_path = (char*) calloc(1, uevent_path_len);
+	snprintf(uevent_path, uevent_path_len, "%s/device/uevent", sysfs_path);
+
+	res = parse_hid_vid_pid_from_uevent_path(uevent_path, bus_type, vendor_id, product_id);
+	free(uevent_path);
+
+	return res;
+}
+
+static int get_hid_report_descriptor_from_hidraw(hid_device *dev, struct hidraw_report_descriptor *rpt_desc)
+{
+	int desc_size = 0;
+
+	/* Get Report Descriptor Size */
+	int res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size);
+	if (res < 0) {
+		register_device_error_format(dev, "ioctl(GRDESCSIZE): %s", strerror(errno));
+		return res;
+	}
+
+	/* Get Report Descriptor */
+	memset(rpt_desc, 0x0, sizeof(*rpt_desc));
+	rpt_desc->size = desc_size;
+	res = ioctl(dev->device_handle, HIDIOCGRDESC, rpt_desc);
+	if (res < 0) {
+		register_device_error_format(dev, "ioctl(GRDESC): %s", strerror(errno));
+	}
+
+	return res;
+}
+
+/*
  * The caller is responsible for free()ing the (newly-allocated) character
  * strings pointed to by serial_number_utf8 and product_name_utf8 after use.
  */
-static int
-parse_uevent_info(const char *uevent, unsigned *bus_type,
+static int parse_uevent_info(const char *uevent, unsigned *bus_type,
 	unsigned short *vendor_id, unsigned short *product_id,
 	char **serial_number_utf8, char **product_name_utf8)
 {
-	char *tmp;
+	char tmp[1024];
+	size_t uevent_len = strlen(uevent);
+	if (uevent_len > sizeof(tmp) - 1)
+		uevent_len = sizeof(tmp) - 1;
+	memcpy(tmp, uevent, uevent_len);
+	tmp[uevent_len] = '\0';
+
 	char *saveptr = NULL;
 	char *line;
 	char *key;
@@ -230,15 +527,6 @@
 	int found_serial = 0;
 	int found_name = 0;
 
-	if (!uevent) {
-		return 0;
-	}
-
-	tmp = strdup(uevent);
-	if (!tmp) {
-		return 0;
-	}
-
 	line = strtok_r(tmp, "\n", &saveptr);
 	while (line != NULL) {
 		/* line: "KEY=value" */
@@ -273,170 +561,203 @@
 		line = strtok_r(NULL, "\n", &saveptr);
 	}
 
-	free(tmp);
 	return (found_id && found_name && found_serial);
 }
 
-static int is_BLE(hid_device *dev)
+
+static struct hid_device_info * create_device_info_for_device(struct udev_device *raw_dev)
 {
-	struct udev *udev;
-	struct udev_device *udev_dev, *hid_dev;
-	struct stat s;
-	int ret;
+	struct hid_device_info *root = NULL;
+	struct hid_device_info *cur_dev = NULL;
 
-	/* Create the udev object */
-	udev = udev_new();
-	if (!udev) {
-		printf("Can't create udev\n");
-		return -1;
-	}
-
-	/* Get the dev_t (major/minor numbers) from the file handle. */
-	if (fstat(dev->device_handle, &s) < 0) {
-		udev_unref(udev);
-		return -1;
-	}
-
-	/* Open a udev device from the dev_t. 'c' means character device. */
-	ret = 0;
-	udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev);
-	if (udev_dev) {
-		hid_dev = udev_device_get_parent_with_subsystem_devtype(
-			udev_dev,
-			"hid",
-			NULL);
-		if (hid_dev) {
-			unsigned short dev_vid = 0;
-			unsigned short dev_pid = 0;
-			unsigned bus_type = 0;
-			char *serial_number_utf8 = NULL;
-			char *product_name_utf8 = NULL;
-
-			parse_uevent_info(
-			           udev_device_get_sysattr_value(hid_dev, "uevent"),
-			           &bus_type,
-			           &dev_vid,
-			           &dev_pid,
-			           &serial_number_utf8,
-			           &product_name_utf8);
-			free(serial_number_utf8);
-			free(product_name_utf8);
-
-			if (bus_type == BUS_BLUETOOTH) {
-				/* Right now the Steam Controller is the only BLE device that we send feature reports to */
-				if (dev_vid == 0x28de /* Valve */) {
-					ret = 1;
-				}
-			}
-
-			/* hid_dev doesn't need to be (and can't be) unref'd.
-			   I'm not sure why, but it'll throw double-free() errors. */
-		}
-		udev_device_unref(udev_dev);
-	}
-
-	udev_unref(udev);
-
-	return ret;
-}
-
-static int get_device_string(hid_device *dev, enum device_string_id key, wchar_t *string, size_t maxlen)
-{
-	struct udev *udev;
-	struct udev_device *udev_dev, *parent, *hid_dev;
-	struct stat s;
-	int ret = -1;
+	const char *sysfs_path;
+	const char *dev_path;
+	const char *str;
+	struct udev_device *hid_dev; /* The device's HID udev node. */
+	struct udev_device *usb_dev; /* The device's USB udev node. */
+	struct udev_device *intf_dev; /* The device's interface (in the USB sense). */
+	unsigned short dev_vid;
+	unsigned short dev_pid;
 	char *serial_number_utf8 = NULL;
 	char *product_name_utf8 = NULL;
-	char *tmp;
+	unsigned bus_type;
+	int result;
+	struct hidraw_report_descriptor report_desc;
 
-	/* Create the udev object */
-	udev = udev_new();
-	if (!udev) {
-		printf("Can't create udev\n");
-		return -1;
+	sysfs_path = udev_device_get_syspath(raw_dev);
+	dev_path = udev_device_get_devnode(raw_dev);
+
+	hid_dev = udev_device_get_parent_with_subsystem_devtype(
+		raw_dev,
+		"hid",
+		NULL);
+
+	if (!hid_dev) {
+		/* Unable to find parent hid device. */
+		goto end;
 	}
 
-	/* Get the dev_t (major/minor numbers) from the file handle. */
-	ret = fstat(dev->device_handle, &s);
-	if (-1 == ret) {
-		udev_unref(udev);
-		return ret;
+	result = parse_uevent_info(
+		udev_device_get_sysattr_value(hid_dev, "uevent"),
+		&bus_type,
+		&dev_vid,
+		&dev_pid,
+		&serial_number_utf8,
+		&product_name_utf8);
+
+	if (!result) {
+		/* parse_uevent_info() failed for at least one field. */
+		goto end;
 	}
-	/* Open a udev device from the dev_t. 'c' means character device. */
-	udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev);
-	if (udev_dev) {
-		hid_dev = udev_device_get_parent_with_subsystem_devtype(
-			udev_dev,
-			"hid",
-			NULL);
-		if (hid_dev) {
-			unsigned short dev_vid;
-			unsigned short dev_pid;
-			unsigned bus_type;
-			size_t retm;
 
-			ret = parse_uevent_info(
-			           udev_device_get_sysattr_value(hid_dev, "uevent"),
-			           &bus_type,
-			           &dev_vid,
-			           &dev_pid,
-			           &serial_number_utf8,
-			           &product_name_utf8);
+	/* Filter out unhandled devices right away */
+	switch (bus_type) {
+		case BUS_BLUETOOTH:
+		case BUS_I2C:
+		case BUS_USB:
+		case BUS_SPI:
+			break;
 
-			if (bus_type == BUS_BLUETOOTH) {
-				switch (key) {
-					case DEVICE_STRING_MANUFACTURER:
-						wcsncpy(string, L"", maxlen);
-						ret = 0;
-						break;
-					case DEVICE_STRING_PRODUCT:
-						retm = mbstowcs(string, product_name_utf8, maxlen);
-						ret = (retm == (size_t)-1)? -1: 0;
-						break;
-					case DEVICE_STRING_SERIAL:
-						/* Bluetooth serial numbers are often the bluetooth device address
-						   and we want that with the colons stripped out, which is the correct
-						   serial number for PS4 controllers
-						 */
-						while ((tmp = strchr(serial_number_utf8, ':')) != NULL) {
-							memmove(tmp, tmp+1, strlen(tmp));
-						}
-						retm = mbstowcs(string, serial_number_utf8, maxlen);
-						ret = (retm == (size_t)-1)? -1: 0;
-						break;
-					case DEVICE_STRING_COUNT:
-					default:
-						ret = -1;
-						break;
-				}
+		default:
+			goto end;
+	}
+
+	/* Create the record. */
+	root = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
+	if (!root)
+		goto end;
+
+	cur_dev = root;
+
+	/* Fill out the record */
+	cur_dev->next = NULL;
+	cur_dev->path = dev_path? strdup(dev_path): NULL;
+
+	/* VID/PID */
+	cur_dev->vendor_id = dev_vid;
+	cur_dev->product_id = dev_pid;
+
+	/* Serial Number */
+	cur_dev->serial_number = utf8_to_wchar_t(serial_number_utf8);
+
+	/* Release Number */
+	cur_dev->release_number = 0x0;
+
+	/* Interface Number */
+	cur_dev->interface_number = -1;
+
+	switch (bus_type) {
+		case BUS_USB:
+			/* The device pointed to by raw_dev contains information about
+				the hidraw device. In order to get information about the
+				USB device, get the parent device with the
+				subsystem/devtype pair of "usb"/"usb_device". This will
+				be several levels up the tree, but the function will find
+				it. */
+			usb_dev = udev_device_get_parent_with_subsystem_devtype(
+					raw_dev,
+					"usb",
+					"usb_device");
+
+			/* uhid USB devices
+			 * Since this is a virtual hid interface, no USB information will
+			 * be available. */
+			if (!usb_dev) {
+				/* Manufacturer and Product strings */
+				cur_dev->manufacturer_string = wcsdup(L"");
+				cur_dev->product_string = utf8_to_wchar_t(product_name_utf8);
+				break;
 			}
-			else {
-				/* This is a USB device. Find its parent USB Device node. */
-				parent = udev_device_get_parent_with_subsystem_devtype(
-					   udev_dev,
-					   "usb",
-					   "usb_device");
-				if (parent) {
-					const char *str;
-					const char *key_str = NULL;
 
-					if ((int)key >= 0 && (int)key < DEVICE_STRING_COUNT) {
-						key_str = device_string_names[key];
-					} else {
-						ret = -1;
-						goto end;
-					}
+			cur_dev->manufacturer_string = copy_udev_string(usb_dev, "manufacturer");
+			cur_dev->product_string = copy_udev_string(usb_dev, "product");
 
-					str = udev_device_get_sysattr_value(parent, key_str);
-					if (str) {
-						/* Convert the string from UTF-8 to wchar_t */
-						retm = mbstowcs(string, str, maxlen);
-						ret = (retm == (size_t)-1)? -1: 0;
-						goto end;
-					}
-				}
+			cur_dev->bus_type = HID_API_BUS_USB;
+
+			str = udev_device_get_sysattr_value(usb_dev, "bcdDevice");
+			cur_dev->release_number = (str)? strtol(str, NULL, 16): 0x0;
+
+			/* Get a handle to the interface's udev node. */
+			intf_dev = udev_device_get_parent_with_subsystem_devtype(
+					raw_dev,
+					"usb",
+					"usb_interface");
+			if (intf_dev) {
+				str = udev_device_get_sysattr_value(intf_dev, "bInterfaceNumber");
+				cur_dev->interface_number = (str)? strtol(str, NULL, 16): -1;
 			}
+
+			break;
+
+		case BUS_BLUETOOTH:
+			cur_dev->manufacturer_string = wcsdup(L"");
+			cur_dev->product_string = utf8_to_wchar_t(product_name_utf8);
+
+			cur_dev->bus_type = HID_API_BUS_BLUETOOTH;
+
+			break;
+		case BUS_I2C:
+			cur_dev->manufacturer_string = wcsdup(L"");
+			cur_dev->product_string = utf8_to_wchar_t(product_name_utf8);
+
+			cur_dev->bus_type = HID_API_BUS_I2C;
+
+			break;
+
+		case BUS_SPI:
+			cur_dev->manufacturer_string = wcsdup(L"");
+			cur_dev->product_string = utf8_to_wchar_t(product_name_utf8);
+
+			cur_dev->bus_type = HID_API_BUS_SPI;
+
+			break;
+
+		default:
+			/* Unknown device type - this should never happen, as we
+			 * check for USB and Bluetooth devices above */
+			break;
+	}
+
+	/* Usage Page and Usage */
+	result = get_hid_report_descriptor_from_sysfs(sysfs_path, &report_desc);
+	if (result >= 0) {
+		unsigned short page = 0, usage = 0;
+		unsigned int pos = 0;
+		/*
+		 * Parse the first usage and usage page
+		 * out of the report descriptor.
+		 */
+		if (!get_next_hid_usage(report_desc.value, report_desc.size, &pos, &page, &usage)) {
+			cur_dev->usage_page = page;
+			cur_dev->usage = usage;
+		}
+
+		/*
+		 * Parse any additional usage and usage pages
+		 * out of the report descriptor.
+		 */
+		while (!get_next_hid_usage(report_desc.value, report_desc.size, &pos, &page, &usage)) {
+			/* Create new record for additional usage pairs */
+			struct hid_device_info *tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
+			struct hid_device_info *prev_dev = cur_dev;
+
+			if (!tmp)
+				continue;
+			cur_dev->next = tmp;
+			cur_dev = tmp;
+
+			/* Update fields */
+			cur_dev->path = dev_path? strdup(dev_path): NULL;
+			cur_dev->vendor_id = dev_vid;
+			cur_dev->product_id = dev_pid;
+			cur_dev->serial_number = prev_dev->serial_number? wcsdup(prev_dev->serial_number): NULL;
+			cur_dev->release_number = prev_dev->release_number;
+			cur_dev->interface_number = prev_dev->interface_number;
+			cur_dev->manufacturer_string = prev_dev->manufacturer_string? wcsdup(prev_dev->manufacturer_string): NULL;
+			cur_dev->product_string = prev_dev->product_string? wcsdup(prev_dev->product_string): NULL;
+			cur_dev->usage_page = page;
+			cur_dev->usage = usage;
+			cur_dev->bus_type = prev_dev->bus_type;
 		}
 	}
 
@@ -444,35 +765,82 @@
 	free(serial_number_utf8);
 	free(product_name_utf8);
 
+	return root;
+}
+
+static struct hid_device_info * create_device_info_for_hid_device(hid_device *dev) {
+	struct udev *udev;
+	struct udev_device *udev_dev;
+	struct stat s;
+	int ret = -1;
+	struct hid_device_info *root = NULL;
+
+	register_device_error(dev, NULL);
+
+	/* Get the dev_t (major/minor numbers) from the file handle. */
+	ret = fstat(dev->device_handle, &s);
+	if (-1 == ret) {
+		register_device_error(dev, "Failed to stat device handle");
+		return NULL;
+	}
+
+	/* Create the udev object */
+	udev = udev_new();
+	if (!udev) {
+		register_device_error(dev, "Couldn't create udev context");
+		return NULL;
+	}
+
+	/* Open a udev device from the dev_t. 'c' means character device. */
+	udev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev);
+	if (udev_dev) {
+		root = create_device_info_for_device(udev_dev);
+	}
+
+	if (!root) {
+		/* TODO: have a better error reporting via create_device_info_for_device */
+		register_device_error(dev, "Couldn't create hid_device_info");
+	}
+
 	udev_device_unref(udev_dev);
-	/* parent and hid_dev don't need to be (and can't be) unref'd.
-	   I'm not sure why, but they'll throw double-free() errors. */
 	udev_unref(udev);
 
-	return ret;
+	return root;
+}
+
+HID_API_EXPORT const struct hid_api_version* HID_API_CALL hid_version(void)
+{
+	return &api_version;
+}
+
+HID_API_EXPORT const char* HID_API_CALL hid_version_str(void)
+{
+	return HID_API_VERSION_STR;
 }
 
 int HID_API_EXPORT hid_init(void)
 {
 	const char *locale;
 
+	/* indicate no error */
+	register_global_error(NULL);
+
 	/* Set the locale if it's not set. */
 	locale = setlocale(LC_CTYPE, NULL);
 	if (!locale)
 		setlocale(LC_CTYPE, "");
 
-	kernel_version = detect_kernel_version();
-
 	return 0;
 }
 
 int HID_API_EXPORT hid_exit(void)
 {
-	/* Nothing to do for this in the Linux/hidraw implementation. */
+	/* Free global error message */
+	register_global_error(NULL);
+
 	return 0;
 }
 
-
 struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
 {
 	struct udev *udev;
@@ -481,15 +849,14 @@
 
 	struct hid_device_info *root = NULL; /* return object */
 	struct hid_device_info *cur_dev = NULL;
-	struct hid_device_info *prev_dev = NULL; /* previous device */
-	const char *hint = SDL_GetHint(SDL_HINT_HIDAPI_IGNORE_DEVICES);
 
 	hid_init();
+	/* register_global_error: global error is reset by hid_init */
 
 	/* Create the udev object */
 	udev = udev_new();
 	if (!udev) {
-		printf("Can't create udev\n");
+		register_global_error("Couldn't create udev context");
 		return NULL;
 	}
 
@@ -502,178 +869,62 @@
 	   create a udev_device record for it */
 	udev_list_entry_foreach(dev_list_entry, devices) {
 		const char *sysfs_path;
-		const char *dev_path;
-		const char *str;
+		unsigned short dev_vid = 0;
+		unsigned short dev_pid = 0;
+		unsigned bus_type = 0;
 		struct udev_device *raw_dev; /* The device's hidraw udev node. */
-		struct udev_device *hid_dev; /* The device's HID udev node. */
-		struct udev_device *usb_dev; /* The device's USB udev node. */
-		struct udev_device *intf_dev; /* The device's interface (in the USB sense). */
-		unsigned short dev_vid;
-		unsigned short dev_pid;
-		char *serial_number_utf8 = NULL;
-		char *product_name_utf8 = NULL;
-		unsigned bus_type;
-		int result;
+		struct hid_device_info * tmp;
 
 		/* Get the filename of the /sys entry for the device
 		   and create a udev_device object (dev) representing it */
 		sysfs_path = udev_list_entry_get_name(dev_list_entry);
-		raw_dev = udev_device_new_from_syspath(udev, sysfs_path);
-		dev_path = udev_device_get_devnode(raw_dev);
+		if (!sysfs_path)
+			continue;
 
-		hid_dev = udev_device_get_parent_with_subsystem_devtype(
-			raw_dev,
-			"hid",
-			NULL);
-
-		if (!hid_dev) {
-			/* Unable to find parent hid device. */
-			goto next;
-		}
-
-		result = parse_uevent_info(
-			udev_device_get_sysattr_value(hid_dev, "uevent"),
-			&bus_type,
-			&dev_vid,
-			&dev_pid,
-			&serial_number_utf8,
-			&product_name_utf8);
-
-		if (!result) {
-			/* parse_uevent_info() failed for at least one field. */
-			goto next;
-		}
-
-		if (bus_type != BUS_USB && bus_type != BUS_BLUETOOTH) {
-			/* We only know how to handle USB and BT devices. */
-			goto next;
-		}
-
-		if (access(dev_path, R_OK|W_OK) != 0) {
-			/* We can't open this device, ignore it */
-			goto next;
-		}
-
-		/* See if there are any devices we should skip in enumeration */
-		if (hint) {
-			char vendor_match[16], product_match[16];
-			SDL_snprintf(vendor_match, sizeof(vendor_match), "0x%.4x/0x0000", dev_vid);
-			SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", dev_vid, dev_pid);
-			if (SDL_strcasestr(hint, vendor_match) || SDL_strcasestr(hint, product_match)) {
+		if (vendor_id != 0 || product_id != 0) {
+			if (!parse_hid_vid_pid_from_sysfs(sysfs_path, &bus_type, &dev_vid, &dev_pid))
 				continue;
-			}
+
+			if (vendor_id != 0 && vendor_id != dev_vid)
+				continue;
+			if (product_id != 0 && product_id != dev_pid)
+				continue;
 		}
 
-		/* Check the VID/PID against the arguments */
-		if ((vendor_id == 0x0 || vendor_id == dev_vid) &&
-		    (product_id == 0x0 || product_id == dev_pid)) {
-			struct hid_device_info *tmp;
+		raw_dev = udev_device_new_from_syspath(udev, sysfs_path);
+		if (!raw_dev)
+			continue;
 
-			/* VID/PID match. Create the record. */
-			tmp = (struct hid_device_info *)calloc(1, sizeof(struct hid_device_info));
+		tmp = create_device_info_for_device(raw_dev);
+		if (tmp) {
 			if (cur_dev) {
 				cur_dev->next = tmp;
 			}
 			else {
 				root = tmp;
 			}
-			prev_dev = cur_dev;
 			cur_dev = tmp;
 
-			/* Fill out the record */
-			cur_dev->next = NULL;
-			cur_dev->path = dev_path? strdup(dev_path): NULL;
-
-			/* VID/PID */
-			cur_dev->vendor_id = dev_vid;
-			cur_dev->product_id = dev_pid;
-
-			/* Serial Number */
-			cur_dev->serial_number = utf8_to_wchar_t(serial_number_utf8);
-
-			/* Release Number */
-			cur_dev->release_number = 0x0;
-
-			/* Interface Number */
-			cur_dev->interface_number = -1;
-
-			switch (bus_type) {
-				case BUS_USB:
-					/* The device pointed to by raw_dev contains information about
-					   the hidraw device. In order to get information about the
-					   USB device, get the parent device with the
-					   subsystem/devtype pair of "usb"/"usb_device". This will
-					   be several levels up the tree, but the function will find
-					   it. */
-					usb_dev = udev_device_get_parent_with_subsystem_devtype(
-							raw_dev,
-							"usb",
-							"usb_device");
-
-					if (!usb_dev) {
-						/* Free this device */
-						free(cur_dev->serial_number);
-						free(cur_dev->path);
-						free(cur_dev);
-
-						/* Take it off the device list. */
-						if (prev_dev) {
-							prev_dev->next = NULL;
-							cur_dev = prev_dev;
-						}
-						else {
-							cur_dev = root = NULL;
-						}
-
-						goto next;
-					}
-
-					/* Manufacturer and Product strings */
-					cur_dev->manufacturer_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_MANUFACTURER]);
-					cur_dev->product_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_PRODUCT]);
-
-					/* Release Number */
-					str = udev_device_get_sysattr_value(usb_dev, "bcdDevice");
-					cur_dev->release_number = (str)? strtol(str, NULL, 16): 0x0;
-
-					/* Get a handle to the interface's udev node. */
-					intf_dev = udev_device_get_parent_with_subsystem_devtype(
-							raw_dev,
-							"usb",
-							"usb_interface");
-					if (intf_dev) {
-						str = udev_device_get_sysattr_value(intf_dev, "bInterfaceNumber");
-						cur_dev->interface_number = (str)? strtol(str, NULL, 16): -1;
-					}
-
-					break;
-
-				case BUS_BLUETOOTH:
-					/* Manufacturer and Product strings */
-					cur_dev->manufacturer_string = wcsdup(L"");
-					cur_dev->product_string = utf8_to_wchar_t(product_name_utf8);
-
-					break;
-
-				default:
-					/* Unknown device type - this should never happen, as we
-					 * check for USB and Bluetooth devices above */
-					break;
+			/* move the pointer to the tail of returnd list */
+			while (cur_dev->next != NULL) {
+				cur_dev = cur_dev->next;
 			}
 		}
 
-	next:
-		free(serial_number_utf8);
-		free(product_name_utf8);
 		udev_device_unref(raw_dev);
-		/* hid_dev, usb_dev and intf_dev don't need to be (and can't be)
-		   unref()d.  It will cause a double-free() error.  I'm not
-		   sure why.  */
 	}
 	/* Free the enumerator and udev objects. */
 	udev_enumerate_unref(enumerate);
 	udev_unref(udev);
 
+	if (root == NULL) {
+		if (vendor_id == 0 && product_id == 0) {
+			register_global_error("No HID devices found in the system.");
+		} else {
+			register_global_error("No HID devices with requested VID/PID found in the system.");
+		}
+	}
+
 	return root;
 }
 
@@ -697,7 +948,13 @@
 	const char *path_to_open = NULL;
 	hid_device *handle = NULL;
 
+	/* register_global_error: global error is reset by hid_enumerate/hid_init */
 	devs = hid_enumerate(vendor_id, product_id);
+	if (devs == NULL) {
+		/* register_global_error: global error is already set by hid_enumerate */
+		return NULL;
+	}
+
 	cur_dev = devs;
 	while (cur_dev) {
 		if (cur_dev->vendor_id == vendor_id &&
@@ -718,7 +975,9 @@
 
 	if (path_to_open) {
 		/* Open the device */
-		handle = hid_open_path(path_to_open, 0);
+		handle = hid_open_path(path_to_open);
+	} else {
+		register_global_error("Device with requested VID/PID/(SerialNumber) not found");
 	}
 
 	hid_free_enumeration(devs);
@@ -726,51 +985,38 @@
 	return handle;
 }
 
-hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
+hid_device * HID_API_EXPORT hid_open_path(const char *path)
 {
 	hid_device *dev = NULL;
 
 	hid_init();
+	/* register_global_error: global error is reset by hid_init */
 
 	dev = new_hid_device();
+	if (!dev) {
+		register_global_error("Couldn't allocate memory");
+		return NULL;
+	}
 
-	/* OPEN HERE */
 	dev->device_handle = open(path, O_RDWR | O_CLOEXEC);
 
-	/* If we have a good handle, return it. */
 	if (dev->device_handle >= 0) {
-
-		/* Get the report descriptor */
 		int res, desc_size = 0;
-		struct hidraw_report_descriptor rpt_desc;
 
-		memset(&rpt_desc, 0x0, sizeof(rpt_desc));
-
-		/* Get Report Descriptor Size */
+		/* Make sure this is a HIDRAW device - responds to HIDIOCGRDESCSIZE */
 		res = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size);
-		if (res < 0)
-			perror("HIDIOCGRDESCSIZE");
-
-
-		/* Get Report Descriptor */
-		rpt_desc.size = desc_size;
-		res = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc);
 		if (res < 0) {
-			perror("HIDIOCGRDESC");
-		} else {
-			/* Determine if this device uses numbered reports. */
-			dev->uses_numbered_reports =
-				uses_numbered_reports(rpt_desc.value,
-				                      rpt_desc.size);
+			hid_close(dev);
+			register_global_error_format("ioctl(GRDESCSIZE) error for '%s', not a HIDRAW device?: %s", path, strerror(errno));
+			return NULL;
 		}
 
-		dev->needs_ble_hack = (is_BLE(dev) == 1);
-
 		return dev;
 	}
 	else {
-		/* Unable to open any devices. */
+		/* Unable to open a device. */
 		free(dev);
+		register_global_error_format("Failed to open a device with path '%s': %s", path, strerror(errno));
 		return NULL;
 	}
 }
@@ -780,14 +1026,25 @@
 {
 	int bytes_written;
 
+	if (!data || (length == 0)) {
+		errno = EINVAL;
+		register_device_error(dev, strerror(errno));
+		return -1;
+	}
+
 	bytes_written = write(dev->device_handle, data, length);
 
+	register_device_error(dev, (bytes_written == -1)? strerror(errno): NULL);
+
 	return bytes_written;
 }
 
 
 int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
 {
+	/* Set device error to none */
+	register_device_error(dev, NULL);
+
 	int bytes_read;
 
 	if (milliseconds >= 0) {
@@ -804,29 +1061,32 @@
 		fds.events = POLLIN;
 		fds.revents = 0;
 		ret = poll(&fds, 1, milliseconds);
-		if (ret == -1 || ret == 0) {
-			/* Error or timeout */
+		if (ret == 0) {
+			/* Timeout */
+			return ret;
+		}
+		if (ret == -1) {
+			/* Error */
+			register_device_error(dev, strerror(errno));
 			return ret;
 		}
 		else {
 			/* Check for errors on the file descriptor. This will
 			   indicate a device disconnection. */
-			if (fds.revents & (POLLERR | POLLHUP | POLLNVAL))
+			if (fds.revents & (POLLERR | POLLHUP | POLLNVAL)) {
+				// We cannot use strerror() here as no -1 was returned from poll().
+				register_device_error(dev, "hid_read_timeout: unexpected poll error (device disconnected)");
 				return -1;
+			}
 		}
 	}
 
 	bytes_read = read(dev->device_handle, data, length);
-	if (bytes_read < 0 && (errno == EAGAIN || errno == EINPROGRESS))
-		bytes_read = 0;
-
-	if (bytes_read >= 0 &&
-	    kernel_version != 0 &&
-	    kernel_version < KERNEL_VERSION(2,6,34) &&
-	    dev->uses_numbered_reports) {
-		/* Work around a kernel bug. Chop off the first byte. */
-		memmove(data, data+1, bytes_read);
-		bytes_read--;
+	if (bytes_read < 0) {
+		if (errno == EAGAIN || errno == EINPROGRESS)
+			bytes_read = 0;
+		else
+			register_device_error(dev, strerror(errno));
 	}
 
 	return bytes_read;
@@ -847,90 +1107,186 @@
 	return 0; /* Success */
 }
 
+
 int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
 {
-	static const int MAX_RETRIES = 50;
-	int retry;
 	int res;
 
-	for (retry = 0; retry < MAX_RETRIES; ++retry) {
-		res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data);
-		if (res < 0 && errno == EPIPE) {
-			/* Try again... */
-			continue;
-		}
+	register_device_error(dev, NULL);
 
-		if (res < 0)
-			perror("ioctl (SFEATURE)");
-		break;
-	}
+	res = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data);
+	if (res < 0)
+		register_device_error_format(dev, "ioctl (SFEATURE): %s", strerror(errno));
+
 	return res;
 }
 
 int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
 {
 	int res;
-	unsigned char report = data[0];
+
+	register_device_error(dev, NULL);
 
 	res = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data);
 	if (res < 0)
-		perror("ioctl (GFEATURE)");
-	else if (dev->needs_ble_hack) {
-		/* Versions of BlueZ before 5.56 don't include the report in the data,
-		 * and versions of BlueZ >= 5.56 include 2 copies of the report.
-		 * We'll fix it so that there is a single copy of the report in both cases
-		 */
-		if (data[0] == report && data[1] == report) {
-			memmove(&data[0], &data[1], res);
-		} else if (data[0] != report) {
-			memmove(&data[1], &data[0], res);
-			data[0] = report;
-			++res;
-		}
-	}
+		register_device_error_format(dev, "ioctl (GFEATURE): %s", strerror(errno));
+
 	return res;
 }
 
+int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length)
+{
+	int res;
+
+	register_device_error(dev, NULL);
+
+	res = ioctl(dev->device_handle, HIDIOCGINPUT(length), data);
+	if (res < 0)
+		register_device_error_format(dev, "ioctl (GINPUT): %s", strerror(errno));
+
+	return res;
+}
 
 void HID_API_EXPORT hid_close(hid_device *dev)
 {
 	if (!dev)
 		return;
+
 	close(dev->device_handle);
+
+	/* Free the device error message */
+	register_device_error(dev, NULL);
+
+	hid_free_enumeration(dev->device_info);
+
 	free(dev);
 }
 
 
 int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
 {
-	return get_device_string(dev, DEVICE_STRING_MANUFACTURER, string, maxlen);
+	if (!string || !maxlen) {
+		register_device_error(dev, "Zero buffer/length");
+		return -1;
+	}
+
+	struct hid_device_info *info = hid_get_device_info(dev);
+	if (!info) {
+		// hid_get_device_info will have set an error already
+		return -1;
+	}
+
+	if (info->manufacturer_string) {
+		wcsncpy(string, info->manufacturer_string, maxlen);
+		string[maxlen - 1] = L'\0';
+	}
+	else {
+		string[0] = L'\0';
+	}
+
+	return 0;
 }
 
 int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
 {
-	return get_device_string(dev, DEVICE_STRING_PRODUCT, string, maxlen);
+	if (!string || !maxlen) {
+		register_device_error(dev, "Zero buffer/length");
+		return -1;
+	}
+
+	struct hid_device_info *info = hid_get_device_info(dev);
+	if (!info) {
+		// hid_get_device_info will have set an error already
+		return -1;
+	}
+
+	if (info->product_string) {
+		wcsncpy(string, info->product_string, maxlen);
+		string[maxlen - 1] = L'\0';
+	}
+	else {
+		string[0] = L'\0';
+	}
+
+	return 0;
 }
 
 int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
 {
-	return get_device_string(dev, DEVICE_STRING_SERIAL, string, maxlen);
+	if (!string || !maxlen) {
+		register_device_error(dev, "Zero buffer/length");
+		return -1;
+	}
+
+	struct hid_device_info *info = hid_get_device_info(dev);
+	if (!info) {
+		// hid_get_device_info will have set an error already
+		return -1;
+	}
+
+	if (info->serial_number) {
+		wcsncpy(string, info->serial_number, maxlen);
+		string[maxlen - 1] = L'\0';
+	}
+	else {
+		string[0] = L'\0';
+	}
+
+	return 0;
+}
+
+
+HID_API_EXPORT struct hid_device_info *HID_API_CALL hid_get_device_info(hid_device *dev) {
+	if (!dev->device_info) {
+		// Lazy initialize device_info
+		dev->device_info = create_device_info_for_hid_device(dev);
+	}
+
+	// create_device_info_for_hid_device will set an error if needed
+	return dev->device_info;
 }
 
 int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
 {
-	(void)dev;
 	(void)string_index;
 	(void)string;
 	(void)maxlen;
+
+	register_device_error(dev, "hid_get_indexed_string: not supported by hidraw");
+
 	return -1;
 }
 
 
-HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)
+int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size)
 {
-	return NULL;
+	struct hidraw_report_descriptor rpt_desc;
+	int res = get_hid_report_descriptor_from_hidraw(dev, &rpt_desc);
+	if (res < 0) {
+		/* error already registered */
+		return res;
+	}
+
+	if (rpt_desc.size < buf_size) {
+		buf_size = (size_t) rpt_desc.size;
+	}
+
+	memcpy(buf, rpt_desc.value, buf_size);
+
+	return (int) buf_size;
 }
 
-#ifdef NAMESPACE
+
+/* Passing in NULL means asking for the last global error message. */
+HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)
+{
+	if (dev) {
+		if (dev->last_error_str == NULL)
+			return L"Success";
+		return dev->last_error_str;
+	}
+
+	if (last_global_error_str == NULL)
+		return L"Success";
+	return last_global_error_str;
 }
-#endif
diff --git a/src/hidapi/linux/hidraw.cpp b/src/hidapi/linux/hidraw.cpp
deleted file mode 100644
index 1bf6fad..0000000
--- a/src/hidapi/linux/hidraw.cpp
+++ /dev/null
@@ -1,3 +0,0 @@
-
-#define NAMESPACE HIDRAW
-#include "hid.c"
diff --git a/src/hidapi/m4/.gitignore b/src/hidapi/m4/.gitignore
new file mode 100644
index 0000000..8f79b02
--- /dev/null
+++ b/src/hidapi/m4/.gitignore
@@ -0,0 +1,5 @@
+# Ignore All, except pkg.m4, and of course this file.
+*
+!.gitignore
+!pkg.m4
+!ax_pthread.m4
diff --git a/src/hidapi/mac/.gitignore b/src/hidapi/mac/.gitignore
new file mode 100644
index 0000000..7cc3f0d
--- /dev/null
+++ b/src/hidapi/mac/.gitignore
@@ -0,0 +1,17 @@
+Debug
+Release
+*.exp
+*.ilk
+*.lib
+*.suo
+*.vcproj.*
+*.ncb
+*.suo
+*.dll
+*.pdb
+*.o
+hidapi-hidtest
+.deps
+.libs
+*.la
+*.lo
diff --git a/src/hidapi/mac/CMakeLists.txt b/src/hidapi/mac/CMakeLists.txt
new file mode 100644
index 0000000..a83664a
--- /dev/null
+++ b/src/hidapi/mac/CMakeLists.txt
@@ -0,0 +1,48 @@
+cmake_minimum_required(VERSION 3.4.3 FATAL_ERROR)
+
+list(APPEND HIDAPI_PUBLIC_HEADERS "hidapi_darwin.h")
+
+add_library(hidapi_darwin
+    ${HIDAPI_PUBLIC_HEADERS}
+    hid.c
+)
+
+find_package(Threads REQUIRED)
+
+target_link_libraries(hidapi_darwin
+    PUBLIC hidapi_include
+    PRIVATE Threads::Threads
+    PRIVATE "-framework IOKit" "-framework CoreFoundation" "-framework AppKit"
+)
+
+set_target_properties(hidapi_darwin
+    PROPERTIES
+        EXPORT_NAME "darwin"
+        OUTPUT_NAME "hidapi"
+        VERSION ${PROJECT_VERSION}
+        SOVERSION ${PROJECT_VERSION_MAJOR}
+        MACHO_COMPATIBILITY_VERSION ${PROJECT_VERSION_MAJOR}
+        FRAMEWORK_VERSION ${PROJECT_VERSION_MAJOR}
+        PUBLIC_HEADER "${HIDAPI_PUBLIC_HEADERS}"
+)
+
+# compatibility with find_package()
+add_library(hidapi::darwin ALIAS hidapi_darwin)
+# compatibility with raw library link
+add_library(hidapi ALIAS hidapi_darwin)
+
+set(PUBLIC_HEADER_DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
+if(NOT CMAKE_FRAMEWORK)
+    set(PUBLIC_HEADER_DESTINATION "${PUBLIC_HEADER_DESTINATION}/hidapi")
+endif()
+
+if(HIDAPI_INSTALL_TARGETS)
+    install(TARGETS hidapi_darwin EXPORT hidapi
+        LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+        ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+        FRAMEWORK DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+        PUBLIC_HEADER DESTINATION "${PUBLIC_HEADER_DESTINATION}"
+    )
+endif()
+
+hidapi_configure_pc("${PROJECT_ROOT}/pc/hidapi.pc.in")
diff --git a/src/hidapi/mac/Makefile-manual b/src/hidapi/mac/Makefile-manual
index 5399b5a..2708492 100644
--- a/src/hidapi/mac/Makefile-manual
+++ b/src/hidapi/mac/Makefile-manual
@@ -9,24 +9,19 @@
 all: hidtest
 
 CC=gcc
-CXX=g++
-COBJS=hid.o
-CPPOBJS=../hidtest/hidtest.o
-OBJS=$(COBJS) $(CPPOBJS)
-CFLAGS+=-I../hidapi -Wall -g -c 
-LIBS=-framework IOKit -framework CoreFoundation
+COBJS=hid.o ../hidtest/test.o
+OBJS=$(COBJS)
+CFLAGS+=-I../hidapi -I. -Wall -g -c
+LIBS=-framework IOKit -framework CoreFoundation -framework AppKit
 
 
 hidtest: $(OBJS)
-	g++ -Wall -g $^ $(LIBS) -o hidtest
+	$(CC) -Wall -g $^ $(LIBS) -o hidtest
 
 $(COBJS): %.o: %.c
 	$(CC) $(CFLAGS) $< -o $@
 
-$(CPPOBJS): %.o: %.cpp
-	$(CXX) $(CFLAGS) $< -o $@
-
 clean:
-	rm -f *.o hidtest $(CPPOBJS)
+	rm -f *.o hidtest
 
 .PHONY: clean
diff --git a/src/hidapi/mac/hid.c b/src/hidapi/mac/hid.c
index 9004960..5c0914a 100644
--- a/src/hidapi/mac/hid.c
+++ b/src/hidapi/mac/hid.c
@@ -1,60 +1,67 @@
 /*******************************************************
  HIDAPI - Multi-Platform library for
  communication with HID devices.
- 
+
  Alan Ott
  Signal 11 Software
- 
- 2010-07-03
- 
- Copyright 2010, All Rights Reserved.
- 
+
+ libusb/hidapi Team
+
+ Copyright 2022, All Rights Reserved.
+
  At the discretion of the user of this library,
  this software may be licensed under the terms of the
- GNU Public License v3, a BSD-Style license, or the
+ GNU General Public License v3, a BSD-Style license, or the
  original HIDAPI license as outlined in the LICENSE.txt,
  LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
  files located at the root of the source distribution.
  These files may also be found in the public source
  code repository located at:
- https://github.com/libusb/hidapi .
- ********************************************************/
-#include "SDL_internal.h"
-
+        https://github.com/libusb/hidapi .
+********************************************************/
 
 /* See Apple Technical Note TN2187 for details on IOHidManager. */
 
 #include <IOKit/hid/IOHIDManager.h>
 #include <IOKit/hid/IOHIDKeys.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/usb/USBSpec.h>
 #include <CoreFoundation/CoreFoundation.h>
+#include <mach/mach_error.h>
+#include <stdbool.h>
 #include <wchar.h>
+#include <locale.h>
 #include <pthread.h>
 #include <sys/time.h>
 #include <unistd.h>
+#include <dlfcn.h>
 
-#include "../hidapi/hidapi.h"
+#include "hidapi_darwin.h"
 
-#define VALVE_USB_VID		0x28DE
+/* As defined in AppKit.h, but we don't need the entire AppKit for a single constant. */
+extern const double NSAppKitVersionNumber;
 
 /* Barrier implementation because Mac OSX doesn't have pthread_barrier.
- It also doesn't have clock_gettime(). So much for POSIX and SUSv2.
- This implementation came from Brent Priddy and was posted on
- StackOverflow. It is used with his permission. */
+   It also doesn't have clock_gettime(). So much for POSIX and SUSv2.
+   This implementation came from Brent Priddy and was posted on
+   StackOverflow. It is used with his permission. */
 typedef int pthread_barrierattr_t;
 typedef struct pthread_barrier {
-	pthread_mutex_t mutex;
-	pthread_cond_t cond;
-	int count;
-	int trip_count;
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    int count;
+    int trip_count;
 } pthread_barrier_t;
 
 static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
 {
+	(void) attr;
+
 	if(count == 0) {
 		errno = EINVAL;
 		return -1;
 	}
-	
+
 	if(pthread_mutex_init(&barrier->mutex, 0) < 0) {
 		return -1;
 	}
@@ -64,7 +71,7 @@
 	}
 	barrier->trip_count = count;
 	barrier->count = 0;
-	
+
 	return 0;
 }
 
@@ -103,10 +110,23 @@
 	struct input_report *next;
 };
 
+static struct hid_api_version api_version = {
+	.major = HID_API_VERSION_MAJOR,
+	.minor = HID_API_VERSION_MINOR,
+	.patch = HID_API_VERSION_PATCH
+};
+
+/* - Run context - */
+static	IOHIDManagerRef hid_mgr = 0x0;
+static	int is_macos_10_10_or_greater = 0;
+static	IOOptionBits device_open_options = 0;
+static	wchar_t *last_global_error_str = NULL;
+/* --- */
+
 struct hid_device_ {
 	IOHIDDeviceRef device_handle;
+	IOOptionBits open_options;
 	int blocking;
-	int uses_numbered_reports;
 	int disconnected;
 	CFStringRef run_loop_mode;
 	CFRunLoopRef run_loop;
@@ -114,113 +134,177 @@
 	uint8_t *input_report_buf;
 	CFIndex max_input_report_len;
 	struct input_report *input_reports;
-	
+	struct hid_device_info* device_info;
+
 	pthread_t thread;
 	pthread_mutex_t mutex; /* Protects input_reports */
 	pthread_cond_t condition;
 	pthread_barrier_t barrier; /* Ensures correct startup sequence */
 	pthread_barrier_t shutdown_barrier; /* Ensures correct shutdown sequence */
 	int shutdown_thread;
+	wchar_t *last_error_str;
 };
 
-struct hid_device_list_node
-{
-	struct hid_device_ *dev;
-	struct hid_device_list_node *next;
-};
-
-static 	IOHIDManagerRef hid_mgr = 0x0;
-static 	struct hid_device_list_node *device_list = 0x0;
-
 static hid_device *new_hid_device(void)
 {
-	hid_device *dev = (hid_device*)calloc(1, sizeof(hid_device));
+	hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
+	if (dev == NULL) {
+		return NULL;
+	}
+
 	dev->device_handle = NULL;
+	dev->open_options = device_open_options;
 	dev->blocking = 1;
-	dev->uses_numbered_reports = 0;
 	dev->disconnected = 0;
 	dev->run_loop_mode = NULL;
 	dev->run_loop = NULL;
 	dev->source = NULL;
 	dev->input_report_buf = NULL;
 	dev->input_reports = NULL;
+	dev->device_info = NULL;
 	dev->shutdown_thread = 0;
-	
+	dev->last_error_str = NULL;
+
 	/* Thread objects */
 	pthread_mutex_init(&dev->mutex, NULL);
 	pthread_cond_init(&dev->condition, NULL);
 	pthread_barrier_init(&dev->barrier, NULL, 2);
 	pthread_barrier_init(&dev->shutdown_barrier, NULL, 2);
-	
+
 	return dev;
 }
 
 static void free_hid_device(hid_device *dev)
 {
-	struct input_report *rpt;
 	if (!dev)
 		return;
-	
+
 	/* Delete any input reports still left over. */
-	rpt = dev->input_reports;
+	struct input_report *rpt = dev->input_reports;
 	while (rpt) {
 		struct input_report *next = rpt->next;
 		free(rpt->data);
 		free(rpt);
 		rpt = next;
 	}
-	
+
 	/* Free the string and the report buffer. The check for NULL
-	 is necessary here as CFRelease() doesn't handle NULL like
-	 free() and others do. */
+	   is necessary here as CFRelease() doesn't handle NULL like
+	   free() and others do. */
 	if (dev->run_loop_mode)
 		CFRelease(dev->run_loop_mode);
 	if (dev->source)
 		CFRelease(dev->source);
 	free(dev->input_report_buf);
+	hid_free_enumeration(dev->device_info);
 
-	if (device_list) {
-		if (device_list->dev == dev) {
-			device_list = device_list->next;
-		}
-		else {
-			struct hid_device_list_node *node = device_list;
-			while (node) {
-				if (node->next && node->next->dev == dev) {
-					struct hid_device_list_node *new_next = node->next->next;
-					free(node->next);
-					node->next = new_next;
-					break;
-				}
-
-				node = node->next;
-			}
-		}
-	}
-	
 	/* Clean up the thread objects */
 	pthread_barrier_destroy(&dev->shutdown_barrier);
 	pthread_barrier_destroy(&dev->barrier);
 	pthread_cond_destroy(&dev->condition);
 	pthread_mutex_destroy(&dev->mutex);
-	
+
 	/* Free the structure itself. */
 	free(dev);
 }
 
-#if 0
-static void register_error(hid_device *device, const char *op)
-{
-	
-}
-#endif
 
+/* The caller must free the returned string with free(). */
+static wchar_t *utf8_to_wchar_t(const char *utf8)
+{
+	wchar_t *ret = NULL;
+
+	if (utf8) {
+		size_t wlen = mbstowcs(NULL, utf8, 0);
+		if ((size_t) -1 == wlen) {
+			return wcsdup(L"");
+		}
+		ret = (wchar_t*) calloc(wlen+1, sizeof(wchar_t));
+		if (ret == NULL) {
+			/* as much as we can do at this point */
+			return NULL;
+		}
+		mbstowcs(ret, utf8, wlen+1);
+		ret[wlen] = 0x0000;
+	}
+
+	return ret;
+}
+
+
+/* Makes a copy of the given error message (and decoded according to the
+ * currently locale) into the wide string pointer pointed by error_str.
+ * The last stored error string is freed.
+ * Use register_error_str(NULL) to free the error message completely. */
+static void register_error_str(wchar_t **error_str, const char *msg)
+{
+	free(*error_str);
+	*error_str = utf8_to_wchar_t(msg);
+}
+
+/* Similar to register_error_str, but allows passing a format string with va_list args into this function. */
+static void register_error_str_vformat(wchar_t **error_str, const char *format, va_list args)
+{
+	char msg[1024];
+	vsnprintf(msg, sizeof(msg), format, args);
+
+	register_error_str(error_str, msg);
+}
+
+/* Set the last global error to be reported by hid_error(NULL).
+ * The given error message will be copied (and decoded according to the
+ * currently locale, so do not pass in string constants).
+ * The last stored global error message is freed.
+ * Use register_global_error(NULL) to indicate "no error". */
+static void register_global_error(const char *msg)
+{
+	register_error_str(&last_global_error_str, msg);
+}
+
+/* Similar to register_global_error, but allows passing a format string into this function. */
+static void register_global_error_format(const char *format, ...)
+{
+	va_list args;
+	va_start(args, format);
+	register_error_str_vformat(&last_global_error_str, format, args);
+	va_end(args);
+}
+
+/* Set the last error for a device to be reported by hid_error(dev).
+ * The given error message will be copied (and decoded according to the
+ * currently locale, so do not pass in string constants).
+ * The last stored device error message is freed.
+ * Use register_device_error(dev, NULL) to indicate "no error". */
+static void register_device_error(hid_device *dev, const char *msg)
+{
+	register_error_str(&dev->last_error_str, msg);
+}
+
+/* Similar to register_device_error, but you can pass a format string into this function. */
+static void register_device_error_format(hid_device *dev, const char *format, ...)
+{
+	va_list args;
+	va_start(args, format);
+	register_error_str_vformat(&dev->last_error_str, format, args);
+	va_end(args);
+}
+
+
+static CFArrayRef get_array_property(IOHIDDeviceRef device, CFStringRef key)
+{
+	CFTypeRef ref = IOHIDDeviceGetProperty(device, key);
+	if (ref != NULL && CFGetTypeID(ref) == CFArrayGetTypeID()) {
+		return (CFArrayRef)ref;
+	} else {
+		return NULL;
+	}
+}
 
 static int32_t get_int_property(IOHIDDeviceRef device, CFStringRef key)
 {
 	CFTypeRef ref;
-	int32_t value;
-	
+	int32_t value = 0;
+
 	ref = IOHIDDeviceGetProperty(device, key);
 	if (ref) {
 		if (CFGetTypeID(ref) == CFNumberGetTypeID()) {
@@ -231,6 +315,41 @@
 	return 0;
 }
 
+static bool try_get_int_property(IOHIDDeviceRef device, CFStringRef key, int32_t *out_val)
+{
+	bool result = false;
+	CFTypeRef ref;
+
+	ref = IOHIDDeviceGetProperty(device, key);
+	if (ref) {
+		if (CFGetTypeID(ref) == CFNumberGetTypeID()) {
+			result = CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, out_val);
+		}
+	}
+	return result;
+}
+
+static bool try_get_ioregistry_int_property(io_service_t service, CFStringRef property, int32_t *out_val)
+{
+	bool result = false;
+	CFTypeRef ref = IORegistryEntryCreateCFProperty(service, property, kCFAllocatorDefault, 0);
+
+	if (ref) {
+		if (CFGetTypeID(ref) == CFNumberGetTypeID()) {
+			result = CFNumberGetValue(ref, kCFNumberSInt32Type, out_val);
+		}
+
+		CFRelease(ref);
+	}
+
+	return result;
+}
+
+static CFArrayRef get_usage_pairs(IOHIDDeviceRef device)
+{
+	return get_array_property(device, CFSTR(kIOHIDDeviceUsagePairsKey));
+}
+
 static unsigned short get_vendor_id(IOHIDDeviceRef device)
 {
 	return get_int_property(device, CFSTR(kIOHIDVendorIDKey));
@@ -241,7 +360,6 @@
 	return get_int_property(device, CFSTR(kIOHIDProductIDKey));
 }
 
-
 static int32_t get_max_report_length(IOHIDDeviceRef device)
 {
 	return get_int_property(device, CFSTR(kIOHIDMaxInputReportSizeKey));
@@ -250,78 +368,45 @@
 static int get_string_property(IOHIDDeviceRef device, CFStringRef prop, wchar_t *buf, size_t len)
 {
 	CFStringRef str;
-	
+
 	if (!len)
 		return 0;
 
-	if (CFGetTypeID(prop) != CFStringGetTypeID())
-		return 0;
+	str = (CFStringRef) IOHIDDeviceGetProperty(device, prop);
 
-	str = (CFStringRef)IOHIDDeviceGetProperty(device, prop);
-	
 	buf[0] = 0;
-	
-	if (str && CFGetTypeID(str) == CFStringGetTypeID()) {
-		CFIndex used_buf_len, chars_copied;
-		CFRange range;
+
+	if (str) {
 		CFIndex str_len = CFStringGetLength(str);
+		CFRange range;
+		CFIndex used_buf_len;
+		CFIndex chars_copied;
+
 		len --;
+
 		range.location = 0;
-		range.length = (str_len > len)? len: str_len;
+		range.length = ((size_t) str_len > len)? len: (size_t) str_len;
 		chars_copied = CFStringGetBytes(str,
-										range,
-										kCFStringEncodingUTF32LE,
-										(char)'?',
-										FALSE,
-										(UInt8*)buf,
-										len,
-										&used_buf_len);
-		
-		buf[chars_copied] = 0;
-		return (int)chars_copied;
+			range,
+			kCFStringEncodingUTF32LE,
+			(char) '?',
+			FALSE,
+			(UInt8*)buf,
+			len * sizeof(wchar_t),
+			&used_buf_len);
+
+		if (chars_copied <= 0)
+			buf[0] = 0;
+		else
+			buf[chars_copied] = 0;
+
+		return 0;
 	}
 	else
-		return 0;
-	
+		return -1;
+
 }
 
-static int get_string_property_utf8(IOHIDDeviceRef device, CFStringRef prop, char *buf, size_t len)
-{
-	CFStringRef str;
-	if (!len)
-		return 0;
-	
-	if (CFGetTypeID(prop) != CFStringGetTypeID())
-		return 0;
-
-	str = (CFStringRef)IOHIDDeviceGetProperty(device, prop);
-	
-	buf[0] = 0;
-	
-	if (str && CFGetTypeID(str) == CFStringGetTypeID()) {
-		CFIndex used_buf_len, chars_copied;
-		CFRange range;
-		CFIndex str_len = CFStringGetLength(str);
-		len--;
-		range.location = 0;
-		range.length = (str_len > len)? len: str_len;
-		chars_copied = CFStringGetBytes(str,
-										range,
-										kCFStringEncodingUTF8,
-										(char)'?',
-										FALSE,
-										(UInt8*)buf,
-										len,
-										&used_buf_len);
-		
-		buf[chars_copied] = 0;
-		return (int)used_buf_len;
-	}
-	else
-		return 0;
-}
-
-
 static int get_serial_number(IOHIDDeviceRef device, wchar_t *buf, size_t len)
 {
 	return get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len);
@@ -342,151 +427,50 @@
 static wchar_t *dup_wcs(const wchar_t *s)
 {
 	size_t len = wcslen(s);
-	wchar_t *ret = (wchar_t *)malloc((len+1)*sizeof(wchar_t));
+	wchar_t *ret = (wchar_t*) malloc((len+1)*sizeof(wchar_t));
 	wcscpy(ret, s);
-	
+
 	return ret;
 }
 
-
-static int make_path(IOHIDDeviceRef device, char *buf, size_t len)
-{
-	int res;
-	unsigned short vid, pid;
-	char transport[32];
-	
-	buf[0] = '\0';
-	
-	res = get_string_property_utf8(
-								   device, CFSTR(kIOHIDTransportKey),
-								   transport, sizeof(transport));
-	
-	if (!res)
-		return -1;
-	
-	vid = get_vendor_id(device);
-	pid = get_product_id(device);
-	
-	res = snprintf(buf, len, "%s_%04hx_%04hx_%p",
-				   transport, vid, pid, device);
-	
-	
-	buf[len-1] = '\0';
-	return res+1;
-}
-
-static void hid_device_removal_callback(void *context, IOReturn result,
-                                        void *sender, IOHIDDeviceRef hid_ref)
-{
-	// The device removal callback is sometimes called even after being
-	// unregistered, leading to a crash when trying to access fields in
-	// the already freed hid_device. We keep a linked list of all created
-	// hid_device's so that the one being removed can be checked against
-	// the list to see if it really hasn't been closed yet and needs to
-	// be dealt with here.
-	struct hid_device_list_node *node = device_list;
-	while (node) {
-		if (node->dev->device_handle == hid_ref) {
-			node->dev->disconnected = 1;
-			CFRunLoopStop(node->dev->run_loop);
-			break;
-		}
-
-		node = node->next;
-	}
-}
-
-static CFDictionaryRef
-create_usage_match(const UInt32 page, const UInt32 usage, int *okay)
-{
-	CFDictionaryRef retval = NULL;
-	CFNumberRef pageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
-	CFNumberRef usageNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
-	const void *keys[2] = { (void *) CFSTR(kIOHIDDeviceUsagePageKey), (void *) CFSTR(kIOHIDDeviceUsageKey) };
-	const void *vals[2] = { (void *) pageNumRef, (void *) usageNumRef };
-
-	if (pageNumRef && usageNumRef) {
-		retval = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-	}
-
-	if (pageNumRef) {
-		CFRelease(pageNumRef);
-	}
-	if (usageNumRef) {
-		CFRelease(usageNumRef);
-	}
-
-	if (!retval) {
-		*okay = 0;
-	}
-
-	return retval;
-}
-
-static CFDictionaryRef
-create_vendor_match(const UInt32 vendor, int *okay)
-{
-	CFDictionaryRef retval = NULL;
-	CFNumberRef vidNumRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &vendor);
-	const void *keys[1] = { (void *) CFSTR(kIOHIDVendorIDKey) };
-	const void *vals[1] = { (void *) vidNumRef };
-
-	if (vidNumRef) {
-		retval = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-		CFRelease(vidNumRef);
-	}
-
-	if (!retval) {
-		*okay = 0;
-	}
-
-	return retval;
-}
-
 /* Initialize the IOHIDManager. Return 0 for success and -1 for failure. */
 static int init_hid_manager(void)
 {
-	int okay = 1;
-	const void *vals[] = {
-		(void *) create_usage_match(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick, &okay),
-		(void *) create_usage_match(kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad, &okay),
-		(void *) create_usage_match(kHIDPage_GenericDesktop, kHIDUsage_GD_MultiAxisController, &okay),
-		(void *) create_vendor_match(VALVE_USB_VID, &okay),
-	};
-	const size_t numElements = SDL_arraysize(vals);
-	CFArrayRef matchingArray = okay ? CFArrayCreate(kCFAllocatorDefault, vals, numElements, &kCFTypeArrayCallBacks) : NULL;
-	size_t i;
-
-	for (i = 0; i < numElements; i++) {
-		if (vals[i]) {
-			CFRelease((CFTypeRef) vals[i]);
-		}
-	}
-
 	/* Initialize all the HID Manager Objects */
 	hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
 	if (hid_mgr) {
-		IOHIDManagerSetDeviceMatchingMultiple(hid_mgr, matchingArray);
+		IOHIDManagerSetDeviceMatching(hid_mgr, NULL);
 		IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
-		IOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, hid_device_removal_callback, NULL);
-	}
-	
-	if (matchingArray != NULL) {
-		CFRelease(matchingArray);
+		return 0;
 	}
 
-	return hid_mgr ? 0 : -1;
+	register_global_error("Failed to create IOHIDManager");
+	return -1;
+}
+
+HID_API_EXPORT const struct hid_api_version* HID_API_CALL hid_version(void)
+{
+	return &api_version;
+}
+
+HID_API_EXPORT const char* HID_API_CALL hid_version_str(void)
+{
+	return HID_API_VERSION_STR;
 }
 
 /* Initialize the IOHIDManager if necessary. This is the public function, and
- it is safe to call this function repeatedly. Return 0 for success and -1
- for failure. */
+   it is safe to call this function repeatedly. Return 0 for success and -1
+   for failure. */
 int HID_API_EXPORT hid_init(void)
 {
+	register_global_error(NULL);
+
 	if (!hid_mgr) {
+		is_macos_10_10_or_greater = (NSAppKitVersionNumber >= 1343); /* NSAppKitVersionNumber10_10 */
+		hid_darwin_set_open_exclusive(1); /* Backward compatibility */
 		return init_hid_manager();
 	}
-	
+
 	/* Already initialized. */
 	return 0;
 }
@@ -499,7 +483,10 @@
 		CFRelease(hid_mgr);
 		hid_mgr = NULL;
 	}
-	
+
+	/* Free global error message */
+	register_global_error(NULL);
+
 	return 0;
 }
 
@@ -510,124 +497,296 @@
 	} while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut);
 }
 
-struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
+static int read_usb_interface_from_hid_service_parent(io_service_t hid_service)
 {
-	struct hid_device_info *root = NULL; // return object
-	struct hid_device_info *cur_dev = NULL;
-	CFIndex num_devices;
-	CFSetRef device_set;
-	IOHIDDeviceRef *device_array;
-	int i;
-	const char *hint = SDL_GetHint(SDL_HINT_HIDAPI_IGNORE_DEVICES);
-	
-	/* Set up the HID Manager if it hasn't been done */
-	if (hid_init() < 0)
-		return NULL;
-	
-	/* give the IOHIDManager a chance to update itself */
-	process_pending_events();
-	
-	/* Get a list of the Devices */
-	device_set = IOHIDManagerCopyDevices(hid_mgr);
-	if (!device_set)
-		return NULL;
+	int32_t result = -1;
+	bool success = false;
+	io_registry_entry_t current = IO_OBJECT_NULL;
+	kern_return_t res;
+	int parent_number = 0;
 
-	/* Convert the list into a C array so we can iterate easily. */	
-	num_devices = CFSetGetCount(device_set);
-	if (!num_devices) {
-		CFRelease(device_set);
+	res = IORegistryEntryGetParentEntry(hid_service, kIOServicePlane, &current);
+	while (KERN_SUCCESS == res
+			/* Only search up to 3 parent entries.
+			 * With the default driver - the parent-of-interest supposed to be the first one,
+			 * but lets assume some custom drivers or so, with deeper tree. */
+			&& parent_number < 3) {
+		io_registry_entry_t parent = IO_OBJECT_NULL;
+		int32_t interface_number = -1;
+		parent_number++;
+
+		success = try_get_ioregistry_int_property(current, CFSTR(kUSBInterfaceNumber), &interface_number);
+		if (success) {
+			result = interface_number;
+			break;
+		}
+
+		res = IORegistryEntryGetParentEntry(current, kIOServicePlane, &parent);
+		if (parent) {
+			IOObjectRelease(current);
+			current = parent;
+		}
+
+	}
+
+	if (current) {
+		IOObjectRelease(current);
+		current = IO_OBJECT_NULL;
+	}
+
+	return result;
+}
+
+static struct hid_device_info *create_device_info_with_usage(IOHIDDeviceRef dev, int32_t usage_page, int32_t usage)
+{
+	unsigned short dev_vid;
+	unsigned short dev_pid;
+	int BUF_LEN = 256;
+	wchar_t buf[BUF_LEN];
+	CFTypeRef transport_prop;
+
+	struct hid_device_info *cur_dev;
+	io_service_t hid_service;
+	kern_return_t res;
+	uint64_t entry_id = 0;
+
+	if (dev == NULL) {
 		return NULL;
 	}
-	device_array = (IOHIDDeviceRef*)calloc(num_devices, sizeof(IOHIDDeviceRef));
-	CFSetGetValues(device_set, (const void **) device_array);
-	
-	/* Iterate over each device, making an entry for it. */	
+
+	cur_dev = (struct hid_device_info *)calloc(1, sizeof(struct hid_device_info));
+	if (cur_dev == NULL) {
+		return NULL;
+	}
+
+	dev_vid = get_vendor_id(dev);
+	dev_pid = get_product_id(dev);
+
+	cur_dev->usage_page = usage_page;
+	cur_dev->usage = usage;
+
+	/* Fill out the record */
+	cur_dev->next = NULL;
+
+	/* Fill in the path (as a unique ID of the service entry) */
+	cur_dev->path = NULL;
+	hid_service = IOHIDDeviceGetService(dev);
+	if (hid_service != MACH_PORT_NULL) {
+		res = IORegistryEntryGetRegistryEntryID(hid_service, &entry_id);
+	}
+	else {
+		res = KERN_INVALID_ARGUMENT;
+	}
+
+	if (res == KERN_SUCCESS) {
+		/* max value of entry_id(uint64_t) is 18446744073709551615 which is 20 characters long,
+		   so for (max) "path" string 'DevSrvsID:18446744073709551615' we would need
+		   9+1+20+1=31 bytes buffer, but allocate 32 for simple alignment */
+		const size_t path_len = 32;
+		cur_dev->path = calloc(1, path_len);
+		if (cur_dev->path != NULL) {
+			snprintf(cur_dev->path, path_len, "DevSrvsID:%llu", entry_id);
+		}
+	}
+
+	if (cur_dev->path == NULL) {
+		/* for whatever reason, trying to keep it a non-NULL string */
+		cur_dev->path = strdup("");
+	}
+
+	/* Serial Number */
+	get_serial_number(dev, buf, BUF_LEN);
+	cur_dev->serial_number = dup_wcs(buf);
+
+	/* Manufacturer and Product strings */
+	get_manufacturer_string(dev, buf, BUF_LEN);
+	cur_dev->manufacturer_string = dup_wcs(buf);
+	get_product_string(dev, buf, BUF_LEN);
+	cur_dev->product_string = dup_wcs(buf);
+
+	/* VID/PID */
+	cur_dev->vendor_id = dev_vid;
+	cur_dev->product_id = dev_pid;
+
+	/* Release Number */
+	cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey));
+
+	/* Interface Number.
+	 * We can only retrieve the interface number for USB HID devices.
+	 * See below */
+	cur_dev->interface_number = -1;
+
+	/* Bus Type */
+	transport_prop = IOHIDDeviceGetProperty(dev, CFSTR(kIOHIDTransportKey));
+
+	if (transport_prop != NULL && CFGetTypeID(transport_prop) == CFStringGetTypeID()) {
+		if (CFStringCompare((CFStringRef)transport_prop, CFSTR(kIOHIDTransportUSBValue), 0) == kCFCompareEqualTo) {
+			int32_t interface_number = -1;
+			cur_dev->bus_type = HID_API_BUS_USB;
+
+			/* A IOHIDDeviceRef used to have this simple property,
+			 * until macOS 13.3 - we will try to use it. */
+			if (try_get_int_property(dev, CFSTR(kUSBInterfaceNumber), &interface_number)) {
+				cur_dev->interface_number = interface_number;
+			} else {
+				/* Otherwise fallback to io_service_t property.
+				 * (of one of the parent services). */
+				cur_dev->interface_number = read_usb_interface_from_hid_service_parent(hid_service);
+
+				/* If the above doesn't work -
+				 * no (known) fallback exists at this point. */
+			}
+
+		/* Match "Bluetooth", "BluetoothLowEnergy" and "Bluetooth Low Energy" strings */
+		} else if (CFStringHasPrefix((CFStringRef)transport_prop, CFSTR(kIOHIDTransportBluetoothValue))) {
+			cur_dev->bus_type = HID_API_BUS_BLUETOOTH;
+		} else if (CFStringCompare((CFStringRef)transport_prop, CFSTR(kIOHIDTransportI2CValue), 0) == kCFCompareEqualTo) {
+			cur_dev->bus_type = HID_API_BUS_I2C;
+		} else  if (CFStringCompare((CFStringRef)transport_prop, CFSTR(kIOHIDTransportSPIValue), 0) == kCFCompareEqualTo) {
+			cur_dev->bus_type = HID_API_BUS_SPI;
+		}
+	}
+
+	return cur_dev;
+}
+
+static struct hid_device_info *create_device_info(IOHIDDeviceRef device)
+{
+	const int32_t primary_usage_page = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey));
+	const int32_t primary_usage = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey));
+
+	/* Primary should always be first, to match previous behavior. */
+	struct hid_device_info *root = create_device_info_with_usage(device, primary_usage_page, primary_usage);
+	struct hid_device_info *cur = root;
+
+	if (!root)
+		return NULL;
+
+	CFArrayRef usage_pairs = get_usage_pairs(device);
+
+	if (usage_pairs != NULL) {
+		struct hid_device_info *next = NULL;
+		for (CFIndex i = 0; i < CFArrayGetCount(usage_pairs); i++) {
+			CFTypeRef dict = CFArrayGetValueAtIndex(usage_pairs, i);
+			if (CFGetTypeID(dict) != CFDictionaryGetTypeID()) {
+				continue;
+			}
+
+			CFTypeRef usage_page_ref, usage_ref;
+			int32_t usage_page, usage;
+
+			if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)dict, CFSTR(kIOHIDDeviceUsagePageKey), &usage_page_ref) ||
+			    !CFDictionaryGetValueIfPresent((CFDictionaryRef)dict, CFSTR(kIOHIDDeviceUsageKey), &usage_ref) ||
+					CFGetTypeID(usage_page_ref) != CFNumberGetTypeID() ||
+					CFGetTypeID(usage_ref) != CFNumberGetTypeID() ||
+					!CFNumberGetValue((CFNumberRef)usage_page_ref, kCFNumberSInt32Type, &usage_page) ||
+					!CFNumberGetValue((CFNumberRef)usage_ref, kCFNumberSInt32Type, &usage)) {
+					continue;
+			}
+			if (usage_page == primary_usage_page && usage == primary_usage)
+				continue; /* Already added. */
+
+			next = create_device_info_with_usage(device, usage_page, usage);
+			cur->next = next;
+			if (next != NULL) {
+				cur = next;
+			}
+		}
+	}
+
+	return root;
+}
+
+struct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
+{
+	struct hid_device_info *root = NULL; /* return object */
+	struct hid_device_info *cur_dev = NULL;
+	CFIndex num_devices;
+	int i;
+
+	/* Set up the HID Manager if it hasn't been done */
+	if (hid_init() < 0) {
+		return NULL;
+	}
+	/* register_global_error: global error is set/reset by hid_init */
+
+	/* give the IOHIDManager a chance to update itself */
+	process_pending_events();
+
+	/* Get a list of the Devices */
+	CFMutableDictionaryRef matching = NULL;
+	if (vendor_id != 0 || product_id != 0) {
+		matching = CFDictionaryCreateMutable(kCFAllocatorDefault, kIOHIDOptionsTypeNone, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+		if (matching && vendor_id != 0) {
+			CFNumberRef v = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &vendor_id);
+			CFDictionarySetValue(matching, CFSTR(kIOHIDVendorIDKey), v);
+			CFRelease(v);
+		}
+
+		if (matching && product_id != 0) {
+			CFNumberRef p = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &product_id);
+			CFDictionarySetValue(matching, CFSTR(kIOHIDProductIDKey), p);
+			CFRelease(p);
+		}
+	}
+	IOHIDManagerSetDeviceMatching(hid_mgr, matching);
+	if (matching != NULL) {
+		CFRelease(matching);
+	}
+
+	CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
+
+	IOHIDDeviceRef *device_array = NULL;
+
+	if (device_set != NULL) {
+		/* Convert the list into a C array so we can iterate easily. */
+		num_devices = CFSetGetCount(device_set);
+		device_array = (IOHIDDeviceRef*) calloc(num_devices, sizeof(IOHIDDeviceRef));
+		CFSetGetValues(device_set, (const void **) device_array);
+	} else {
+		num_devices = 0;
+	}
+
+	/* Iterate over each device, making an entry for it. */
 	for (i = 0; i < num_devices; i++) {
-		unsigned short dev_vid;
-		unsigned short dev_pid;
-#define BUF_LEN 256
-		wchar_t buf[BUF_LEN];
-		char cbuf[BUF_LEN];
-		
+
 		IOHIDDeviceRef dev = device_array[i];
-		
 		if (!dev) {
 			continue;
 		}
 
-#if 0 // Prefer direct HID support as that has extended functionality
-#ifdef SDL_JOYSTICK_MFI
-		// We want to prefer Game Controller support where available,
-		// as Apple will likely be requiring that for supported devices.
-		extern SDL_bool IOS_SupportedHIDDevice(IOHIDDeviceRef device);
-		if (IOS_SupportedHIDDevice(dev)) {
+		struct hid_device_info *tmp = create_device_info(dev);
+		if (tmp == NULL) {
 			continue;
 		}
-#endif
-#endif
 
-		dev_vid = get_vendor_id(dev);
-		dev_pid = get_product_id(dev);
-		
-		/* See if there are any devices we should skip in enumeration */
-		if (hint) {
-			char vendor_match[16], product_match[16];
-			SDL_snprintf(vendor_match, sizeof(vendor_match), "0x%.4x/0x0000", dev_vid);
-			SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", dev_vid, dev_pid);
-			if (SDL_strcasestr(hint, vendor_match) || SDL_strcasestr(hint, product_match)) {
-				continue;
-			}
+		if (cur_dev) {
+			cur_dev->next = tmp;
 		}
+		else {
+			root = tmp;
+		}
+		cur_dev = tmp;
 
-		/* Check the VID/PID against the arguments */
-		if ((vendor_id == 0x0 || dev_vid == vendor_id) &&
-		    (product_id == 0x0 || dev_pid == product_id)) {
-			struct hid_device_info *tmp;
-
-			/* VID/PID match. Create the record. */
-			tmp = (struct hid_device_info *)calloc(1, sizeof(struct hid_device_info));
-			if (cur_dev) {
-				cur_dev->next = tmp;
-			}
-			else {
-				root = tmp;
-			}
-			cur_dev = tmp;
-			
-			// Get the Usage Page and Usage for this device.
-			cur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey));
-			cur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey));
-			
-			/* Fill out the record */
-			cur_dev->next = NULL;
-			make_path(dev, cbuf, sizeof(cbuf));
-			cur_dev->path = strdup(cbuf);
-			
-			/* Serial Number */
-			get_serial_number(dev, buf, BUF_LEN);
-			cur_dev->serial_number = dup_wcs(buf);
-			
-			/* Manufacturer and Product strings */
-			get_manufacturer_string(dev, buf, BUF_LEN);
-			cur_dev->manufacturer_string = dup_wcs(buf);
-			get_product_string(dev, buf, BUF_LEN);
-			cur_dev->product_string = dup_wcs(buf);
-			
-			/* VID/PID */
-			cur_dev->vendor_id = dev_vid;
-			cur_dev->product_id = dev_pid;
-			
-			/* Release Number */
-			cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey));
-			
-			/* Interface Number (Unsupported on Mac)*/
-			cur_dev->interface_number = -1;
+		/* move the pointer to the tail of returnd list */
+		while (cur_dev->next != NULL) {
+			cur_dev = cur_dev->next;
 		}
 	}
-	
+
 	free(device_array);
-	CFRelease(device_set);
-	
+	if (device_set != NULL)
+		CFRelease(device_set);
+
+	if (root == NULL) {
+		if (vendor_id == 0 && product_id == 0) {
+			register_global_error("No HID devices found in the system.");
+		} else {
+			register_global_error("No HID devices with requested VID/PID found in the system.");
+		}
+	}
+
 	return root;
 }
 
@@ -649,11 +808,18 @@
 hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
 {
 	/* This function is identical to the Linux version. Platform independent. */
+
 	struct hid_device_info *devs, *cur_dev;
 	const char *path_to_open = NULL;
 	hid_device * handle = NULL;
-	
+
+	/* register_global_error: global error is reset by hid_enumerate/hid_init */
 	devs = hid_enumerate(vendor_id, product_id);
+	if (devs == NULL) {
+		/* register_global_error: global error is already set by hid_enumerate */
+		return NULL;
+	}
+
 	cur_dev = devs;
 	while (cur_dev) {
 		if (cur_dev->vendor_id == vendor_id &&
@@ -671,37 +837,56 @@
 		}
 		cur_dev = cur_dev->next;
 	}
-	
+
 	if (path_to_open) {
-		/* Open the device */
-		handle = hid_open_path(path_to_open, 0);
+		handle = hid_open_path(path_to_open);
+	} else {
+		register_global_error("Device with requested VID/PID/(SerialNumber) not found");
 	}
-	
+
 	hid_free_enumeration(devs);
-	
+
 	return handle;
 }
 
-/* The Run Loop calls this function for each input report received.
- This function puts the data into a linked list to be picked up by
- hid_read(). */
-static void hid_report_callback(void *context, IOReturn result, void *sender,
-								IOHIDReportType report_type, uint32_t report_id,
-								uint8_t *report, CFIndex report_length)
+static void hid_device_removal_callback(void *context, IOReturn result,
+                                        void *sender)
 {
+	(void) result;
+	(void) sender;
+
+	/* Stop the Run Loop for this device. */
+	hid_device *d = (hid_device*) context;
+
+	d->disconnected = 1;
+	CFRunLoopStop(d->run_loop);
+}
+
+/* The Run Loop calls this function for each input report received.
+   This function puts the data into a linked list to be picked up by
+   hid_read(). */
+static void hid_report_callback(void *context, IOReturn result, void *sender,
+                         IOHIDReportType report_type, uint32_t report_id,
+                         uint8_t *report, CFIndex report_length)
+{
+	(void) result;
+	(void) sender;
+	(void) report_type;
+	(void) report_id;
+
 	struct input_report *rpt;
-	hid_device *dev = (hid_device *)context;
-	
+	hid_device *dev = (hid_device*) context;
+
 	/* Make a new Input Report object */
-	rpt = (struct input_report *)calloc(1, sizeof(struct input_report));
-	rpt->data = (uint8_t *)calloc(1, report_length);
+	rpt = (struct input_report*) calloc(1, sizeof(struct input_report));
+	rpt->data = (uint8_t*) calloc(1, report_length);
 	memcpy(rpt->data, report, report_length);
 	rpt->len = report_length;
 	rpt->next = NULL;
-	
+
 	/* Lock this section */
 	pthread_mutex_lock(&dev->mutex);
-	
+
 	/* Attach the new report object to the end of the list. */
 	if (dev->input_reports == NULL) {
 		/* The list is empty. Put it at the root. */
@@ -716,58 +901,58 @@
 			num_queued++;
 		}
 		cur->next = rpt;
-		
+
 		/* Pop one off if we've reached 30 in the queue. This
-		 way we don't grow forever if the user never reads
-		 anything from the device. */
+		   way we don't grow forever if the user never reads
+		   anything from the device. */
 		if (num_queued > 30) {
 			return_data(dev, NULL, 0);
 		}
 	}
-	
+
 	/* Signal a waiting thread that there is data. */
 	pthread_cond_signal(&dev->condition);
-	
+
 	/* Unlock */
 	pthread_mutex_unlock(&dev->mutex);
-	
+
 }
 
-/* This gets called when the read_thred's run loop gets signaled by
- hid_close(), and serves to stop the read_thread's run loop. */
+/* This gets called when the read_thread's run loop gets signaled by
+   hid_close(), and serves to stop the read_thread's run loop. */
 static void perform_signal_callback(void *context)
 {
-	hid_device *dev = (hid_device *)context;
-	CFRunLoopStop(dev->run_loop); //TODO: CFRunLoopGetCurrent()
+	hid_device *dev = (hid_device*) context;
+	CFRunLoopStop(dev->run_loop); /*TODO: CFRunLoopGetCurrent()*/
 }
 
 static void *read_thread(void *param)
 {
-	hid_device *dev = (hid_device *)param;
-	CFRunLoopSourceContext ctx;
-    SInt32 code;
-	
+	hid_device *dev = (hid_device*) param;
+	SInt32 code;
+
 	/* Move the device's run loop to this thread. */
 	IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode);
-	
+
 	/* Create the RunLoopSource which is used to signal the
-	 event loop to stop when hid_close() is called. */
+	   event loop to stop when hid_close() is called. */
+	CFRunLoopSourceContext ctx;
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.version = 0;
 	ctx.info = dev;
 	ctx.perform = &perform_signal_callback;
 	dev->source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0/*order*/, &ctx);
 	CFRunLoopAddSource(CFRunLoopGetCurrent(), dev->source, dev->run_loop_mode);
-	
+
 	/* Store off the Run Loop so it can be stopped from hid_close()
-	 and on device disconnection. */
+	   and on device disconnection. */
 	dev->run_loop = CFRunLoopGetCurrent();
-	
+
 	/* Notify the main thread that the read thread is up and running. */
 	pthread_barrier_wait(&dev->barrier);
-	
+
 	/* Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input
-	 reports into the hid_report_callback(). */
+	   reports into the hid_report_callback(). */
 	while (!dev->shutdown_thread && !dev->disconnected) {
 		code = CFRunLoopRunInMode(dev->run_loop_mode, 1000/*sec*/, FALSE);
 		/* Return if the device has been disconnected */
@@ -775,171 +960,220 @@
 			dev->disconnected = 1;
 			break;
 		}
-		
-		
+
+
 		/* Break if The Run Loop returns Finished or Stopped. */
 		if (code != kCFRunLoopRunTimedOut &&
 		    code != kCFRunLoopRunHandledSource) {
 			/* There was some kind of error. Setting
-			 shutdown seems to make sense, but
-			 there may be something else more appropriate */
+			   shutdown seems to make sense, but
+			   there may be something else more appropriate */
 			dev->shutdown_thread = 1;
 			break;
 		}
 	}
-	
+
 	/* Now that the read thread is stopping, Wake any threads which are
-	 waiting on data (in hid_read_timeout()). Do this under a mutex to
-	 make sure that a thread which is about to go to sleep waiting on
-	 the condition acutally will go to sleep before the condition is
-	 signaled. */
+	   waiting on data (in hid_read_timeout()). Do this under a mutex to
+	   make sure that a thread which is about to go to sleep waiting on
+	   the condition actually will go to sleep before the condition is
+	   signaled. */
 	pthread_mutex_lock(&dev->mutex);
 	pthread_cond_broadcast(&dev->condition);
 	pthread_mutex_unlock(&dev->mutex);
-	
+
 	/* Wait here until hid_close() is called and makes it past
-	 the call to CFRunLoopWakeUp(). This thread still needs to
-	 be valid when that function is called on the other thread. */
+	   the call to CFRunLoopWakeUp(). This thread still needs to
+	   be valid when that function is called on the other thread. */
 	pthread_barrier_wait(&dev->shutdown_barrier);
-	
+
 	return NULL;
 }
 
-hid_device * HID_API_EXPORT hid_open_path(const char *path, int bExclusive)
+/* \p path must be one of:
+     - in format 'DevSrvsID:<RegistryEntryID>' (as returned by hid_enumerate);
+     - a valid path to an IOHIDDevice in the IOService plane (as returned by IORegistryEntryGetPath,
+       e.g.: "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/EHC1@1D,7/AppleUSBEHCI/PLAYSTATION(R)3 Controller@fd120000/IOUSBInterface@0/IOUSBHIDDriver");
+   Second format is for compatibility with paths accepted by older versions of HIDAPI.
+*/
+static io_registry_entry_t hid_open_service_registry_from_path(const char *path)
 {
-	int i;
-	hid_device *dev = NULL;
-	CFIndex num_devices;
-	CFSetRef device_set;
-	IOHIDDeviceRef *device_array;
+	if (path == NULL)
+		return MACH_PORT_NULL;
 
-	dev = new_hid_device();
-	
-	/* Set up the HID Manager if it hasn't been done */
-	if (hid_init() < 0)
-		return NULL;
-
-#if 0 /* We have a path because the IOHIDManager is already updated */
-	/* give the IOHIDManager a chance to update itself */
-	process_pending_events();
-#endif
-
-	device_set = IOHIDManagerCopyDevices(hid_mgr);
-	if (!device_set)
-		return NULL;
-	
-	num_devices = CFSetGetCount(device_set);
-	device_array = (IOHIDDeviceRef *)calloc(num_devices, sizeof(IOHIDDeviceRef));
-	CFSetGetValues(device_set, (const void **) device_array);	
-	for (i = 0; i < num_devices; i++) {
-		char cbuf[BUF_LEN];
-		IOHIDDeviceRef os_dev = device_array[i];
-		
-		make_path(os_dev, cbuf, sizeof(cbuf));
-		if (!strcmp(cbuf, path)) {
-			// Matched Paths. Open this Device.
-			IOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeNone);
-			if (ret == kIOReturnSuccess) {
-				char str[32];
-				struct hid_device_list_node *node;
-				
-				free(device_array);
-				CFRelease(device_set);
-				dev->device_handle = os_dev;
-				
-				/* Create the buffers for receiving data */
-				dev->max_input_report_len = (CFIndex) get_max_report_length(os_dev);
-				SDL_assert(dev->max_input_report_len > 0);
-				dev->input_report_buf = (uint8_t *)calloc(dev->max_input_report_len, sizeof(uint8_t));
-				
-				/* Create the Run Loop Mode for this device.
-				 printing the reference seems to work. */
-				snprintf(str, sizeof(str), "HIDAPI_%p", os_dev);
-				dev->run_loop_mode = 
-				CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII);
-				
-				/* Attach the device to a Run Loop */
-				IOHIDDeviceRegisterInputReportCallback(
-													   os_dev, dev->input_report_buf, dev->max_input_report_len,
-													   &hid_report_callback, dev);
-
-				node = (struct hid_device_list_node *)calloc(1, sizeof(struct hid_device_list_node));
-				node->dev = dev;
-				node->next = device_list;
-				device_list = node;
-
-				/* Start the read thread */
-				pthread_create(&dev->thread, NULL, read_thread, dev);
-				
-				/* Wait here for the read thread to be initialized. */
-				pthread_barrier_wait(&dev->barrier);
-				
-				return dev;
-			}
-			else {
-				goto return_error;
-			}
+	/* Get the IORegistry entry for the given path */
+	if (strncmp("DevSrvsID:", path, 10) == 0) {
+		char *endptr;
+		uint64_t entry_id = strtoull(path + 10, &endptr, 10);
+		if (*endptr == '\0') {
+			return IOServiceGetMatchingService((mach_port_t) 0, IORegistryEntryIDMatching(entry_id));
 		}
 	}
-	
+	else {
+		/* Fallback to older format of the path */
+		return IORegistryEntryFromPath((mach_port_t) 0, path);
+	}
+
+	return MACH_PORT_NULL;
+}
+
+hid_device * HID_API_EXPORT hid_open_path(const char *path)
+{
+	hid_device *dev = NULL;
+	io_registry_entry_t entry = MACH_PORT_NULL;
+	IOReturn ret = kIOReturnInvalid;
+	char str[32];
+
+	/* Set up the HID Manager if it hasn't been done */
+	if (hid_init() < 0) {
+		return NULL;
+	}
+	/* register_global_error: global error is set/reset by hid_init */
+
+	dev = new_hid_device();
+	if (!dev) {
+		register_global_error("Couldn't allocate memory");
+		return NULL;
+	}
+
+	/* Get the IORegistry entry for the given path */
+	entry = hid_open_service_registry_from_path(path);
+	if (entry == MACH_PORT_NULL) {
+		/* Path wasn't valid (maybe device was removed?) */
+		register_global_error("hid_open_path: device mach entry not found with the given path");
+		goto return_error;
+	}
+
+	/* Create an IOHIDDevice for the entry */
+	dev->device_handle = IOHIDDeviceCreate(kCFAllocatorDefault, entry);
+	if (dev->device_handle == NULL) {
+		/* Error creating the HID device */
+		register_global_error("hid_open_path: failed to create IOHIDDevice from the mach entry");
+		goto return_error;
+	}
+
+	/* Open the IOHIDDevice */
+	ret = IOHIDDeviceOpen(dev->device_handle, dev->open_options);
+	if (ret != kIOReturnSuccess) {
+		register_global_error_format("hid_open_path: failed to open IOHIDDevice from mach entry: (0x%08X) %s", ret, mach_error_string(ret));
+		goto return_error;
+	}
+
+	/* Create the buffers for receiving data */
+	dev->max_input_report_len = (CFIndex) get_max_report_length(dev->device_handle);
+	dev->input_report_buf = (uint8_t*) calloc(dev->max_input_report_len, sizeof(uint8_t));
+
+	/* Create the Run Loop Mode for this device.
+	   printing the reference seems to work. */
+	snprintf(str, sizeof(str), "HIDAPI_%p", (void*) dev->device_handle);
+	dev->run_loop_mode =
+		CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII);
+
+	/* Attach the device to a Run Loop */
+	IOHIDDeviceRegisterInputReportCallback(
+		dev->device_handle, dev->input_report_buf, dev->max_input_report_len,
+		&hid_report_callback, dev);
+	IOHIDDeviceRegisterRemovalCallback(dev->device_handle, hid_device_removal_callback, dev);
+
+	/* Start the read thread */
+	pthread_create(&dev->thread, NULL, read_thread, dev);
+
+	/* Wait here for the read thread to be initialized. */
+	pthread_barrier_wait(&dev->barrier);
+
+	IOObjectRelease(entry);
+	return dev;
+
 return_error:
-	free(device_array);
-	CFRelease(device_set);
+	if (dev->device_handle != NULL)
+		CFRelease(dev->device_handle);
+
+	if (entry != MACH_PORT_NULL)
+		IOObjectRelease(entry);
+
 	free_hid_device(dev);
 	return NULL;
 }
 
 static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char *data, size_t length)
 {
-	const char *pass_through_magic = "MAGIC0";
-	size_t pass_through_magic_length = strlen(pass_through_magic);
-	unsigned char report_id = data[0];
-	const unsigned char *data_to_send;
-	size_t length_to_send;
+	const unsigned char *data_to_send = data;
+	CFIndex length_to_send = length;
 	IOReturn res;
-	
-	/* Return if the device has been disconnected. */
-   	if (dev->disconnected)
-   		return -1;
-	
+	unsigned char report_id;
+
+	register_device_error(dev, NULL);
+
+	if (!data || (length == 0)) {
+		register_device_error(dev, strerror(EINVAL));
+		return -1;
+	}
+
+	report_id = data[0];
+
 	if (report_id == 0x0) {
 		/* Not using numbered Reports.
-		 Don't send the report number. */
+		   Don't send the report number. */
 		data_to_send = data+1;
 		length_to_send = length-1;
 	}
-	else if (length > 6 && memcmp(data, pass_through_magic, pass_through_magic_length) == 0) {
-		report_id = data[pass_through_magic_length];
-		data_to_send = data+pass_through_magic_length;
-		length_to_send = length-pass_through_magic_length;
+
+	/* Avoid crash if the device has been unplugged. */
+	if (dev->disconnected) {
+		register_device_error(dev, "Device is disconnected");
+		return -1;
 	}
-	else {
-		/* Using numbered Reports.
-		 Send the Report Number */
-		data_to_send = data;
-		length_to_send = length;
+
+	res = IOHIDDeviceSetReport(dev->device_handle,
+	                           type,
+	                           report_id,
+	                           data_to_send, length_to_send);
+
+	if (res != kIOReturnSuccess) {
+		register_device_error_format(dev, "IOHIDDeviceSetReport failed: (0x%08X) %s", res, mach_error_string(res));
+		return -1;
 	}
-	
-	if (!dev->disconnected) {
-		res = IOHIDDeviceSetReport(dev->device_handle,
-								   type,
-								   report_id, /* Report ID*/
-								   data_to_send, length_to_send);
-		
-		if (res == kIOReturnSuccess) {
-			return (int)length;
-		}
-		else if (res == kIOReturnUnsupported) {
-			/*printf("kIOReturnUnsupported\n");*/
-			return -1;
-		}
-		else {
-			/*printf("0x%x\n", res);*/
-			return -1;
-		}
+
+	return (int) length;
+}
+
+static int get_report(hid_device *dev, IOHIDReportType type, unsigned char *data, size_t length)
+{
+	unsigned char *report = data;
+	CFIndex report_length = length;
+	IOReturn res = kIOReturnSuccess;
+	const unsigned char report_id = data[0];
+
+	register_device_error(dev, NULL);
+
+	if (report_id == 0x0) {
+		/* Not using numbered Reports.
+		   Don't send the report number. */
+		report = data+1;
+		report_length = length-1;
 	}
-	
-	return -1;
+
+	/* Avoid crash if the device has been unplugged. */
+	if (dev->disconnected) {
+		register_device_error(dev, "Device is disconnected");
+		return -1;
+	}
+
+	res = IOHIDDeviceGetReport(dev->device_handle,
+	                           type,
+	                           report_id,
+	                           report, &report_length);
+
+	if (res != kIOReturnSuccess) {
+		register_device_error_format(dev, "IOHIDDeviceGetReport failed: (0x%08X) %s", res, mach_error_string(res));
+		return -1;
+	}
+
+	if (report_id == 0x0) { /* 0 report number still present at the beginning */
+		report_length++;
+	}
+
+	return (int) report_length;
 }
 
 int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
@@ -951,90 +1185,91 @@
 static int return_data(hid_device *dev, unsigned char *data, size_t length)
 {
 	/* Copy the data out of the linked list item (rpt) into the
-	 return buffer (data), and delete the liked list item. */
+	   return buffer (data), and delete the liked list item. */
 	struct input_report *rpt = dev->input_reports;
-	size_t len = 0;
-	if (rpt != NULL) {
-		len = (length < rpt->len)? length: rpt->len;
-		memcpy(data, rpt->data, len);
-		dev->input_reports = rpt->next;
-		free(rpt->data);
-		free(rpt);
-	}
-	return (int)len;
+	size_t len = (length < rpt->len)? length: rpt->len;
+	memcpy(data, rpt->data, len);
+	dev->input_reports = rpt->next;
+	free(rpt->data);
+	free(rpt);
+	return (int) len;
 }
 
-static int cond_wait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex)
+static int cond_wait(hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex)
 {
 	while (!dev->input_reports) {
 		int res = pthread_cond_wait(cond, mutex);
 		if (res != 0)
 			return res;
-		
+
 		/* A res of 0 means we may have been signaled or it may
-		 be a spurious wakeup. Check to see that there's acutally
-		 data in the queue before returning, and if not, go back
-		 to sleep. See the pthread_cond_timedwait() man page for
-		 details. */
-		
-		if (dev->shutdown_thread || dev->disconnected)
+		   be a spurious wakeup. Check to see that there's actually
+		   data in the queue before returning, and if not, go back
+		   to sleep. See the pthread_cond_timedwait() man page for
+		   details. */
+
+		if (dev->shutdown_thread || dev->disconnected) {
 			return -1;
+		}
 	}
-	
+
 	return 0;
 }
 
-static int cond_timedwait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
+static int cond_timedwait(hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
 {
 	while (!dev->input_reports) {
 		int res = pthread_cond_timedwait(cond, mutex, abstime);
 		if (res != 0)
 			return res;
-		
+
 		/* A res of 0 means we may have been signaled or it may
-		 be a spurious wakeup. Check to see that there's acutally
-		 data in the queue before returning, and if not, go back
-		 to sleep. See the pthread_cond_timedwait() man page for
-		 details. */
-		
-		if (dev->shutdown_thread || dev->disconnected)
+		   be a spurious wakeup. Check to see that there's actually
+		   data in the queue before returning, and if not, go back
+		   to sleep. See the pthread_cond_timedwait() man page for
+		   details. */
+
+		if (dev->shutdown_thread || dev->disconnected) {
 			return -1;
+		}
 	}
-	
+
 	return 0;
-	
+
 }
 
 int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
 {
 	int bytes_read = -1;
-	
+
 	/* Lock the access to the report list. */
 	pthread_mutex_lock(&dev->mutex);
-	
+
 	/* There's an input report queued up. Return it. */
 	if (dev->input_reports) {
 		/* Return the first one */
 		bytes_read = return_data(dev, data, length);
 		goto ret;
 	}
-	
+
 	/* Return if the device has been disconnected. */
 	if (dev->disconnected) {
 		bytes_read = -1;
+		register_device_error(dev, "hid_read_timeout: device disconnected");
 		goto ret;
 	}
-	
+
 	if (dev->shutdown_thread) {
 		/* This means the device has been closed (or there
-		 has been an error. An error code of -1 should
-		 be returned. */
+		   has been an error. An error code of -1 should
+		   be returned. */
 		bytes_read = -1;
+		register_device_error(dev, "hid_read_timeout: thread shutdown");
 		goto ret;
 	}
-	
+
 	/* There is no data. Go to sleep and wait for data. */
-	
+
 	if (milliseconds == -1) {
 		/* Blocking */
 		int res;
@@ -1043,6 +1278,7 @@
 			bytes_read = return_data(dev, data, length);
 		else {
 			/* There was an error, or a device disconnection. */
+			register_device_error(dev, "hid_read_timeout: error waiting for more data");
 			bytes_read = -1;
 		}
 	}
@@ -1059,20 +1295,22 @@
 			ts.tv_sec++;
 			ts.tv_nsec -= 1000000000L;
 		}
-		
+
 		res = cond_timedwait(dev, &dev->condition, &dev->mutex, &ts);
-		if (res == 0)
+		if (res == 0) {
 			bytes_read = return_data(dev, data, length);
-		else if (res == ETIMEDOUT)
+		} else if (res == ETIMEDOUT) {
 			bytes_read = 0;
-		else
+		} else {
+			register_device_error(dev, "hid_read_timeout:  error waiting for more data");
 			bytes_read = -1;
+		}
 	}
 	else {
 		/* Purely non-blocking */
 		bytes_read = 0;
 	}
-	
+
 ret:
 	/* Unlock */
 	pthread_mutex_unlock(&dev->mutex);
@@ -1088,7 +1326,7 @@
 {
 	/* All Nonblocking operation is handled by the library. */
 	dev->blocking = !nonblock;
-	
+
 	return 0;
 }
 
@@ -1099,180 +1337,215 @@
 
 int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
 {
-	CFIndex len = length;
-	IOReturn res;
-	int skipped_report_id = 0, report_number;
-
-	/* Return if the device has been unplugged. */
-	if (dev->disconnected)
-		return -1;
-	
-	report_number = data[0];
-	if (report_number == 0x0) {
-		/* Offset the return buffer by 1, so that the report ID
-		 will remain in byte 0. */
-		data++;
-		len--;
-		skipped_report_id = 1;
-	}
-	
-	res = IOHIDDeviceGetReport(dev->device_handle,
-	                           kIOHIDReportTypeFeature,
-	                           report_number, /* Report ID */
-	                           data, &len);
-	if (res != kIOReturnSuccess)
-		return -1;
-
-	if (skipped_report_id)
-		len++;
-
-	return (int)len;
+	return get_report(dev, kIOHIDReportTypeFeature, data, length);
 }
 
+int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length)
+{
+	return get_report(dev, kIOHIDReportTypeInput, data, length);
+}
 
 void HID_API_EXPORT hid_close(hid_device *dev)
 {
 	if (!dev)
 		return;
-	
-	/* Disconnect the report callback before close. */
-	if (!dev->disconnected) {
+
+	/* Disconnect the report callback before close.
+	   See comment below.
+	*/
+	if (is_macos_10_10_or_greater || !dev->disconnected) {
 		IOHIDDeviceRegisterInputReportCallback(
-											   dev->device_handle, dev->input_report_buf, dev->max_input_report_len,
-											   NULL, dev);
+			dev->device_handle, dev->input_report_buf, dev->max_input_report_len,
+			NULL, dev);
+		IOHIDDeviceRegisterRemovalCallback(dev->device_handle, NULL, dev);
 		IOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run_loop_mode);
 		IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
 	}
-	
+
 	/* Cause read_thread() to stop. */
 	dev->shutdown_thread = 1;
-	
+
 	/* Wake up the run thread's event loop so that the thread can exit. */
 	CFRunLoopSourceSignal(dev->source);
 	CFRunLoopWakeUp(dev->run_loop);
-	
+
 	/* Notify the read thread that it can shut down now. */
 	pthread_barrier_wait(&dev->shutdown_barrier);
-	
+
 	/* Wait for read_thread() to end. */
 	pthread_join(dev->thread, NULL);
-	
+
 	/* Close the OS handle to the device, but only if it's not
-	 been unplugged. If it's been unplugged, then calling
-	 IOHIDDeviceClose() will crash. */
-	if (!dev->disconnected) {
-		IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeNone);
+	   been unplugged. If it's been unplugged, then calling
+	   IOHIDDeviceClose() will crash.
+
+	   UPD: The crash part was true in/until some version of macOS.
+	   Starting with macOS 10.15, there is an opposite effect in some environments:
+	   crash happenes if IOHIDDeviceClose() is not called.
+	   Not leaking a resource in all tested environments.
+	*/
+	if (is_macos_10_10_or_greater || !dev->disconnected) {
+		IOHIDDeviceClose(dev->device_handle, dev->open_options);
 	}
-	
+
 	/* Clear out the queue of received reports. */
 	pthread_mutex_lock(&dev->mutex);
 	while (dev->input_reports) {
 		return_data(dev, NULL, 0);
 	}
 	pthread_mutex_unlock(&dev->mutex);
-	
+	CFRelease(dev->device_handle);
+
 	free_hid_device(dev);
 }
 
 int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
 {
-	return get_manufacturer_string(dev->device_handle, string, maxlen);
+	if (!string || !maxlen)
+	{
+		register_device_error(dev, "Zero buffer/length");
+		return -1;
+	}
+
+	struct hid_device_info *info = hid_get_device_info(dev);
+	if (!info)
+	{
+		// hid_get_device_info will have set an error already
+		return -1;
+	}
+
+	wcsncpy(string, info->manufacturer_string, maxlen);
+	string[maxlen - 1] = L'\0';
+
+	return 0;
 }
 
 int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
 {
-	return get_product_string(dev->device_handle, string, maxlen);
+	if (!string || !maxlen) {
+		register_device_error(dev, "Zero buffer/length");
+		return -1;
+	}
+
+	struct hid_device_info *info = hid_get_device_info(dev);
+	if (!info) {
+		// hid_get_device_info will have set an error already
+		return -1;
+	}
+
+	wcsncpy(string, info->product_string, maxlen);
+	string[maxlen - 1] = L'\0';
+
+	return 0;
 }
 
 int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
 {
-	return get_serial_number(dev->device_handle, string, maxlen);
+	if (!string || !maxlen) {
+		register_device_error(dev, "Zero buffer/length");
+		return -1;
+	}
+
+	struct hid_device_info *info = hid_get_device_info(dev);
+	if (!info) {
+		// hid_get_device_info will have set an error already
+		return -1;
+	}
+
+	wcsncpy(string, info->serial_number, maxlen);
+	string[maxlen - 1] = L'\0';
+
+	return 0;
+}
+
+HID_API_EXPORT struct hid_device_info *HID_API_CALL hid_get_device_info(hid_device *dev) {
+	if (!dev->device_info) {
+		dev->device_info = create_device_info(dev->device_handle);
+		if (!dev->device_info) {
+			register_device_error(dev, "Failed to create hid_device_info");
+		}
+	}
+
+	return dev->device_info;
 }
 
 int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
 {
-	// TODO:
-	
-	return 0;
+	(void) dev;
+	(void) string_index;
+	(void) string;
+	(void) maxlen;
+
+	register_device_error(dev, "hid_get_indexed_string: not available on this platform");
+	return -1;
 }
 
+int HID_API_EXPORT_CALL hid_darwin_get_location_id(hid_device *dev, uint32_t *location_id)
+{
+	int res = get_int_property(dev->device_handle, CFSTR(kIOHIDLocationIDKey));
+	if (res != 0) {
+		*location_id = (uint32_t) res;
+		return 0;
+	} else {
+		register_device_error(dev, "Failed to get IOHIDLocationID property");
+		return -1;
+	}
+}
+
+void HID_API_EXPORT_CALL hid_darwin_set_open_exclusive(int open_exclusive)
+{
+	device_open_options = (open_exclusive == 0) ? kIOHIDOptionsTypeNone : kIOHIDOptionsTypeSeizeDevice;
+}
+
+int HID_API_EXPORT_CALL hid_darwin_get_open_exclusive(void)
+{
+	return (device_open_options == kIOHIDOptionsTypeSeizeDevice) ? 1 : 0;
+}
+
+int HID_API_EXPORT_CALL hid_darwin_is_device_open_exclusive(hid_device *dev)
+{
+	if (!dev)
+		return -1;
+
+	return (dev->open_options == kIOHIDOptionsTypeSeizeDevice) ? 1 : 0;
+}
+
+int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size)
+{
+	CFTypeRef ref = IOHIDDeviceGetProperty(dev->device_handle, CFSTR(kIOHIDReportDescriptorKey));
+	if (ref != NULL && CFGetTypeID(ref) == CFDataGetTypeID()) {
+		CFDataRef report_descriptor = (CFDataRef) ref;
+		const UInt8 *descriptor_buf = CFDataGetBytePtr(report_descriptor);
+		CFIndex descriptor_buf_len = CFDataGetLength(report_descriptor);
+		size_t copy_len = (size_t) descriptor_buf_len;
+
+		if (descriptor_buf == NULL || descriptor_buf_len < 0) {
+			register_device_error(dev, "Zero buffer/length");
+			return -1;
+		}
+
+		if (buf_size < copy_len) {
+			copy_len = buf_size;
+		}
+
+		memcpy(buf, descriptor_buf, copy_len);
+		return copy_len;
+	}
+	else {
+		register_device_error(dev, "Failed to get kIOHIDReportDescriptorKey property");
+		return -1;
+	}
+}
 
 HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)
 {
-	// TODO:
-	
-	return NULL;
-}
-
-
-
-
-
-
-#if 0
-static int32_t get_location_id(IOHIDDeviceRef device)
-{
-	return get_int_property(device, CFSTR(kIOHIDLocationIDKey));
-}
-
-static int32_t get_usage(IOHIDDeviceRef device)
-{
-	int32_t res;
-	res = get_int_property(device, CFSTR(kIOHIDDeviceUsageKey));
-	if (!res)
-		res = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey));
-	return res;
-}
-
-static int32_t get_usage_page(IOHIDDeviceRef device)
-{
-	int32_t res;
-	res = get_int_property(device, CFSTR(kIOHIDDeviceUsagePageKey));
-	if (!res)
-		res = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey));
-	return res;
-}
-
-static int get_transport(IOHIDDeviceRef device, wchar_t *buf, size_t len)
-{
-	return get_string_property(device, CFSTR(kIOHIDTransportKey), buf, len);
-}
-
-
-int main(void)
-{
-	IOHIDManagerRef mgr;
-	int i;
-	
-	mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
-	IOHIDManagerSetDeviceMatching(mgr, NULL);
-	IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone);
-	
-	CFSetRef device_set = IOHIDManagerCopyDevices(mgr);
-	
-	CFIndex num_devices = CFSetGetCount(device_set);
-	IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
-	CFSetGetValues(device_set, (const void **) device_array);
-	
-	for (i = 0; i < num_devices; i++) {
-		IOHIDDeviceRef dev = device_array[i];
-		printf("Device: %p\n", dev);
-		printf("  %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev));
-		
-		wchar_t serial[256], buf[256];
-		char cbuf[256];
-		get_serial_number(dev, serial, 256);
-		
-		
-		printf("  Serial: %ls\n", serial);
-		printf("  Loc: %ld\n", get_location_id(dev));
-		get_transport(dev, buf, 256);
-		printf("  Trans: %ls\n", buf);
-		make_path(dev, cbuf, 256);
-		printf("  Path: %s\n", cbuf);
-		
+	if (dev) {
+		if (dev->last_error_str == NULL)
+			return L"Success";
+		return dev->last_error_str;
 	}
-	
-	return 0;
+
+	if (last_global_error_str == NULL)
+		return L"Success";
+	return last_global_error_str;
 }
-#endif
diff --git a/src/hidapi/mac/hidapi_darwin.h b/src/hidapi/mac/hidapi_darwin.h
new file mode 100644
index 0000000..34c30a0
--- /dev/null
+++ b/src/hidapi/mac/hidapi_darwin.h
@@ -0,0 +1,98 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ libusb/hidapi Team
+
+ Copyright 2022, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+        https://github.com/libusb/hidapi .
+********************************************************/
+
+/** @file
+ * @defgroup API hidapi API
+
+ * Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
+ */
+
+#ifndef HIDAPI_DARWIN_H__
+#define HIDAPI_DARWIN_H__
+
+#include <stdint.h>
+
+#include "hidapi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+		/** @brief Get the location ID for a HID device.
+
+			Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
+
+			@ingroup API
+			@param dev A device handle returned from hid_open().
+			@param location_id The device's location ID on return.
+
+			@returns
+				This function returns 0 on success and -1 on error.
+		*/
+		int HID_API_EXPORT_CALL hid_darwin_get_location_id(hid_device *dev, uint32_t *location_id);
+
+
+		/** @brief Changes the behavior of all further calls to @ref hid_open or @ref hid_open_path.
+
+			By default on Darwin platform all devices opened by HIDAPI with @ref hid_open or @ref hid_open_path
+			are opened in exclusive mode (see kIOHIDOptionsTypeSeizeDevice).
+
+			Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
+
+			@ingroup API
+			@param open_exclusive When set to 0 - all further devices will be opened
+				in non-exclusive mode. Otherwise - all further devices will be opened
+				in exclusive mode.
+
+			@note During the initialisation by @ref hid_init - this property is set to 1 (TRUE).
+			This is done to preserve full backward compatibility with previous behavior.
+
+			@note Calling this function before @ref hid_init or after @ref hid_exit has no effect.
+		*/
+		void HID_API_EXPORT_CALL hid_darwin_set_open_exclusive(int open_exclusive);
+
+		/** @brief Getter for option set by @ref hid_darwin_set_open_exclusive.
+
+			Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
+
+			@ingroup API
+			@return 1 if all further devices will be opened in exclusive mode.
+
+			@note Value returned by this function before calling to @ref hid_init or after @ref hid_exit
+			is not reliable.
+		*/
+		int HID_API_EXPORT_CALL hid_darwin_get_open_exclusive(void);
+
+		/** @brief Check how the device was opened.
+
+			Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
+
+			@ingroup API
+			@param dev A device to get property from.
+
+			@return 1 if the device is opened in exclusive mode, 0 - opened in non-exclusive,
+			-1 - if dev is invalid.
+		*/
+		int HID_API_EXPORT_CALL hid_darwin_is_device_open_exclusive(hid_device *dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/hidapi/meson.build b/src/hidapi/meson.build
new file mode 100644
index 0000000..d7867cb
--- /dev/null
+++ b/src/hidapi/meson.build
@@ -0,0 +1,22 @@
+project('hidapi', meson_version: '>=0.57.0', version: files('VERSION'))
+
+cmake = import('cmake')
+
+hidapi_build_options = cmake.subproject_options()
+hidapi_build_options.set_install(true)
+
+hidapi_build = cmake.subproject('hidapi_build_cmake', options: hidapi_build_options)
+
+if (hidapi_build.target_list().contains('hidapi_winapi'))
+	hidapi_winapi_dep = hidapi_build.dependency('hidapi_winapi')
+	hidapi_dep = hidapi_winapi_dep
+elif (hidapi_build.target_list().contains('hidapi_darwin'))
+	hidapi_darwin_dep = hidapi_build.dependency('hidapi_darwin')
+	hidapi_dep = hidapi_darwin_dep
+elif (hidapi_build.target_list().contains('hidapi_hidraw'))
+	hidapi_hidraw_dep = hidapi_build.dependency('hidapi_hidraw')
+	hidapi_dep = hidapi_hidraw_dep
+elif (hidapi_build.target_list().contains('hidapi_libusb'))
+	hidapi_libusb_dep = hidapi_build.dependency('hidapi_libusb')
+	hidapi_dep = hidapi_libusb_dep
+endif
diff --git a/src/hidapi/pc/.gitignore b/src/hidapi/pc/.gitignore
new file mode 100644
index 0000000..6fd0ef0
--- /dev/null
+++ b/src/hidapi/pc/.gitignore
@@ -0,0 +1 @@
+*.pc
diff --git a/src/hidapi/pc/hidapi-hidraw.pc.in b/src/hidapi/pc/hidapi-hidraw.pc.in
index e20558d..28b9fe6 100644
--- a/src/hidapi/pc/hidapi-hidraw.pc.in
+++ b/src/hidapi/pc/hidapi-hidraw.pc.in
@@ -5,6 +5,7 @@
 
 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
diff --git a/src/hidapi/pc/hidapi-libusb.pc.in b/src/hidapi/pc/hidapi-libusb.pc.in
index 2e49506..d51e98f 100644
--- a/src/hidapi/pc/hidapi-libusb.pc.in
+++ b/src/hidapi/pc/hidapi-libusb.pc.in
@@ -5,6 +5,7 @@
 
 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
diff --git a/src/hidapi/pc/hidapi.pc.in b/src/hidapi/pc/hidapi.pc.in
index 5835c99..75b11a5 100644
--- a/src/hidapi/pc/hidapi.pc.in
+++ b/src/hidapi/pc/hidapi.pc.in
@@ -5,6 +5,7 @@
 
 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
diff --git a/src/hidapi/src/CMakeLists.txt b/src/hidapi/src/CMakeLists.txt
new file mode 100644
index 0000000..d08224b
--- /dev/null
+++ b/src/hidapi/src/CMakeLists.txt
@@ -0,0 +1,193 @@
+get_filename_component(PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
+
+# Read version from file
+file(READ "${PROJECT_ROOT}/VERSION" RAW_VERSION_STR)
+string(REGEX MATCH "^([0-9]+\\.[0-9]+\\.[0-9]+)(.*)" VERSION_STR "${RAW_VERSION_STR}")
+
+if(NOT VERSION_STR)
+    message(FATAL_ERROR "Broken VERSION file, couldn't parse '${PROJECT_ROOT}/VERSION' with content: '${RAW_VERSION_STR}'")
+endif()
+
+set(VERSION "${CMAKE_MATCH_1}")
+string(STRIP "${CMAKE_MATCH_2}" VERSION_SUFFIX)
+# compatibility with find_package() vs add_subdirectory
+set(hidapi_VERSION "${VERSION}" PARENT_SCOPE)
+#
+
+if(DEFINED HIDAPI_PRINT_VERSION AND HIDAPI_PRINT_VERSION)
+    set(HIDAPI_PRINT_VERSION "hidapi: v${VERSION}")
+    if(VERSION_SUFFIX)
+        set(HIDAPI_PRINT_VERSION "${HIDAPI_PRINT_VERSION} (${VERSION_SUFFIX})")
+    endif()
+    message(STATUS "${HIDAPI_PRINT_VERSION}")
+endif()
+
+project(hidapi VERSION "${VERSION}" LANGUAGES C)
+
+# Defaults and required options
+
+if(NOT DEFINED HIDAPI_WITH_TESTS)
+    set(HIDAPI_WITH_TESTS OFF)
+endif()
+if(NOT DEFINED BUILD_SHARED_LIBS)
+    set(BUILD_SHARED_LIBS ON)
+endif()
+if(NOT DEFINED HIDAPI_INSTALL_TARGETS)
+    set(HIDAPI_INSTALL_TARGETS OFF)
+endif()
+if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
+    set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+endif()
+
+get_directory_property(IS_EXCLUDE_FROM_ALL EXCLUDE_FROM_ALL)
+if(IS_EXCLUDE_FROM_ALL)
+    if(HIDAPI_INSTALL_TARGETS)
+        message(WARNING "Installing EXCLUDE_FROM_ALL targets in an undefined behavior in CMake.\nDon't add 'hidapi' sundirectory with 'EXCLUDE_FROM_ALL' property, or don't set 'HIDAPI_INSTALL_TARGETS' to TRUE.")
+    endif()
+endif()
+
+# Helper(s)
+
+function(hidapi_configure_pc PC_IN_FILE)
+    file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/pc")
+
+    set(VERSION "${VERSION}${VERSION_SUFFIX}")
+    set(prefix "${CMAKE_INSTALL_PREFIX}")
+    set(exec_prefix "\${prefix}")
+    if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
+        set(libdir "${CMAKE_INSTALL_LIBDIR}")
+    else()
+        set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
+    endif()
+    if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
+        set(includedir "${CMAKE_INSTALL_INCLUDEDIR}")
+    else()
+        set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
+    endif()
+
+    get_filename_component(PC_IN_FILENAME "${PC_IN_FILE}" NAME_WE)
+    set(PC_FILE "${CMAKE_CURRENT_BINARY_DIR}/pc/${PC_IN_FILENAME}.pc")
+    configure_file("${PC_IN_FILE}" "${PC_FILE}" @ONLY)
+
+    install(FILES "${PC_FILE}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig/")
+endfunction()
+
+# The library
+
+if(HIDAPI_INSTALL_TARGETS)
+    include(GNUInstallDirs)
+endif()
+
+add_library(hidapi_include INTERFACE)
+target_include_directories(hidapi_include INTERFACE
+    "$<BUILD_INTERFACE:${PROJECT_ROOT}/hidapi>"
+)
+if(APPLE AND CMAKE_FRAMEWORK)
+    # FIXME: https://github.com/libusb/hidapi/issues/492: it is untrivial to set the include path for Framework correctly
+else()
+    target_include_directories(hidapi_include INTERFACE
+        "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/hidapi>"
+    )
+endif()
+set_target_properties(hidapi_include PROPERTIES EXPORT_NAME "include")
+set(HIDAPI_PUBLIC_HEADERS "${PROJECT_ROOT}/hidapi/hidapi.h")
+
+add_library(hidapi::include ALIAS hidapi_include)
+
+if(HIDAPI_INSTALL_TARGETS)
+    install(TARGETS hidapi_include EXPORT hidapi)
+endif()
+
+set(EXPORT_ALIAS)
+set(EXPORT_COMPONENTS)
+
+set(HIDAPI_NEED_EXPORT_THREADS FALSE)
+set(HIDAPI_NEED_EXPORT_LIBUSB FALSE)
+set(HIDAPI_NEED_EXPORT_LIBUDEV FALSE)
+set(HIDAPI_NEED_EXPORT_ICONV FALSE)
+
+if(WIN32)
+    target_include_directories(hidapi_include INTERFACE
+        "$<BUILD_INTERFACE:${PROJECT_ROOT}/windows>"
+    )
+    add_subdirectory("${PROJECT_ROOT}/windows" windows)
+    set(EXPORT_ALIAS winapi)
+    list(APPEND EXPORT_COMPONENTS winapi)
+elseif(APPLE)
+    target_include_directories(hidapi_include INTERFACE
+        "$<BUILD_INTERFACE:${PROJECT_ROOT}/mac>"
+    )
+    add_subdirectory("${PROJECT_ROOT}/mac" mac)
+    set(EXPORT_ALIAS darwin)
+    list(APPEND EXPORT_COMPONENTS darwin)
+    if(NOT BUILD_SHARED_LIBS)
+        set(HIDAPI_NEED_EXPORT_THREADS TRUE)
+    endif()
+else()
+    if(NOT DEFINED HIDAPI_WITH_LIBUSB)
+        set(HIDAPI_WITH_LIBUSB ON)
+    endif()
+    if(CMAKE_SYSTEM_NAME MATCHES "Linux")
+        if(NOT DEFINED HIDAPI_WITH_HIDRAW)
+            set(HIDAPI_WITH_HIDRAW ON)
+        endif()
+        if(HIDAPI_WITH_HIDRAW)
+            add_subdirectory("${PROJECT_ROOT}/linux" linux)
+            list(APPEND EXPORT_COMPONENTS hidraw)
+            set(EXPORT_ALIAS hidraw)
+            if(NOT BUILD_SHARED_LIBS)
+                set(HIDAPI_NEED_EXPORT_THREADS TRUE)
+                set(HIDAPI_NEED_EXPORT_LIBUDEV TRUE)
+            endif()
+        endif()
+    else()
+        set(HIDAPI_WITH_LIBUSB ON)
+    endif()
+    if(HIDAPI_WITH_LIBUSB)
+        target_include_directories(hidapi_include INTERFACE
+            "$<BUILD_INTERFACE:${PROJECT_ROOT}/libusb>"
+        )
+        if(NOT DEFINED HIDAPI_NO_ICONV)
+            set(HIDAPI_NO_ICONV OFF)
+        endif()
+        add_subdirectory("${PROJECT_ROOT}/libusb" libusb)
+        list(APPEND EXPORT_COMPONENTS libusb)
+        if(NOT EXPORT_ALIAS)
+            set(EXPORT_ALIAS libusb)
+        endif()
+        if(NOT BUILD_SHARED_LIBS)
+            set(HIDAPI_NEED_EXPORT_THREADS TRUE)
+            if(NOT TARGET usb-1.0)
+                set(HIDAPI_NEED_EXPORT_LIBUSB TRUE)
+            endif()
+        endif()
+    elseif(NOT TARGET hidapi_hidraw)
+        message(FATAL_ERROR "Select at least one option to build: HIDAPI_WITH_LIBUSB or HIDAPI_WITH_HIDRAW")
+    endif()
+endif()
+
+add_library(hidapi::hidapi ALIAS hidapi_${EXPORT_ALIAS})
+
+if(HIDAPI_INSTALL_TARGETS)
+    include(CMakePackageConfigHelpers)
+    set(EXPORT_DENERATED_LOCATION "${CMAKE_BINARY_DIR}/export_generated")
+    set(EXPORT_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/hidapi")
+    write_basic_package_version_file("${EXPORT_DENERATED_LOCATION}/hidapi-config-version.cmake"
+        COMPATIBILITY SameMajorVersion
+    )
+    configure_package_config_file("cmake/hidapi-config.cmake.in" "${EXPORT_DENERATED_LOCATION}/hidapi-config.cmake"
+        INSTALL_DESTINATION "${EXPORT_DESTINATION}"
+        NO_SET_AND_CHECK_MACRO
+    )
+
+    install(EXPORT hidapi
+        DESTINATION "${EXPORT_DESTINATION}"
+        NAMESPACE hidapi::
+        FILE "libhidapi.cmake"
+    )
+    install(FILES
+            "${EXPORT_DENERATED_LOCATION}/hidapi-config-version.cmake"
+            "${EXPORT_DENERATED_LOCATION}/hidapi-config.cmake"
+        DESTINATION "${EXPORT_DESTINATION}"
+    )
+endif()
diff --git a/src/hidapi/src/cmake/hidapi-config.cmake.in b/src/hidapi/src/cmake/hidapi-config.cmake.in
new file mode 100644
index 0000000..4226c8c
--- /dev/null
+++ b/src/hidapi/src/cmake/hidapi-config.cmake.in
@@ -0,0 +1,61 @@
+@PACKAGE_INIT@
+
+set(hidapi_VERSION_MAJOR "@hidapi_VERSION_MAJOR@")
+set(hidapi_VERSION_MINOR "@hidapi_VERSION_MINOR@")
+set(hidapi_VERSION_PATCH "@hidapi_VERSION_PATCH@")
+set(hidapi_VERSION "@hidapi_VERSION@")
+set(hidapi_VERSION_STR "@hidapi_VERSION@@VERSION_SUFFIX@")
+
+set(hidapi_FOUND FALSE)
+
+set(HIDAPI_NEED_EXPORT_THREADS @HIDAPI_NEED_EXPORT_THREADS@)
+set(HIDAPI_NEED_EXPORT_LIBUSB @HIDAPI_NEED_EXPORT_LIBUSB@)
+set(HIDAPI_NEED_EXPORT_LIBUDEV @HIDAPI_NEED_EXPORT_LIBUDEV@)
+set(HIDAPI_NEED_EXPORT_ICONV @HIDAPI_NEED_EXPORT_ICONV@)
+
+if(HIDAPI_NEED_EXPORT_THREADS)
+  if(CMAKE_VERSION VERSION_LESS 3.4.3)
+    message(FATAL_ERROR "This file relies on consumers using CMake 3.4.3 or greater.")
+  endif()
+  find_package(Threads REQUIRED)
+endif()
+
+if(HIDAPI_NEED_EXPORT_LIBUSB OR HIDAPI_NEED_EXPORT_LIBUDEV)
+  if(CMAKE_VERSION VERSION_LESS 3.6.3)
+    message(FATAL_ERROR "This file relies on consumers using CMake 3.6.3 or greater.")
+  endif()
+  find_package(PkgConfig)
+  if(HIDAPI_NEED_EXPORT_LIBUSB)
+    pkg_check_modules(libusb REQUIRED IMPORTED_TARGET libusb-1.0>=1.0.9)
+  endif()
+  if(HIDAPI_NEED_EXPORT_LIBUDEV)
+    pkg_check_modules(libudev REQUIRED IMPORTED_TARGET libudev)
+  endif()
+endif()
+
+if(HIDAPI_NEED_EXPORT_ICONV)
+  if(CMAKE_VERSION VERSION_LESS 3.11)
+    message(WARNING "HIDAPI requires CMake target Iconv::Iconv, make sure to provide it")
+  else()
+    find_package(Iconv REQUIRED)
+  endif()
+endif()
+
+include("${CMAKE_CURRENT_LIST_DIR}/libhidapi.cmake")
+
+set(hidapi_FOUND TRUE)
+
+foreach(_component @EXPORT_COMPONENTS@)
+  if(TARGET hidapi::${_component})
+    set(hidapi_${_component}_FOUND TRUE)
+  endif()
+endforeach()
+
+check_required_components(hidapi)
+
+if(NOT TARGET hidapi::hidapi)
+  add_library(hidapi::hidapi INTERFACE IMPORTED)
+  set_target_properties(hidapi::hidapi PROPERTIES
+    INTERFACE_LINK_LIBRARIES hidapi::@EXPORT_ALIAS@
+  )
+endif()
diff --git a/src/hidapi/subprojects/README.md b/src/hidapi/subprojects/README.md
new file mode 100644
index 0000000..8ba8f60
--- /dev/null
+++ b/src/hidapi/subprojects/README.md
@@ -0,0 +1,2 @@
+This folder is used only to support [meson.build](../meson.build) `subproject` command
+which would only look for a subproject in a "subprojects" directory.
\ No newline at end of file
diff --git a/src/hidapi/subprojects/hidapi_build_cmake/CMakeLists.txt b/src/hidapi/subprojects/hidapi_build_cmake/CMakeLists.txt
new file mode 100644
index 0000000..80aed67
--- /dev/null
+++ b/src/hidapi/subprojects/hidapi_build_cmake/CMakeLists.txt
@@ -0,0 +1,10 @@
+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)
diff --git a/src/hidapi/testgui/.gitignore b/src/hidapi/testgui/.gitignore
new file mode 100644
index 0000000..f989ea8
--- /dev/null
+++ b/src/hidapi/testgui/.gitignore
@@ -0,0 +1,20 @@
+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
diff --git a/src/hidapi/testgui/Makefile.mingw b/src/hidapi/testgui/Makefile.mingw
index df0f69d..f76b5a0 100644
--- a/src/hidapi/testgui/Makefile.mingw
+++ b/src/hidapi/testgui/Makefile.mingw
@@ -14,7 +14,7 @@
 CPPOBJS=test.o
 OBJS=$(COBJS) $(CPPOBJS)
 CFLAGS=-I../hidapi -I../../hidapi-externals/fox/include -g -c
-LIBS= -mwindows -lsetupapi -L../../hidapi-externals/fox/lib -Wl,-Bstatic -lFOX-1.6 -Wl,-Bdynamic -lgdi32 -Wl,--enable-auto-import -static-libgcc -static-libstdc++ -lkernel32
+LIBS= -mwindows -L../../hidapi-externals/fox/lib -Wl,-Bstatic -lFOX-1.6 -Wl,-Bdynamic -lgdi32 -Wl,--enable-auto-import -static-libgcc -static-libstdc++ -lkernel32
 
 
 hidapi-testgui: $(OBJS)
diff --git a/src/hidapi/testgui/copy_to_bundle.sh b/src/hidapi/testgui/copy_to_bundle.sh
index f0fc767..ddff64f 100755
--- a/src/hidapi/testgui/copy_to_bundle.sh
+++ b/src/hidapi/testgui/copy_to_bundle.sh
@@ -77,9 +77,10 @@
 }
 
 rm -f $EXEPATH/*
+mkdir -p $EXEPATH
 
 # Copy the binary into the bundle. Use ../libtool to do this if it's
-# available beacuse if $EXE_NAME was built with autotools, it will be
+# 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
diff --git a/src/hidapi/testgui/mac_support.cpp b/src/hidapi/testgui/mac_support.cpp
deleted file mode 100644
index e1e3874..0000000
--- a/src/hidapi/testgui/mac_support.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/*******************************
- Mac support for HID Test GUI
- 
- Alan Ott
- Signal 11 Software
-
- Some of this code is from Apple Documentation, most notably
- http://developer.apple.com/legacy/mac/library/documentation/AppleScript/Conceptual/AppleEvents/AppleEvents.pdf 
-*******************************/
-
-#include <Carbon/Carbon.h>
-#include <fx.h>
-
-
-extern FXMainWindow *g_main_window;
-
-static pascal OSErr HandleQuitMessage(const AppleEvent *theAppleEvent, AppleEvent 
-									  *reply, long handlerRefcon) 
-{
-	puts("Quitting\n");
-	FXApp::instance()->exit();
-	return 0;
-}
-
-static pascal OSErr HandleReopenMessage(const AppleEvent *theAppleEvent, AppleEvent 
-									  *reply, long handlerRefcon) 
-{
-	puts("Showing");
-	g_main_window->show();
-	return 0;
-}
-
-static pascal OSErr HandleWildCardMessage(const AppleEvent *theAppleEvent, AppleEvent 
-									  *reply, long handlerRefcon) 
-{
-	puts("WildCard\n");
-	return 0;
-}
-
-OSStatus AEHandler(EventHandlerCallRef inCaller, EventRef inEvent, void* inRefcon) 
-{ 
-    Boolean     release = false; 
-    EventRecord eventRecord; 
-    OSErr       ignoreErrForThisSample; 
-	
-    // Events of type kEventAppleEvent must be removed from the queue 
-    //  before being passed to AEProcessAppleEvent. 
-    if (IsEventInQueue(GetMainEventQueue(), inEvent)) 
-    { 
-        // RemoveEventFromQueue will release the event, which will 
-        //  destroy it if we don't retain it first. 
-        RetainEvent(inEvent); 
-        release = true; 
-        RemoveEventFromQueue(GetMainEventQueue(), inEvent); 
-    } 
-    // Convert the event ref to the type AEProcessAppleEvent expects. 
-    ConvertEventRefToEventRecord(inEvent, &eventRecord); 
-    ignoreErrForThisSample = AEProcessAppleEvent(&eventRecord); 
-    if (release) 
-        ReleaseEvent(inEvent); 
-    // This Carbon event has been handled, even if no AppleEvent handlers 
-    //  were installed for the Apple event. 
-    return noErr; 
-}
-
-static void HandleEvent(EventRecord *event) 
-{ 
-	//printf("What: %d message %x\n", event->what, event->message);
-	if (event->what == osEvt) {
-		if (((event->message >> 24) & 0xff) == suspendResumeMessage) {
-			if (event->message & resumeFlag) {
-				g_main_window->show();				
-			}
-		}
-	}
-
-#if 0
-    switch (event->what) 
-    { 
-        case mouseDown: 
-            //HandleMouseDown(event); 
-            break; 
-        case keyDown: 
-        case autoKey: 
-            //HandleKeyPress(event); 
-            break; 
-        case kHighLevelEvent: 
-			puts("Calling ProcessAppleEvent\n");
-            AEProcessAppleEvent(event); 
-            break; 
-    } 
-#endif
-} 
-
-void
-init_apple_message_system()
-{
-	OSErr err;
-	static const EventTypeSpec appleEvents[] = 
-	{
-		{ kEventClassAppleEvent, kEventAppleEvent }
-	};
-	
-	/* Install the handler for Apple Events */
-	InstallApplicationEventHandler(NewEventHandlerUPP(AEHandler), 
-	              GetEventTypeCount(appleEvents), appleEvents, 0, NULL); 
-
-	/* Install handlers for the individual Apple Events that come
-	   from the Dock icon: the Reopen (click), and the Quit messages. */
-	err = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, 
-	              NewAEEventHandlerUPP(HandleQuitMessage), 0, false);
-	err = AEInstallEventHandler(kCoreEventClass, kAEReopenApplication, 
-	              NewAEEventHandlerUPP(HandleReopenMessage), 0, false);
-#if 0
-	// Left as an example of a wild card match.
-	err = AEInstallEventHandler(kCoreEventClass, typeWildCard, 
-	              NewAEEventHandlerUPP(HandleWildMessage), 0, false);
-#endif
-}
-
-void
-check_apple_events()
-{
-	RgnHandle       cursorRgn = NULL; 
-	Boolean         gotEvent=TRUE; 
-	EventRecord     event; 
-
-	while (gotEvent) { 
-		gotEvent = WaitNextEvent(everyEvent, &event, 0L/*timeout*/, cursorRgn); 
-		if (gotEvent) { 
-			HandleEvent(&event); 
-		} 
-	}
-}
diff --git a/src/hidapi/testgui/mac_support_cocoa.m b/src/hidapi/testgui/mac_support_cocoa.m
index 75de7e9..1b12163 100644
--- a/src/hidapi/testgui/mac_support_cocoa.m
+++ b/src/hidapi/testgui/mac_support_cocoa.m
@@ -8,10 +8,19 @@
 #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
+@interface MyAppDelegate : NSObject<NSApplicationDelegate>
 {
 } 
 @end
@@ -77,7 +86,7 @@
 
 	NSAutoreleasePool *pool = [NSAutoreleasePool new];
 	while (1) {
-		NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
+		NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
 		                        untilDate:nil
                                         inMode:NSDefaultRunLoopMode
                                         dequeue:YES];
diff --git a/src/hidapi/testgui/start.sh b/src/hidapi/testgui/start.sh
deleted file mode 100755
index 980635d..0000000
--- a/src/hidapi/testgui/start.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/bash
-xterm -e /Users/alan/work/hidapi/testgui/TestGUI.app/Contents/MacOS/tg
diff --git a/src/hidapi/testgui/testgui.sln b/src/hidapi/testgui/testgui.sln
index 35abcec..56be6c6 100644
--- a/src/hidapi/testgui/testgui.sln
+++ b/src/hidapi/testgui/testgui.sln
@@ -1,20 +1,20 @@
-

-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

+
+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
diff --git a/src/hidapi/testgui/testgui.vcproj b/src/hidapi/testgui/testgui.vcproj
index 91be8ee..f6e6c09 100644
--- a/src/hidapi/testgui/testgui.vcproj
+++ b/src/hidapi/testgui/testgui.vcproj
@@ -1,217 +1,217 @@
-<?xml version="1.0" encoding="Windows-1252"?>

-<VisualStudioProject

-	ProjectType="Visual C++"

-	Version="9.00"

-	Name="testgui"

-	ProjectGUID="{08769AC3-785A-4DDC-BFC7-1775414B7AB7}"

-	RootNamespace="testgui"

-	Keyword="Win32Proj"

-	TargetFrameworkVersion="196613"

-	>

-	<Platforms>

-		<Platform

-			Name="Win32"

-		/>

-	</Platforms>

-	<ToolFiles>

-	</ToolFiles>

-	<Configurations>

-		<Configuration

-			Name="Debug|Win32"

-			OutputDirectory="$(SolutionDir)$(ConfigurationName)"

-			IntermediateDirectory="$(ConfigurationName)"

-			ConfigurationType="1"

-			CharacterSet="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				Optimization="0"

-				AdditionalIncludeDirectories="&quot;..\..\hidapi-externals\fox\include&quot;;..\hidapi"

-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"

-				MinimalRebuild="true"

-				BasicRuntimeChecks="3"

-				RuntimeLibrary="3"

-				UsePrecompiledHeader="0"

-				WarningLevel="3"

-				DebugInformationFormat="4"

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="setupapi.lib fox-1.6.lib"

-				OutputFile="$(ProjectName).exe"

-				LinkIncremental="2"

-				AdditionalLibraryDirectories="..\hidapi\objfre_wxp_x86\i386;&quot;..\..\hidapi-externals\fox\lib&quot;"

-				GenerateDebugInformation="true"

-				SubSystem="2"

-				EntryPointSymbol="mainCRTStartup"

-				TargetMachine="1"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCManifestTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCFxCopTool"

-			/>

-			<Tool

-				Name="VCAppVerifierTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-				CommandLine=""

-			/>

-		</Configuration>

-		<Configuration

-			Name="Release|Win32"

-			OutputDirectory="$(SolutionDir)$(ConfigurationName)"

-			IntermediateDirectory="$(ConfigurationName)"

-			ConfigurationType="1"

-			CharacterSet="1"

-			WholeProgramOptimization="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				Optimization="2"

-				EnableIntrinsicFunctions="true"

-				AdditionalIncludeDirectories="&quot;..\..\hidapi-externals\fox\include&quot;;..\hidapi"

-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"

-				RuntimeLibrary="2"

-				EnableFunctionLevelLinking="true"

-				UsePrecompiledHeader="0"

-				WarningLevel="3"

-				DebugInformationFormat="3"

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="setupapi.lib fox-1.6.lib"

-				OutputFile="$(ProjectName).exe"

-				LinkIncremental="1"

-				AdditionalLibraryDirectories="..\hidapi\objfre_wxp_x86\i386;&quot;..\..\hidapi-externals\fox\lib&quot;"

-				GenerateDebugInformation="true"

-				SubSystem="2"

-				OptimizeReferences="2"

-				EnableCOMDATFolding="2"

-				EntryPointSymbol="mainCRTStartup"

-				TargetMachine="1"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCManifestTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCFxCopTool"

-			/>

-			<Tool

-				Name="VCAppVerifierTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-				CommandLine=""

-			/>

-		</Configuration>

-	</Configurations>

-	<References>

-	</References>

-	<Files>

-		<Filter

-			Name="Source Files"

-			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

-			>

-			<File

-				RelativePath="..\windows\hid.c"

-				>

-			</File>

-			<File

-				RelativePath=".\test.cpp"

-				>

-			</File>

-		</Filter>

-		<Filter

-			Name="Header Files"

-			Filter="h;hpp;hxx;hm;inl;inc;xsd"

-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

-			>

-			<File

-				RelativePath="..\hidapi\hidapi.h"

-				>

-			</File>

-		</Filter>

-		<Filter

-			Name="Resource Files"

-			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"

-			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"

-			>

-		</Filter>

-		<File

-			RelativePath=".\ReadMe.txt"

-			>

-		</File>

-	</Files>

-	<Globals>

-	</Globals>

-</VisualStudioProject>

+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="testgui"
+	ProjectGUID="{08769AC3-785A-4DDC-BFC7-1775414B7AB7}"
+	RootNamespace="testgui"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;..\..\hidapi-externals\fox\include&quot;;..\hidapi"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="fox-1.6.lib"
+				OutputFile="$(ProjectName).exe"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="..\hidapi\objfre_wxp_x86\i386;&quot;..\..\hidapi-externals\fox\lib&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				EntryPointSymbol="mainCRTStartup"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				CommandLine=""
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="&quot;..\..\hidapi-externals\fox\include&quot;;..\hidapi"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="fox-1.6.lib"
+				OutputFile="$(ProjectName).exe"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="..\hidapi\objfre_wxp_x86\i386;&quot;..\..\hidapi-externals\fox\lib&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				EntryPointSymbol="mainCRTStartup"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				CommandLine=""
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\windows\hid.c"
+				>
+			</File>
+			<File
+				RelativePath=".\test.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\hidapi\hidapi.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+		<File
+			RelativePath=".\ReadMe.txt"
+			>
+		</File>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/hidapi/udev/69-hid.rules b/src/hidapi/udev/69-hid.rules
new file mode 100644
index 0000000..a27113c
--- /dev/null
+++ b/src/hidapi/udev/69-hid.rules
@@ -0,0 +1,36 @@
+# This is a sample udev file for HIDAPI devices which lets unprivileged
+# users who are physically present at the system (not remote users) access
+# HID devices.
+
+# If you are using the libusb implementation of hidapi (libusb/hid.c), then
+# use something like the following line, substituting the VID and PID with
+# those of your device.
+
+# HIDAPI/libusb
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="003f", TAG+="uaccess"
+
+# If you are using the hidraw implementation (linux/hid.c), then do something
+# like the following, substituting the VID and PID with your device.
+
+# HIDAPI/hidraw
+KERNEL=="hidraw*", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="003f", TAG+="uaccess"
+
+# Once done, optionally rename this file for your application, and drop it into
+# /etc/udev/rules.d/.
+# NOTE: these rules must have priorty before 73-seat-late.rules.
+# (Small discussion/explanation in systemd repo:
+#  https://github.com/systemd/systemd/issues/4288#issuecomment-348166161)
+# for example, name the file /etc/udev/rules.d/70-my-application-hid.rules.
+# Then, replug your device or run:
+# sudo udevadm control --reload-rules && sudo udevadm trigger
+
+# Note that the hexadecimal values for VID and PID are case sensitive and
+# must be lower case.
+
+# TAG+="uaccess" only gives permission to physically present users, which
+# is appropriate in most scenarios. If you require access to the device
+# from a remote session (e.g. over SSH), add
+# GROUP="plugdev", MODE="660"
+# to the end of the udev rule lines, add your user to the plugdev group with:
+# usermod -aG plugdev USERNAME
+# then log out and log back in (or restart the system).
diff --git a/src/hidapi/udev/99-hid.rules b/src/hidapi/udev/99-hid.rules
deleted file mode 100644
index 0385f50..0000000
--- a/src/hidapi/udev/99-hid.rules
+++ /dev/null
@@ -1,33 +0,0 @@
-# This is a sample udev file for HIDAPI devices which changes the permissions
-# to 0666 (world readable/writable) for a specified device on Linux systems.
-
-
-# If you are using the libusb implementation of hidapi (libusb/hid.c), then
-# use something like the following line, substituting the VID and PID with
-# those of your device. Note that for kernels before 2.6.24, you will need
-# to substitute "usb" with "usb_device". It shouldn't hurt to use two lines
-# (one each way) for compatibility with older systems.
-
-# HIDAPI/libusb
-SUBSYSTEM=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="003f", MODE="0666"
-
-
-# If you are using the hidraw implementation (linux/hid.c), then do something
-# like the following, substituting the VID and PID with your device. Busnum 1
-# is USB.
-
-# HIDAPI/hidraw
-KERNEL=="hidraw*", ATTRS{busnum}=="1", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="003f", MODE="0666"
-
-# Once done, optionally rename this file for your device, and drop it into
-# /etc/udev/rules.d and unplug and re-plug your device. This is all that is
-# necessary to see the new permissions. Udev does not have to be restarted.
-
-# Note that the hexadecimal values for VID and PID are case sensitive and
-# must be lower case.
-
-# If you think permissions of 0666 are too loose, then see:
-# http://reactivated.net/writing_udev_rules.html for more information on finer
-# grained permission setting. For example, it might be sufficient to just
-# set the group or user owner for specific devices (for example the plugdev
-# group on some systems).
diff --git a/src/hidapi/windows/.gitignore b/src/hidapi/windows/.gitignore
new file mode 100644
index 0000000..c2ad395
--- /dev/null
+++ b/src/hidapi/windows/.gitignore
@@ -0,0 +1,17 @@
+Debug
+Release
+.vs/
+*.exp
+*.ilk
+*.lib
+*.suo
+*.vcproj.*
+*.vcxproj.*
+*.ncb
+*.suo
+*.dll
+*.pdb
+.deps
+.libs
+*.lo
+*.la
diff --git a/src/hidapi/windows/CMakeLists.txt b/src/hidapi/windows/CMakeLists.txt
new file mode 100644
index 0000000..c8228bc
--- /dev/null
+++ b/src/hidapi/windows/CMakeLists.txt
@@ -0,0 +1,63 @@
+list(APPEND HIDAPI_PUBLIC_HEADERS "hidapi_winapi.h")
+
+set(SOURCES
+    hid.c
+    hidapi_cfgmgr32.h
+    hidapi_descriptor_reconstruct.c
+    hidapi_descriptor_reconstruct.h
+    hidapi_hidclass.h
+    hidapi_hidpi.h
+    hidapi_hidsdi.h
+)
+
+if(BUILD_SHARED_LIBS)
+    list(APPEND SOURCES hidapi.rc)
+endif()
+
+add_library(hidapi_winapi
+    ${HIDAPI_PUBLIC_HEADERS}
+    ${SOURCES}
+)
+target_link_libraries(hidapi_winapi
+    PUBLIC hidapi_include
+)
+
+if(NOT BUILD_SHARED_LIBS)
+    target_compile_definitions(hidapi_winapi
+        # prevent marking functions as __declspec(dllexport) for static library build
+        # #480: this should be refactored for v1.0
+        PUBLIC HID_API_NO_EXPORT_DEFINE
+    )
+endif()
+
+set_target_properties(hidapi_winapi
+    PROPERTIES
+        EXPORT_NAME "winapi"
+        OUTPUT_NAME "hidapi"
+        VERSION ${PROJECT_VERSION}
+        PUBLIC_HEADER "${HIDAPI_PUBLIC_HEADERS}"
+)
+
+# compatibility with find_package()
+add_library(hidapi::winapi ALIAS hidapi_winapi)
+# compatibility with raw library link
+add_library(hidapi ALIAS hidapi_winapi)
+
+if(HIDAPI_INSTALL_TARGETS)
+    install(TARGETS hidapi_winapi EXPORT hidapi
+        RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
+        LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+        ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+        PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/hidapi"
+    )
+endif()
+
+hidapi_configure_pc("${PROJECT_ROOT}/pc/hidapi.pc.in")
+
+if(HIDAPI_WITH_TESTS)
+     add_subdirectory(test)
+endif()
+
+if(DEFINED HIDAPI_BUILD_PP_DATA_DUMP AND HIDAPI_BUILD_PP_DATA_DUMP)
+    add_subdirectory(pp_data_dump)
+endif()
diff --git a/src/hidapi/windows/Makefile.am b/src/hidapi/windows/Makefile.am
index 97e261a..2ea5c0d 100644
--- a/src/hidapi/windows/Makefile.am
+++ b/src/hidapi/windows/Makefile.am
@@ -8,7 +8,6 @@
 hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h
 
 EXTRA_DIST = \
-  ddk_build \
   hidapi.vcproj \
   hidtest.vcproj \
   Makefile-manual \
diff --git a/src/hidapi/windows/Makefile.mingw b/src/hidapi/windows/Makefile.mingw
index b800004..857e4fb 100644
--- a/src/hidapi/windows/Makefile.mingw
+++ b/src/hidapi/windows/Makefile.mingw
@@ -9,16 +9,14 @@
 all: hidtest libhidapi.dll
 
 CC=gcc
-CXX=g++
-COBJS=hid.o
-CPPOBJS=../hidtest/hidtest.o
-OBJS=$(COBJS) $(CPPOBJS)
-CFLAGS=-I../hidapi -g -c
-LIBS= -lsetupapi
-DLL_LDFLAGS = -mwindows -lsetupapi
+COBJS=hid.o ../hidtest/test.o
+OBJS=$(COBJS)
+CFLAGS=-I../hidapi -I. -g -c
+LIBS=
+DLL_LDFLAGS = -mwindows
 
 hidtest: $(OBJS)
-	g++ -g $^ $(LIBS) -o hidtest
+	$(CC) -g $^ $(LIBS) -o hidtest
 
 libhidapi.dll: $(OBJS)
 	$(CC) -g $^ $(DLL_LDFLAGS) -o libhidapi.dll
@@ -26,9 +24,6 @@
 $(COBJS): %.o: %.c
 	$(CC) $(CFLAGS) $< -o $@
 
-$(CPPOBJS): %.o: %.cpp
-	$(CXX) $(CFLAGS) $< -o $@
-
 clean:
 	rm *.o ../hidtest/*.o hidtest.exe
 
diff --git a/src/hidapi/windows/ddk_build/hidapi.def b/src/hidapi/windows/ddk_build/hidapi.def
deleted file mode 100644
index 05e35af..0000000
--- a/src/hidapi/windows/ddk_build/hidapi.def
+++ /dev/null
@@ -1,17 +0,0 @@
-LIBRARY   hidapi
-EXPORTS
-   hid_open    @1
-   hid_write   @2
-   hid_read    @3
-   hid_close   @4
-   hid_get_product_string @5
-   hid_get_manufacturer_string @6
-   hid_get_serial_number_string @7
-   hid_get_indexed_string @8
-   hid_error @9
-   hid_set_nonblocking @10
-   hid_enumerate @11
-   hid_open_path @12
-   hid_send_feature_report @13
-   hid_get_feature_report @14
-   
\ No newline at end of file
diff --git a/src/hidapi/windows/ddk_build/makefile b/src/hidapi/windows/ddk_build/makefile
deleted file mode 100644
index 637f712..0000000
--- a/src/hidapi/windows/ddk_build/makefile
+++ /dev/null
@@ -1,49 +0,0 @@
-#############################################################################
-#
-#               Copyright (C) Microsoft Corporation 1995, 1996
-#       All Rights Reserved.
-#
-#       MAKEFILE for HID directory
-#
-#############################################################################
-
-!IFDEF WIN95_BUILD
-
-ROOT=..\..\..\..
-
-VERSIONLIST = debug retail
-IS_32 = TRUE
-IS_SDK = TRUE
-IS_PRIVATE = TRUE
-IS_SDK = TRUE
-IS_DDK = TRUE
-WIN32 = TRUE
-COMMONMKFILE = hidapi.mk
-
-!include $(ROOT)\dev\master.mk
-
-
-!ELSE
-
-#
-# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
-# file to this component.  This file merely indirects to the real make file
-# that is shared by all the driver components of the Windows NT DDK
-#
-
-!IF DEFINED(_NT_TARGET_VERSION)
-!	IF $(_NT_TARGET_VERSION)>=0x501
-!		INCLUDE $(NTMAKEENV)\makefile.def
-!	ELSE
-#               Only warn once per directory
-!               INCLUDE $(NTMAKEENV)\makefile.plt
-!               IF "$(BUILD_PASS)"=="PASS1"
-!		    message BUILDMSG: Warning : The sample "$(MAKEDIR)" is not valid for the current OS target.
-!               ENDIF
-!	ENDIF
-!ELSE
-!	INCLUDE $(NTMAKEENV)\makefile.def
-!ENDIF
-
-!ENDIF
-
diff --git a/src/hidapi/windows/ddk_build/sources b/src/hidapi/windows/ddk_build/sources
deleted file mode 100644
index 7f06a09..0000000
--- a/src/hidapi/windows/ddk_build/sources
+++ /dev/null
@@ -1,23 +0,0 @@
-TARGETNAME=hidapi
-TARGETTYPE=DYNLINK
-UMTYPE=console
-UMENTRY=main
-
-MSC_WARNING_LEVEL=/W3 /WX
-
-TARGETLIBS=$(SDK_LIB_PATH)\hid.lib \
-           $(SDK_LIB_PATH)\setupapi.lib \
-           $(SDK_LIB_PATH)\kernel32.lib \
-           $(SDK_LIB_PATH)\comdlg32.lib
-
-USE_MSVCRT=1
-
-INCLUDES= ..\..\hidapi
-SOURCES= ..\hid.c \
-
-
-TARGET_DESTINATION=retail
-
-MUI=0
-MUI_COMMENT="HID Interface DLL"
-
diff --git a/src/hidapi/windows/hid.c b/src/hidapi/windows/hid.c
index 7a292a4..6999691 100644
--- a/src/hidapi/windows/hid.c
+++ b/src/hidapi/windows/hid.c
@@ -5,9 +5,9 @@
  Alan Ott
  Signal 11 Software
 
- 8/22/2009
+ libusb/hidapi Team
 
- Copyright 2009, All Rights Reserved.
+ Copyright 2022, All Rights Reserved.
 
  At the discretion of the user of this library,
  this software may be licensed under the terms of the
@@ -19,98 +19,61 @@
  code repository located at:
         https://github.com/libusb/hidapi .
 ********************************************************/
-#include "SDL_internal.h"
 
+#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
+/* Do not warn about wcsncpy usage.
+   https://docs.microsoft.com/cpp/c-runtime-library/security-features-in-the-crt */
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hidapi_winapi.h"
 
 #include <windows.h>
 
-#ifndef _WIN32_WINNT_WIN8
-#define _WIN32_WINNT_WIN8   0x0602
-#endif
-
-#if 0 /* can cause redefinition errors on some toolchains */
-#ifdef __MINGW32__
-#include <ntdef.h>
-#include <winbase.h>
-#endif
-
-#ifdef __CYGWIN__
-#include <ntdef.h>
-#define _wcsdup wcsdup
-#endif
-#endif /* */
-
 #ifndef _NTDEF_
 typedef LONG NTSTATUS;
 #endif
 
-/* The maximum number of characters that can be passed into the
-   HidD_Get*String() functions without it failing.*/
-#define MAX_STRING_WCHARS 0xFFF
+#ifdef __MINGW32__
+#include <ntdef.h>
+#include <winbase.h>
+#define WC_ERR_INVALID_CHARS 0x00000080
+#endif
+
+#ifdef __CYGWIN__
+#include <ntdef.h>
+#include <wctype.h>
+#define _wcsdup wcsdup
+#endif
 
 /*#define HIDAPI_USE_DDK*/
 
-/* The timeout in milliseconds for waiting on WriteFile to
-   complete in hid_write. The longest observed time to do a output
-   report that we've seen is ~200-250ms so let's double that */
-#define HID_WRITE_TIMEOUT_MILLISECONDS 500
+#include "hidapi_cfgmgr32.h"
+#include "hidapi_hidclass.h"
+#include "hidapi_hidsdi.h"
 
-/* We will only enumerate devices that match these usages */
-#define USAGE_PAGE_GENERIC_DESKTOP 0x0001
-#define USAGE_JOYSTICK 0x0004
-#define USAGE_GAMEPAD 0x0005
-#define USAGE_MULTIAXISCONTROLLER 0x0008
-#define USB_VENDOR_VALVE 0x28de
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-	#include <setupapi.h>
-	#include <winioctl.h>
-	#include <devpropdef.h>
-	#include "hidapi_cfgmgr32.h"
-	#include "hidapi_hidclass.h"
-	#include "hidapi_hidsdi.h"
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-#include "../hidapi/hidapi.h"
-
-/*#include <stdio.h>*/
-/*#include <stdlib.h>*/
-
-/* SDL C runtime functions */
-
-#define calloc SDL_calloc
-#define free SDL_free
-#define malloc SDL_malloc
-#define memcpy SDL_memcpy
-#define memset SDL_memset
-#define strcmp SDL_strcmp
-#define strlen SDL_strlen
-#define strstr SDL_strstr
-#define strtol SDL_strtol
-#define towupper SDL_toupper
-#define wcscmp SDL_wcscmp
-#define wcslen SDL_wcslen
-#define _wcsdup SDL_wcsdup
-#define wcsstr SDL_wcsstr
-
-
+#ifdef MIN
 #undef MIN
+#endif
 #define MIN(x,y) ((x) < (y)? (x): (y))
 
-#ifdef _MSC_VER
-	/* Yes, we have some unreferenced formal parameters */
-	#pragma warning(disable:4100)
-#endif
+/* MAXIMUM_USB_STRING_LENGTH from usbspec.h is 255 */
+/* BLUETOOTH_DEVICE_NAME_SIZE from bluetoothapis.h is 256 */
+#define MAX_STRING_WCHARS 256
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
+static struct hid_api_version api_version = {
+	.major = HID_API_VERSION_MAJOR,
+	.minor = HID_API_VERSION_MINOR,
+	.patch = HID_API_VERSION_PATCH
+};
 
 #ifndef HIDAPI_USE_DDK
 /* Since we're not building with the DDK, and the HID header
@@ -131,7 +94,6 @@
 static HidD_FreePreparsedData_ HidD_FreePreparsedData;
 static HidP_GetCaps_ HidP_GetCaps;
 static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers;
-static HidD_SetOutputReport_ HidD_SetOutputReport;
 
 static CM_Locate_DevNodeW_ CM_Locate_DevNodeW = NULL;
 static CM_Get_Parent_ CM_Get_Parent = NULL;
@@ -144,7 +106,7 @@
 static HMODULE cfgmgr32_lib_handle = NULL;
 static BOOLEAN hidapi_initialized = FALSE;
 
-static void free_library_handles(void)
+static void free_library_handles()
 {
 	if (hid_lib_handle)
 		FreeLibrary(hid_lib_handle);
@@ -154,11 +116,7 @@
 	cfgmgr32_lib_handle = NULL;
 }
 
-#ifdef __GNUC__
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wcast-function-type"
-#endif
-static int lookup_functions(void)
+static int lookup_functions()
 {
 	hid_lib_handle = LoadLibraryW(L"hid.dll");
 	if (hid_lib_handle == NULL) {
@@ -170,6 +128,10 @@
 		goto err;
 	}
 
+#if defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
 #define RESOLVE(lib_handle, x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) goto err;
 
 	RESOLVE(hid_lib_handle, HidD_GetHidGuid);
@@ -185,7 +147,6 @@
 	RESOLVE(hid_lib_handle, HidD_FreePreparsedData);
 	RESOLVE(hid_lib_handle, HidP_GetCaps);
 	RESOLVE(hid_lib_handle, HidD_SetNumInputBuffers);
-	RESOLVE(hid_lib_handle, HidD_SetOutputReport);
 
 	RESOLVE(cfgmgr32_lib_handle, CM_Locate_DevNodeW);
 	RESOLVE(cfgmgr32_lib_handle, CM_Get_Parent);
@@ -195,6 +156,9 @@
 	RESOLVE(cfgmgr32_lib_handle, CM_Get_Device_Interface_ListW);
 
 #undef RESOLVE
+#if defined(__GNUC__)
+# pragma GCC diagnostic pop
+#endif
 
 	return 0;
 
@@ -202,9 +166,6 @@
 	free_library_handles();
 	return -1;
 }
-#ifdef __GNUC__
-# pragma GCC diagnostic pop
-#endif
 
 #endif /* HIDAPI_USE_DDK */
 
@@ -212,50 +173,41 @@
 		HANDLE device_handle;
 		BOOL blocking;
 		USHORT output_report_length;
+		unsigned char *write_buf;
 		size_t input_report_length;
-		void *last_error_str;
-		DWORD last_error_num;
+		USHORT feature_report_length;
+		unsigned char *feature_buf;
+		wchar_t *last_error_str;
 		BOOL read_pending;
 		char *read_buf;
 		OVERLAPPED ol;
 		OVERLAPPED write_ol;
-		BOOL use_hid_write_output_report;
+		struct hid_device_info* device_info;
 };
 
-static BOOL IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
-{
-	OSVERSIONINFOEXW osvi;
-	DWORDLONG const dwlConditionMask = VerSetConditionMask(
-		VerSetConditionMask(
-			VerSetConditionMask(
-				0, VER_MAJORVERSION, VER_GREATER_EQUAL ),
-			VER_MINORVERSION, VER_GREATER_EQUAL ),
-		VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL );
-
-	memset(&osvi, 0, sizeof(osvi));
-	osvi.dwOSVersionInfoSize = sizeof( osvi );
-	osvi.dwMajorVersion = wMajorVersion;
-	osvi.dwMinorVersion = wMinorVersion;
-	osvi.wServicePackMajor = wServicePackMajor;
-
-	return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
-}
-
-static hid_device *new_hid_device(void)
+static hid_device *new_hid_device()
 {
 	hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
+
+	if (dev == NULL) {
+		return NULL;
+	}
+
 	dev->device_handle = INVALID_HANDLE_VALUE;
 	dev->blocking = TRUE;
 	dev->output_report_length = 0;
+	dev->write_buf = NULL;
 	dev->input_report_length = 0;
+	dev->feature_report_length = 0;
+	dev->feature_buf = NULL;
 	dev->last_error_str = NULL;
-	dev->last_error_num = 0;
 	dev->read_pending = FALSE;
 	dev->read_buf = NULL;
 	memset(&dev->ol, 0, sizeof(dev->ol));
 	dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
 	memset(&dev->write_ol, 0, sizeof(dev->write_ol));
-	dev->write_ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
+	dev->write_ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsignaled*/, NULL);
+	dev->device_info = NULL;
 
 	return dev;
 }
@@ -265,54 +217,123 @@
 	CloseHandle(dev->ol.hEvent);
 	CloseHandle(dev->write_ol.hEvent);
 	CloseHandle(dev->device_handle);
-	LocalFree(dev->last_error_str);
+	free(dev->last_error_str);
+	dev->last_error_str = NULL;
+	free(dev->write_buf);
+	free(dev->feature_buf);
 	free(dev->read_buf);
+	hid_free_enumeration(dev->device_info);
 	free(dev);
 }
 
-static void register_error(hid_device *device, const char *op)
+static void register_winapi_error_to_buffer(wchar_t **error_buffer, const WCHAR *op)
 {
-	WCHAR *ptr, *msg;
+	free(*error_buffer);
+	*error_buffer = NULL;
 
-	DWORD count = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-		FORMAT_MESSAGE_FROM_SYSTEM |
-		FORMAT_MESSAGE_IGNORE_INSERTS,
-		NULL,
-		GetLastError(),
-		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-		(LPWSTR)&msg, 0/*sz*/,
-		NULL);
-	if (!count)
+	/* Only clear out error messages if NULL is passed into op */
+	if (!op) {
 		return;
+	}
+
+	WCHAR system_err_buf[1024];
+	DWORD error_code = GetLastError();
+
+	DWORD system_err_len = FormatMessageW(
+		FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+		NULL,
+		error_code,
+		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+		system_err_buf, ARRAYSIZE(system_err_buf),
+		NULL);
+
+	DWORD op_len = (DWORD)wcslen(op);
+
+	DWORD op_prefix_len =
+		op_len
+		+ 15 /*: (0x00000000) */
+		;
+	DWORD msg_len =
+		+ op_prefix_len
+		+ system_err_len
+		;
+
+	*error_buffer = (WCHAR *)calloc(msg_len + 1, sizeof (WCHAR));
+	WCHAR *msg = *error_buffer;
+
+	if (!msg)
+		return;
+
+	int printf_written = swprintf(msg, msg_len + 1, L"%.*ls: (0x%08X) %.*ls", (int)op_len, op, error_code, (int)system_err_len, system_err_buf);
+
+	if (printf_written < 0)
+	{
+		/* Highly unlikely */
+		msg[0] = L'\0';
+		return;
+	}
 
 	/* Get rid of the CR and LF that FormatMessage() sticks at the
 	   end of the message. Thanks Microsoft! */
-	ptr = msg;
-	while (*ptr) {
-		if (*ptr == '\r') {
-			*ptr = 0x0000;
-			break;
-		}
-		ptr++;
+	while(msg[msg_len-1] == L'\r' || msg[msg_len-1] == L'\n' || msg[msg_len-1] == L' ')
+	{
+		msg[msg_len-1] = L'\0';
+		msg_len--;
 	}
-
-	/* Store the message off in the Device entry so that
-	   the hid_error() function can pick it up. */
-	LocalFree(device->last_error_str);
-	device->last_error_str = msg;
 }
 
-static HANDLE open_device(const char *path, BOOL enumerate, BOOL bExclusive )
+#if defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Warray-bounds"
+#endif
+/* A bug in GCC/mingw gives:
+ * error: array subscript 0 is outside array bounds of 'wchar_t *[0]' {aka 'short unsigned int *[]'} [-Werror=array-bounds]
+ * |         free(*error_buffer);
+ * Which doesn't make sense in this context. */
+
+static void register_string_error_to_buffer(wchar_t **error_buffer, const WCHAR *string_error)
+{
+	free(*error_buffer);
+	*error_buffer = NULL;
+
+	if (string_error) {
+		*error_buffer = _wcsdup(string_error);
+	}
+}
+
+#if defined(__GNUC__)
+# pragma GCC diagnostic pop
+#endif
+
+static void register_winapi_error(hid_device *dev, const WCHAR *op)
+{
+	register_winapi_error_to_buffer(&dev->last_error_str, op);
+}
+
+static void register_string_error(hid_device *dev, const WCHAR *string_error)
+{
+	register_string_error_to_buffer(&dev->last_error_str, string_error);
+}
+
+static wchar_t *last_global_error_str = NULL;
+
+static void register_global_winapi_error(const WCHAR *op)
+{
+	register_winapi_error_to_buffer(&last_global_error_str, op);
+}
+
+static void register_global_error(const WCHAR *string_error)
+{
+	register_string_error_to_buffer(&last_global_error_str, string_error);
+}
+
+static HANDLE open_device(const wchar_t *path, BOOL open_rw)
 {
 	HANDLE handle;
-	// Opening with access 0 causes keyboards to stop responding in some system configurations
-	// http://steamcommunity.com/discussions/forum/1/1843493219428923893
-	// Thanks to co-wie (Ka-wei Low <kawei@mac.com>) for help narrowing down the problem on his system
-	//DWORD desired_access = (enumerate)? 0: (GENERIC_WRITE | GENERIC_READ);
-	DWORD desired_access = ( GENERIC_WRITE | GENERIC_READ );
-	DWORD share_mode = bExclusive ? 0 : ( FILE_SHARE_READ | FILE_SHARE_WRITE );
+	DWORD desired_access = (open_rw)? (GENERIC_WRITE | GENERIC_READ): 0;
+	DWORD share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
 
-	handle = CreateFileA(path,
+	handle = CreateFileW(path,
 		desired_access,
 		share_mode,
 		NULL,
@@ -323,11 +344,23 @@
 	return handle;
 }
 
+HID_API_EXPORT const struct hid_api_version* HID_API_CALL hid_version(void)
+{
+	return &api_version;
+}
+
+HID_API_EXPORT const char* HID_API_CALL hid_version_str(void)
+{
+	return HID_API_VERSION_STR;
+}
+
 int HID_API_EXPORT hid_init(void)
 {
+	register_global_error(NULL);
 #ifndef HIDAPI_USE_DDK
 	if (!hidapi_initialized) {
 		if (lookup_functions() < 0) {
+			register_global_winapi_error(L"resolve DLL functions");
 			return -1;
 		}
 		hidapi_initialized = TRUE;
@@ -342,6 +375,7 @@
 	free_library_handles();
 	hidapi_initialized = FALSE;
 #endif
+	register_global_error(NULL);
 	return 0;
 }
 
@@ -387,65 +421,178 @@
 	return property_value;
 }
 
-static void hid_internal_get_ble_info(struct hid_device_info* dev, DEVINST dev_node)
+static void hid_internal_towupper(wchar_t* string)
 {
-	wchar_t *manufacturer_string, *serial_number, *product_string;
-	/* Manufacturer String */
-	manufacturer_string = hid_internal_get_devnode_property(dev_node, (const DEVPROPKEY*)&PKEY_DeviceInterface_Bluetooth_Manufacturer, DEVPROP_TYPE_STRING);
-	if (manufacturer_string) {
-		free(dev->manufacturer_string);
-		dev->manufacturer_string = manufacturer_string;
-	}
-
-	/* Serial Number String (MAC Address) */
-	serial_number = hid_internal_get_devnode_property(dev_node, (const DEVPROPKEY*)&PKEY_DeviceInterface_Bluetooth_DeviceAddress, DEVPROP_TYPE_STRING);
-	if (serial_number) {
-		free(dev->serial_number);
-		dev->serial_number = serial_number;
-	}
-
-	/* Get devnode grandparent to reach out Bluetooth LE device node */
-	if (CM_Get_Parent(&dev_node, dev_node, 0) != CR_SUCCESS)
-		return;
-
-	/* Product String */
-	product_string = hid_internal_get_devnode_property(dev_node, &DEVPKEY_NAME, DEVPROP_TYPE_STRING);
-	if (product_string) {
-		free(dev->product_string);
-		dev->product_string = product_string;
-	}
+	for (wchar_t* p = string; *p; ++p) *p = towupper(*p);
 }
 
-#if 0
-/* USB Device Interface Number.
-   It can be parsed out of the Hardware ID if a USB device is has multiple interfaces (composite device).
-   See https://docs.microsoft.com/windows-hardware/drivers/hid/hidclass-hardware-ids-for-top-level-collections
-   and https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers
-
-   hardware_id is always expected to be uppercase.
-*/
-static int hid_internal_get_interface_number(const wchar_t* hardware_id)
+static int hid_internal_extract_int_token_value(wchar_t* string, const wchar_t* token)
 {
-	int interface_number;
-	wchar_t *startptr, *endptr;
-	const wchar_t *interface_token = L"&MI_";
+	int token_value;
+	wchar_t* startptr, * endptr;
 
-	startptr = wcsstr(hardware_id, interface_token);
+	startptr = wcsstr(string, token);
 	if (!startptr)
 		return -1;
 
-	startptr += wcslen(interface_token);
-	interface_number = wcstol(startptr, &endptr, 16);
+	startptr += wcslen(token);
+	token_value = wcstol(startptr, &endptr, 16);
 	if (endptr == startptr)
 		return -1;
 
-	return interface_number;
+	return token_value;
+}
+
+static void hid_internal_get_usb_info(struct hid_device_info* dev, DEVINST dev_node)
+{
+	wchar_t *device_id = NULL, *hardware_ids = NULL;
+
+	device_id = hid_internal_get_devnode_property(dev_node, &DEVPKEY_Device_InstanceId, DEVPROP_TYPE_STRING);
+	if (!device_id)
+		goto end;
+
+	/* Normalize to upper case */
+	hid_internal_towupper(device_id);
+
+	/* Check for Xbox Common Controller class (XUSB) device.
+	   https://docs.microsoft.com/windows/win32/xinput/directinput-and-xusb-devices
+	   https://docs.microsoft.com/windows/win32/xinput/xinput-and-directinput
+	*/
+	if (hid_internal_extract_int_token_value(device_id, L"IG_") != -1) {
+		/* Get devnode parent to reach out USB device. */
+		if (CM_Get_Parent(&dev_node, dev_node, 0) != CR_SUCCESS)
+			goto end;
+	}
+
+	/* Get the hardware ids from devnode */
+	hardware_ids = hid_internal_get_devnode_property(dev_node, &DEVPKEY_Device_HardwareIds, DEVPROP_TYPE_STRING_LIST);
+	if (!hardware_ids)
+		goto end;
+
+	/* Get additional information from USB device's Hardware ID
+	   https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers
+	   https://docs.microsoft.com/windows-hardware/drivers/usbcon/enumeration-of-interfaces-not-grouped-in-collections
+	*/
+	for (wchar_t* hardware_id = hardware_ids; *hardware_id; hardware_id += wcslen(hardware_id) + 1) {
+		/* Normalize to upper case */
+		hid_internal_towupper(hardware_id);
+
+		if (dev->release_number == 0) {
+			/* USB_DEVICE_DESCRIPTOR.bcdDevice value. */
+			int release_number = hid_internal_extract_int_token_value(hardware_id, L"REV_");
+			if (release_number != -1) {
+				dev->release_number = (unsigned short)release_number;
+			}
+		}
+
+		if (dev->interface_number == -1) {
+			/* USB_INTERFACE_DESCRIPTOR.bInterfaceNumber value. */
+			int interface_number = hid_internal_extract_int_token_value(hardware_id, L"MI_");
+			if (interface_number != -1) {
+				dev->interface_number = interface_number;
+			}
+		}
+	}
+
+	/* Try to get USB device manufacturer string if not provided by HidD_GetManufacturerString. */
+	if (wcslen(dev->manufacturer_string) == 0) {
+		wchar_t* manufacturer_string = hid_internal_get_devnode_property(dev_node, &DEVPKEY_Device_Manufacturer, DEVPROP_TYPE_STRING);
+		if (manufacturer_string) {
+			free(dev->manufacturer_string);
+			dev->manufacturer_string = manufacturer_string;
+		}
+	}
+
+	/* Try to get USB device serial number if not provided by HidD_GetSerialNumberString. */
+	if (wcslen(dev->serial_number) == 0) {
+		DEVINST usb_dev_node = dev_node;
+		if (dev->interface_number != -1) {
+			/* Get devnode parent to reach out composite parent USB device.
+			   https://docs.microsoft.com/windows-hardware/drivers/usbcon/enumeration-of-the-composite-parent-device
+			*/
+			if (CM_Get_Parent(&usb_dev_node, dev_node, 0) != CR_SUCCESS)
+				goto end;
+		}
+
+		/* Get the device id of the USB device. */
+		free(device_id);
+		device_id = hid_internal_get_devnode_property(usb_dev_node, &DEVPKEY_Device_InstanceId, DEVPROP_TYPE_STRING);
+		if (!device_id)
+			goto end;
+
+		/* Extract substring after last '\\' of Instance ID.
+		   For USB devices it may contain device's serial number.
+		   https://docs.microsoft.com/windows-hardware/drivers/install/instance-ids
+		*/
+		for (wchar_t *ptr = device_id + wcslen(device_id); ptr > device_id; --ptr) {
+			/* Instance ID is unique only within the scope of the bus.
+			   For USB devices it means that serial number is not available. Skip. */
+			if (*ptr == L'&')
+				break;
+
+			if (*ptr == L'\\') {
+				free(dev->serial_number);
+				dev->serial_number = _wcsdup(ptr + 1);
+				break;
+			}
+		}
+	}
+
+	/* If we can't get the interface number, it means that there is only one interface. */
+	if (dev->interface_number == -1)
+		dev->interface_number = 0;
+
+end:
+	free(device_id);
+	free(hardware_ids);
+}
+
+/* HidD_GetProductString/HidD_GetManufacturerString/HidD_GetSerialNumberString is not working for BLE HID devices
+   Request this info via dev node properties instead.
+   https://docs.microsoft.com/answers/questions/401236/hidd-getproductstring-with-ble-hid-device.html
+*/
+static void hid_internal_get_ble_info(struct hid_device_info* dev, DEVINST dev_node)
+{
+	if (wcslen(dev->manufacturer_string) == 0) {
+		/* Manufacturer Name String (UUID: 0x2A29) */
+		wchar_t* manufacturer_string = hid_internal_get_devnode_property(dev_node, (const DEVPROPKEY*)&PKEY_DeviceInterface_Bluetooth_Manufacturer, DEVPROP_TYPE_STRING);
+		if (manufacturer_string) {
+			free(dev->manufacturer_string);
+			dev->manufacturer_string = manufacturer_string;
+		}
+	}
+
+	if (wcslen(dev->serial_number) == 0) {
+		/* Serial Number String (UUID: 0x2A25) */
+		wchar_t* serial_number = hid_internal_get_devnode_property(dev_node, (const DEVPROPKEY*)&PKEY_DeviceInterface_Bluetooth_DeviceAddress, DEVPROP_TYPE_STRING);
+		if (serial_number) {
+			free(dev->serial_number);
+			dev->serial_number = serial_number;
+		}
+	}
+
+	if (wcslen(dev->product_string) == 0) {
+		/* Model Number String (UUID: 0x2A24) */
+		wchar_t* product_string = hid_internal_get_devnode_property(dev_node, (const DEVPROPKEY*)&PKEY_DeviceInterface_Bluetooth_ModelNumber, DEVPROP_TYPE_STRING);
+		if (!product_string) {
+			DEVINST parent_dev_node = 0;
+			/* Fallback: Get devnode grandparent to reach out Bluetooth LE device node */
+			if (CM_Get_Parent(&parent_dev_node, dev_node, 0) == CR_SUCCESS) {
+				/* Device Name (UUID: 0x2A00) */
+				product_string = hid_internal_get_devnode_property(parent_dev_node, &DEVPKEY_NAME, DEVPROP_TYPE_STRING);
+			}
+		}
+
+		if (product_string) {
+			free(dev->product_string);
+			dev->product_string = product_string;
+		}
+	}
 }
 
 static void hid_internal_get_info(const wchar_t* interface_path, struct hid_device_info* dev)
 {
-	wchar_t *device_id = NULL, *compatible_ids = NULL, *hardware_ids = NULL;
-	wchar_t *id;
+	wchar_t *device_id = NULL, *compatible_ids = NULL;
 	CONFIGRET cr;
 	DEVINST dev_node;
 
@@ -459,23 +606,6 @@
 	if (cr != CR_SUCCESS)
 		goto end;
 
-	/* Get the hardware ids from devnode */
-	hardware_ids = hid_internal_get_devnode_property(dev_node, &DEVPKEY_Device_HardwareIds, DEVPROP_TYPE_STRING_LIST);
-	if (!hardware_ids)
-		goto end;
-
-	/* Search for interface number in hardware ids */
-	for (id = hardware_ids; *id; id += wcslen(id) + 1) {
-		/* Normalize to upper case */
-		wchar_t* p = id;
-		for (; *p; ++p) *p = towupper(*p);
-
-		dev->interface_number = hid_internal_get_interface_number(id);
-
-		if (dev->interface_number != -1)
-			break;
-	}
-
 	/* Get devnode parent */
 	cr = CM_Get_Parent(&dev_node, dev_node, 0);
 	if (cr != CR_SUCCESS)
@@ -487,54 +617,49 @@
 		goto end;
 
 	/* Now we can parse parent's compatible IDs to find out the device bus type */
-	for (id = compatible_ids; *id; id += wcslen(id) + 1) {
+	for (wchar_t* compatible_id = compatible_ids; *compatible_id; compatible_id += wcslen(compatible_id) + 1) {
 		/* Normalize to upper case */
-		wchar_t* p = id;
-		for (; *p; ++p) *p = towupper(*p);
+		hid_internal_towupper(compatible_id);
 
 		/* USB devices
 		   https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support
 		   https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers */
-		if (wcsstr(id, L"USB") != NULL) {
+		if (wcsstr(compatible_id, L"USB") != NULL) {
 			dev->bus_type = HID_API_BUS_USB;
+			hid_internal_get_usb_info(dev, dev_node);
 			break;
 		}
 
 		/* Bluetooth devices
 		   https://docs.microsoft.com/windows-hardware/drivers/bluetooth/installing-a-bluetooth-device */
-		if (wcsstr(id, L"BTHENUM") != NULL) {
+		if (wcsstr(compatible_id, L"BTHENUM") != NULL) {
 			dev->bus_type = HID_API_BUS_BLUETOOTH;
 			break;
 		}
 
 		/* Bluetooth LE devices */
-		if (wcsstr(id, L"BTHLEDEVICE") != NULL) {
-			/* HidD_GetProductString/HidD_GetManufacturerString/HidD_GetSerialNumberString is not working for BLE HID devices
-			   Request this info via dev node properties instead.
-			   https://docs.microsoft.com/answers/questions/401236/hidd-getproductstring-with-ble-hid-device.html */
-			hid_internal_get_ble_info(dev, dev_node);
-
+		if (wcsstr(compatible_id, L"BTHLEDEVICE") != NULL) {
 			dev->bus_type = HID_API_BUS_BLUETOOTH;
+			hid_internal_get_ble_info(dev, dev_node);
 			break;
 		}
 
 		/* I2C devices
 		   https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support-and-power-management */
-		if (wcsstr(id, L"PNP0C50") != NULL) {
+		if (wcsstr(compatible_id, L"PNP0C50") != NULL) {
 			dev->bus_type = HID_API_BUS_I2C;
 			break;
 		}
 
 		/* SPI devices
 		   https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-for-spi */
-		if (wcsstr(id, L"PNP0C51") != NULL) {
+		if (wcsstr(compatible_id, L"PNP0C51") != NULL) {
 			dev->bus_type = HID_API_BUS_SPI;
 			break;
 		}
 	}
 end:
 	free(device_id);
-	free(hardware_ids);
 	free(compatible_ids);
 }
 
@@ -552,7 +677,6 @@
 
 	return dst;
 }
-#endif /* 0 */
 
 static wchar_t *hid_internal_UTF8toUTF16(const char *src)
 {
@@ -569,299 +693,148 @@
 	return dst;
 }
 
-static int hid_get_bluetooth_info(const char *path, struct hid_device_info* dev)
+static struct hid_device_info *hid_internal_get_device_info(const wchar_t *path, HANDLE handle)
 {
-	wchar_t *interface_path = NULL, *device_id = NULL, *compatible_ids = NULL;
-	wchar_t *id;
-	CONFIGRET cr;
-	DEVINST dev_node;
-	int is_bluetooth = 0;
+	struct hid_device_info *dev = NULL; /* return object */
+	HIDD_ATTRIBUTES attrib;
+	PHIDP_PREPARSED_DATA pp_data = NULL;
+	HIDP_CAPS caps;
+	wchar_t string[MAX_STRING_WCHARS];
 
-	/* Get the device id from interface path */
-	interface_path = hid_internal_UTF8toUTF16(path);
-	device_id = hid_internal_get_device_interface_property(interface_path, &DEVPKEY_Device_InstanceId, DEVPROP_TYPE_STRING);
-	if (!device_id)
-		goto end;
+	/* Create the record. */
+	dev = (struct hid_device_info*)calloc(1, sizeof(struct hid_device_info));
 
-	/* Open devnode from device id */
-	cr = CM_Locate_DevNodeW(&dev_node, (DEVINSTID_W)device_id, CM_LOCATE_DEVNODE_NORMAL);
-	if (cr != CR_SUCCESS)
-		goto end;
-
-	/* Get devnode parent */
-	cr = CM_Get_Parent(&dev_node, dev_node, 0);
-	if (cr != CR_SUCCESS)
-		goto end;
-
-	/* Get the compatible ids from parent devnode */
-	compatible_ids = hid_internal_get_devnode_property(dev_node, &DEVPKEY_Device_CompatibleIds, DEVPROP_TYPE_STRING_LIST);
-	if (!compatible_ids)
-		goto end;
-
-	/* Now we can parse parent's compatible IDs to find out the device bus type */
-	for (id = compatible_ids; *id; id += wcslen(id) + 1) {
-		/* Normalize to upper case */
-		wchar_t* p = id;
-		for (; *p; ++p) *p = (wchar_t)towupper(*p);
-
-		/* USB devices
-		   https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support
-		   https://docs.microsoft.com/windows-hardware/drivers/install/standard-usb-identifiers */
-		if (wcsstr(id, L"USB") != NULL) {
-			/*dev->bus_type = HID_API_BUS_USB;*/
-			break;
-		}
-
-		/* Bluetooth devices
-		   https://docs.microsoft.com/windows-hardware/drivers/bluetooth/installing-a-bluetooth-device */
-		if (wcsstr(id, L"BTHENUM") != NULL) {
-			/*dev->bus_type = HID_API_BUS_BLUETOOTH;*/
-			is_bluetooth = 1;
-			break;
-		}
-
-		/* Bluetooth LE devices */
-		if (wcsstr(id, L"BTHLEDEVICE") != NULL) {
-			/* HidD_GetProductString/HidD_GetManufacturerString/HidD_GetSerialNumberString is not working for BLE HID devices
-			   Request this info via dev node properties instead.
-			   https://docs.microsoft.com/answers/questions/401236/hidd-getproductstring-with-ble-hid-device.html */
-			if (dev)
-				hid_internal_get_ble_info(dev, dev_node);
-
-			/*dev->bus_type = HID_API_BUS_BLUETOOTH;*/
-			is_bluetooth = 1;
-			break;
-		}
-
-		/* I2C devices
-		   https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-support-and-power-management */
-		if (wcsstr(id, L"PNP0C50") != NULL) {
-			/*dev->bus_type = HID_API_BUS_I2C;*/
-			break;
-		}
-
-		/* SPI devices
-		   https://docs.microsoft.com/windows-hardware/drivers/hid/plug-and-play-for-spi */
-		if (wcsstr(id, L"PNP0C51") != NULL) {
-			/*dev->bus_type = HID_API_BUS_SPI;*/
-			break;
-		}
+	if (dev == NULL) {
+		return NULL;
 	}
-end:
-	free(interface_path);
-	free(device_id);
-	free(compatible_ids);
-	return is_bluetooth;
-}
 
-static int hid_blacklist(unsigned short vendor_id, unsigned short product_id)
-{
-    size_t i;
-    static const struct { unsigned short vid; unsigned short pid; } known_bad[] = {
-        /* Causes deadlock when asking for device details... */
-        { 0x1B1C, 0x1B3D },  /* Corsair Gaming keyboard */
-        { 0x1532, 0x0109 },  /* Razer Lycosa Gaming keyboard */
-        { 0x1532, 0x010B },  /* Razer Arctosa Gaming keyboard */
-        { 0x045E, 0x0822 },  /* Microsoft Precision Mouse */
-        { 0x0D8C, 0x0014 },  /* Sharkoon Skiller SGH2 headset */
-        { 0x1CCF, 0x0000 },  /* All Konami Amusement Devices */
+	/* Fill out the record */
+	dev->next = NULL;
+	dev->path = hid_internal_UTF16toUTF8(path);
+	dev->interface_number = -1;
 
-        /* Turns into an Android controller when enumerated... */
-        { 0x0738, 0x2217 }   /* SPEEDLINK COMPETITION PRO */
-    };
+	attrib.Size = sizeof(HIDD_ATTRIBUTES);
+	if (HidD_GetAttributes(handle, &attrib)) {
+		/* VID/PID */
+		dev->vendor_id = attrib.VendorID;
+		dev->product_id = attrib.ProductID;
 
-    for (i = 0; i < (sizeof(known_bad)/sizeof(known_bad[0])); i++) {
-        if ((vendor_id == known_bad[i].vid) && (product_id == known_bad[i].pid || known_bad[i].pid == 0x0000)) {
-            return 1;
-        }
-    }
+		/* Release Number */
+		dev->release_number = attrib.VersionNumber;
+	}
 
-    return 0;
+	/* Get the Usage Page and Usage for this device. */
+	if (HidD_GetPreparsedData(handle, &pp_data)) {
+		if (HidP_GetCaps(pp_data, &caps) == HIDP_STATUS_SUCCESS) {
+			dev->usage_page = caps.UsagePage;
+			dev->usage = caps.Usage;
+		}
+
+		HidD_FreePreparsedData(pp_data);
+	}
+
+	/* Serial Number */
+	string[0] = L'\0';
+	HidD_GetSerialNumberString(handle, string, sizeof(string));
+	string[MAX_STRING_WCHARS - 1] = L'\0';
+	dev->serial_number = _wcsdup(string);
+
+	/* Manufacturer String */
+	string[0] = L'\0';
+	HidD_GetManufacturerString(handle, string, sizeof(string));
+	string[MAX_STRING_WCHARS - 1] = L'\0';
+	dev->manufacturer_string = _wcsdup(string);
+
+	/* Product String */
+	string[0] = L'\0';
+	HidD_GetProductString(handle, string, sizeof(string));
+	string[MAX_STRING_WCHARS - 1] = L'\0';
+	dev->product_string = _wcsdup(string);
+
+	hid_internal_get_info(path, dev);
+
+	return dev;
 }
 
 struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
 {
-	BOOL res;
 	struct hid_device_info *root = NULL; /* return object */
 	struct hid_device_info *cur_dev = NULL;
+	GUID interface_class_guid;
+	CONFIGRET cr;
+	wchar_t* device_interface_list = NULL;
+	DWORD len;
 
-	/* Windows objects for interacting with the driver. */
-	GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} };
-	SP_DEVINFO_DATA devinfo_data;
-	SP_DEVICE_INTERFACE_DATA device_interface_data;
-	SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;
-	HDEVINFO device_info_set = INVALID_HANDLE_VALUE;
-	int device_index = 0;
-	const char *hint = SDL_GetHint(SDL_HINT_HIDAPI_IGNORE_DEVICES);
-
-	if (hid_init() < 0)
+	if (hid_init() < 0) {
+		/* register_global_error: global error is reset by hid_init */
 		return NULL;
+	}
 
-	/* Initialize the Windows objects. */
-	memset(&devinfo_data, 0x0, sizeof(devinfo_data));
-	devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
-	device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+	/* Retrieve HID Interface Class GUID
+	   https://docs.microsoft.com/windows-hardware/drivers/install/guid-devinterface-hid */
+	HidD_GetHidGuid(&interface_class_guid);
 
-	/* Get information for all the devices belonging to the HID class. */
-	device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
-
-	/* Iterate over each device in the HID class, looking for the right one. */
-
-	for (;;) {
-		HANDLE write_handle = INVALID_HANDLE_VALUE;
-		DWORD required_size = 0;
-		HIDD_ATTRIBUTES attrib;
-
-		res = SetupDiEnumDeviceInterfaces(device_info_set,
-			NULL,
-			&InterfaceClassGuid,
-			device_index,
-			&device_interface_data);
-
-		if (!res) {
-			/* A return of FALSE from this function means that
-			   there are no more devices. */
+	/* Get the list of all device interfaces belonging to the HID class. */
+	/* Retry in case of list was changed between calls to
+	  CM_Get_Device_Interface_List_SizeW and CM_Get_Device_Interface_ListW */
+	do {
+		cr = CM_Get_Device_Interface_List_SizeW(&len, &interface_class_guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
+		if (cr != CR_SUCCESS) {
+			register_global_error(L"Failed to get size of HID device interface list");
 			break;
 		}
 
-		/* Call with 0-sized detail size, and let the function
-		   tell us how long the detail struct needs to be. The
-		   size is put in &required_size. */
-		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
-			&device_interface_data,
-			NULL,
-			0,
-			&required_size,
-			NULL);
-
-		/* Allocate a long enough structure for device_interface_detail_data. */
-		device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size);
-		device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
-
-		/* Get the detailed data for this device. The detail data gives us
-		   the device path for this device, which is then passed into
-		   CreateFile() to get a handle to the device. */
-		res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
-			&device_interface_data,
-			device_interface_detail_data,
-			required_size,
-			NULL,
-			NULL);
-
-		if (!res) {
-			/* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");
-			   Continue to the next device. */
-			goto cont;
+		if (device_interface_list != NULL) {
+			free(device_interface_list);
 		}
 
-		/* XInput devices don't get real HID reports and are better handled by the raw input driver */
-		if (strstr(device_interface_detail_data->DevicePath, "&ig_") != NULL) {
-			goto cont;
+		device_interface_list = (wchar_t*)calloc(len, sizeof(wchar_t));
+		if (device_interface_list == NULL) {
+			register_global_error(L"Failed to allocate memory for HID device interface list");
+			return NULL;
 		}
-
-		/* Make sure this device is of Setup Class "HIDClass" and has a
-		   driver bound to it. */
-		/* In the main HIDAPI tree this is a loop which will erroneously open
-			devices that aren't HID class. Please preserve this delta if we ever
-			update to take new changes */
-		{
-			char driver_name[256];
-
-			/* Populate devinfo_data. This function will return failure
-			   when there are no more interfaces left. */
-			res = SetupDiEnumDeviceInfo(device_info_set, device_index, &devinfo_data);
-
-			if (!res)
-				goto cont;
-
-			res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
-			               SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
-			if (!res)
-				goto cont;
-
-			if (strcmp(driver_name, "HIDClass") == 0) {
-				/* See if there's a driver bound. */
-				res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
-				           SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
-				if (!res)
-					goto cont;
-			}
-			else
-			{
-				goto cont;
-			}
+		cr = CM_Get_Device_Interface_ListW(&interface_class_guid, NULL, device_interface_list, len, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
+		if (cr != CR_SUCCESS && cr != CR_BUFFER_SMALL) {
+			register_global_error(L"Failed to get HID device interface list");
 		}
+	} while (cr == CR_BUFFER_SMALL);
 
-		//wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);
+	if (cr != CR_SUCCESS) {
+		goto end_of_function;
+	}
 
-		/* Open a handle to the device */
-		write_handle = open_device(device_interface_detail_data->DevicePath, TRUE, FALSE);
+	/* Iterate over each device interface in the HID class, looking for the right one. */
+	for (wchar_t* device_interface = device_interface_list; *device_interface; device_interface += wcslen(device_interface) + 1) {
+		HANDLE device_handle = INVALID_HANDLE_VALUE;
+		HIDD_ATTRIBUTES attrib;
 
-		/* Check validity of write_handle. */
-		if (write_handle == INVALID_HANDLE_VALUE) {
+		/* Open read-only handle to the device */
+		device_handle = open_device(device_interface, FALSE);
+
+		/* Check validity of device_handle. */
+		if (device_handle == INVALID_HANDLE_VALUE) {
 			/* Unable to open the device. */
-			//register_error(dev, "CreateFile");
-			goto cont;
+			continue;
 		}
 
-
 		/* Get the Vendor ID and Product ID for this device. */
 		attrib.Size = sizeof(HIDD_ATTRIBUTES);
-		HidD_GetAttributes(write_handle, &attrib);
-		//wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);
-
-		/* See if there are any devices we should skip in enumeration */
-		if (hint) {
-			char vendor_match[16], product_match[16];
-			SDL_snprintf(vendor_match, sizeof(vendor_match), "0x%.4x/0x0000", attrib.VendorID);
-			SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", attrib.VendorID, attrib.ProductID);
-			if (SDL_strcasestr(hint, vendor_match) || SDL_strcasestr(hint, product_match)) {
-				continue;
-			}
+		if (!HidD_GetAttributes(device_handle, &attrib)) {
+			goto cont_close;
 		}
 
 		/* Check the VID/PID to see if we should add this
 		   device to the enumeration list. */
 		if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
-		    (product_id == 0x0 || attrib.ProductID == product_id) &&
-			!hid_blacklist(attrib.VendorID, attrib.ProductID)) {
+		    (product_id == 0x0 || attrib.ProductID == product_id)) {
 
-			#define WSTR_LEN 512
-			const char *str;
-			struct hid_device_info *tmp;
-			PHIDP_PREPARSED_DATA pp_data = NULL;
-			HIDP_CAPS caps;
-			BOOLEAN hidp_res;
-			NTSTATUS nt_res;
-			wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */
-			size_t len;
+			/* VID/PID match. Create the record. */
+			struct hid_device_info *tmp = hid_internal_get_device_info(device_interface, device_handle);
 
-			/* Get the Usage Page and Usage for this device. */
-			hidp_res = HidD_GetPreparsedData(write_handle, &pp_data);
-			if (hidp_res) {
-				nt_res = HidP_GetCaps(pp_data, &caps);
-				HidD_FreePreparsedData(pp_data);
-				if (nt_res != HIDP_STATUS_SUCCESS) {
-					goto cont_close;
-				}
-			}
-			else {
+			if (tmp == NULL) {
 				goto cont_close;
 			}
 
-			/* SDL Modification: Ignore the device if it's not a gamepad. This limits compatibility
-			   risk from devices that may respond poorly to our string queries below. */
-			if (attrib.VendorID != USB_VENDOR_VALVE) {
-				if (caps.UsagePage != USAGE_PAGE_GENERIC_DESKTOP) {
-					goto cont_close;
-				}
-				if (caps.Usage != USAGE_JOYSTICK && caps.Usage != USAGE_GAMEPAD && caps.Usage != USAGE_MULTIAXISCONTROLLER) {
-					goto cont_close;
-				}
-			}
-
-			/* VID/PID match. Create the record. */
-			tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
 			if (cur_dev) {
 				cur_dev->next = tmp;
 			}
@@ -869,86 +842,24 @@
 				root = tmp;
 			}
 			cur_dev = tmp;
-
-			/* Fill out the record */
-			cur_dev->usage_page = caps.UsagePage;
-			cur_dev->usage = caps.Usage;
-			cur_dev->next = NULL;
-			str = device_interface_detail_data->DevicePath;
-			if (str) {
-				len = strlen(str);
-				cur_dev->path = (char*) calloc(len+1, sizeof(char));
-				memcpy(cur_dev->path, str, len+1);
-			}
-			else
-				cur_dev->path = NULL;
-
-			/* Serial Number */
-			hidp_res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr));
-			wstr[WSTR_LEN-1] = 0x0000;
-			if (hidp_res) {
-				cur_dev->serial_number = _wcsdup(wstr);
-			}
-
-			/* Manufacturer String */
-			hidp_res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr));
-			wstr[WSTR_LEN-1] = 0x0000;
-			if (hidp_res) {
-				cur_dev->manufacturer_string = _wcsdup(wstr);
-			}
-
-			/* Product String */
-			hidp_res = HidD_GetProductString(write_handle, wstr, sizeof(wstr));
-			wstr[WSTR_LEN-1] = 0x0000;
-			if (hidp_res) {
-				cur_dev->product_string = _wcsdup(wstr);
-			}
-
-			/* VID/PID */
-			cur_dev->vendor_id = attrib.VendorID;
-			cur_dev->product_id = attrib.ProductID;
-
-			/* Release Number */
-			cur_dev->release_number = attrib.VersionNumber;
-
-			/* Interface Number. It can sometimes be parsed out of the path
-			   on Windows if a device has multiple interfaces. See
-			   http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or
-			   search for "Hardware IDs for HID Devices" at MSDN. If it's not
-			   in the path, it's set to -1. */
-			cur_dev->interface_number = -1;
-			if (cur_dev->path) {
-				char *interface_component = strstr(cur_dev->path, "&mi_");
-				if (interface_component) {
-					char *hex_str = interface_component + 4;
-					char *endptr = NULL;
-					cur_dev->interface_number = strtol(hex_str, &endptr, 16);
-					if (endptr == hex_str) {
-						/* The parsing failed. Set interface_number to -1. */
-						cur_dev->interface_number = -1;
-					}
-				}
-			}
-
-			/* Get the Bluetooth device info */
-			hid_get_bluetooth_info(cur_dev->path, cur_dev);
 		}
 
 cont_close:
-		CloseHandle(write_handle);
-cont:
-		/* We no longer need the detail data. It can be freed */
-		free(device_interface_detail_data);
-
-		device_index++;
-
+		CloseHandle(device_handle);
 	}
 
-	/* Close the device information handle. */
-	SetupDiDestroyDeviceInfoList(device_info_set);
+	if (root == NULL) {
+		if (vendor_id == 0 && product_id == 0) {
+			register_global_error(L"No HID devices found in the system.");
+		} else {
+			register_global_error(L"No HID devices with requested VID/PID found in the system.");
+		}
+	}
+
+end_of_function:
+	free(device_interface_list);
 
 	return root;
-
 }
 
 void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
@@ -966,7 +877,6 @@
 	}
 }
 
-
 HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
 {
 	/* TODO: Merge this functions with the Linux version. This function should be platform independent. */
@@ -974,13 +884,19 @@
 	const char *path_to_open = NULL;
 	hid_device *handle = NULL;
 
+	/* register_global_error: global error is reset by hid_enumerate/hid_init */
 	devs = hid_enumerate(vendor_id, product_id);
+	if (!devs) {
+		/* register_global_error: global error is already set by hid_enumerate */
+		return NULL;
+	}
+
 	cur_dev = devs;
 	while (cur_dev) {
 		if (cur_dev->vendor_id == vendor_id &&
 		    cur_dev->product_id == product_id) {
 			if (serial_number) {
-				if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
+				if (cur_dev->serial_number && wcscmp(serial_number, cur_dev->serial_number) == 0) {
 					path_to_open = cur_dev->path;
 					break;
 				}
@@ -995,7 +911,9 @@
 
 	if (path_to_open) {
 		/* Open the device */
-		handle = hid_open_path(path_to_open, 0);
+		handle = hid_open_path(path_to_open);
+	} else {
+		register_global_error(L"Device with requested VID/PID/(SerialNumber) not found");
 	}
 
 	hid_free_enumeration(devs);
@@ -1003,151 +921,173 @@
 	return handle;
 }
 
-HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path, int bExclusive)
+HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
 {
-	hid_device *dev;
-	HIDP_CAPS caps;
+	hid_device *dev = NULL;
+	wchar_t* interface_path = NULL;
+	HANDLE device_handle = INVALID_HANDLE_VALUE;
 	PHIDP_PREPARSED_DATA pp_data = NULL;
-	BOOLEAN res;
-	NTSTATUS nt_res;
+	HIDP_CAPS caps;
 
 	if (hid_init() < 0) {
-		return NULL;
+		/* register_global_error: global error is reset by hid_init */
+		goto end_of_function;
+	}
+
+	interface_path = hid_internal_UTF8toUTF16(path);
+	if (!interface_path) {
+		register_global_error(L"Path conversion failure");
+		goto end_of_function;
+	}
+
+	/* Open a handle to the device */
+	device_handle = open_device(interface_path, TRUE);
+
+	/* Check validity of write_handle. */
+	if (device_handle == INVALID_HANDLE_VALUE) {
+		/* System devices, such as keyboards and mice, cannot be opened in
+		   read-write mode, because the system takes exclusive control over
+		   them.  This is to prevent keyloggers.  However, feature reports
+		   can still be sent and received.  Retry opening the device, but
+		   without read/write access. */
+		device_handle = open_device(interface_path, FALSE);
+
+		/* Check the validity of the limited device_handle. */
+		if (device_handle == INVALID_HANDLE_VALUE) {
+			register_global_winapi_error(L"open_device");
+			goto end_of_function;
+		}
+	}
+
+	/* Set the Input Report buffer size to 64 reports. */
+	if (!HidD_SetNumInputBuffers(device_handle, 64)) {
+		register_global_winapi_error(L"set input buffers");
+		goto end_of_function;
+	}
+
+	/* Get the Input Report length for the device. */
+	if (!HidD_GetPreparsedData(device_handle, &pp_data)) {
+		register_global_winapi_error(L"get preparsed data");
+		goto end_of_function;
+	}
+
+	if (HidP_GetCaps(pp_data, &caps) != HIDP_STATUS_SUCCESS) {
+		register_global_error(L"HidP_GetCaps");
+		goto end_of_function;
 	}
 
 	dev = new_hid_device();
 
-	/* Open a handle to the device */
-	dev->device_handle = open_device(path, FALSE, bExclusive);
-
-	/* Check validity of write_handle. */
-	if (dev->device_handle == INVALID_HANDLE_VALUE) {
-		/* Unable to open the device. */
-		register_error(dev, "CreateFile");
-		goto err;
+	if (dev == NULL) {
+		register_global_error(L"hid_device allocation error");
+		goto end_of_function;
 	}
 
-	/* Set the Input Report buffer size to 64 reports. */
-	res = HidD_SetNumInputBuffers(dev->device_handle, 64);
-	if (!res) {
-		register_error(dev, "HidD_SetNumInputBuffers");
-		goto err;
-	}
+	dev->device_handle = device_handle;
+	device_handle = INVALID_HANDLE_VALUE;
 
-	/* Get the Input Report length for the device. */
-	res = HidD_GetPreparsedData(dev->device_handle, &pp_data);
-	if (!res) {
-		register_error(dev, "HidD_GetPreparsedData");
-		goto err;
-	}
-	nt_res = HidP_GetCaps(pp_data, &caps);
-	if (nt_res != HIDP_STATUS_SUCCESS) {
-		register_error(dev, "HidP_GetCaps");
-		goto err_pp_data;
-	}
 	dev->output_report_length = caps.OutputReportByteLength;
 	dev->input_report_length = caps.InputReportByteLength;
-	HidD_FreePreparsedData(pp_data);
-
-	/* On Windows 7, we need to use hid_write_output_report() over Bluetooth */
-	if (dev->output_report_length > 512) {
-		dev->use_hid_write_output_report = !IsWindowsVersionOrGreater( HIBYTE( _WIN32_WINNT_WIN8 ), LOBYTE( _WIN32_WINNT_WIN8 ), 0 );
-	}
-
+	dev->feature_report_length = caps.FeatureReportByteLength;
 	dev->read_buf = (char*) malloc(dev->input_report_length);
+	dev->device_info = hid_internal_get_device_info(interface_path, dev->device_handle);
+
+end_of_function:
+	free(interface_path);
+	CloseHandle(device_handle);
+
+	if (pp_data) {
+		HidD_FreePreparsedData(pp_data);
+	}
 
 	return dev;
-
-err_pp_data:
-		HidD_FreePreparsedData(pp_data);
-err:
-		free_hid_device(dev);
-		return NULL;
 }
 
-int HID_API_EXPORT HID_API_CALL hid_write_output_report(hid_device *dev, const unsigned char *data, size_t length)
+int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
 {
+	DWORD bytes_written = 0;
+	int function_result = -1;
 	BOOL res;
-	res = HidD_SetOutputReport(dev->device_handle, (void *)data, (ULONG)length);
-	if (res)
-		return (int)length;
-	else
-		return -1;
-}
+	BOOL overlapped = FALSE;
 
-static int hid_write_timeout(hid_device *dev, const unsigned char *data, size_t length, int milliseconds)
-{
-	DWORD bytes_written;
-	BOOL res;
 	unsigned char *buf;
 
-	if (dev->use_hid_write_output_report) {
-		return hid_write_output_report(dev, data, length);
+	if (!data || !length) {
+		register_string_error(dev, L"Zero buffer/length");
+		return function_result;
 	}
 
+	register_string_error(dev, NULL);
+
 	/* Make sure the right number of bytes are passed to WriteFile. Windows
 	   expects the number of bytes which are in the _longest_ report (plus
 	   one for the report number) bytes even if the data is a report
 	   which is shorter than that. Windows gives us this value in
 	   caps.OutputReportByteLength. If a user passes in fewer bytes than this,
-	   create a temporary buffer which is the proper size. */
+	   use cached temporary buffer which is the proper size. */
 	if (length >= dev->output_report_length) {
 		/* The user passed the right number of bytes. Use the buffer as-is. */
 		buf = (unsigned char *) data;
 	} else {
-		/* Create a temporary buffer and copy the user's data
-		   into it, padding the rest with zeros. */
-		buf = (unsigned char *) malloc(dev->output_report_length);
+		if (dev->write_buf == NULL)
+			dev->write_buf = (unsigned char *) malloc(dev->output_report_length);
+		buf = dev->write_buf;
 		memcpy(buf, data, length);
 		memset(buf + length, 0, dev->output_report_length - length);
 		length = dev->output_report_length;
 	}
 
-	res = WriteFile( dev->device_handle, buf, ( DWORD ) length, NULL, &dev->write_ol );
+	res = WriteFile(dev->device_handle, buf, (DWORD) length, NULL, &dev->write_ol);
+
 	if (!res) {
 		if (GetLastError() != ERROR_IO_PENDING) {
 			/* WriteFile() failed. Return error. */
-			register_error(dev, "WriteFile");
-			bytes_written = (DWORD) -1;
+			register_winapi_error(dev, L"WriteFile");
+			goto end_of_function;
+		}
+		overlapped = TRUE;
+	}
+
+	if (overlapped) {
+		/* Wait for the transaction to complete. This makes
+		   hid_write() synchronous. */
+		res = WaitForSingleObject(dev->write_ol.hEvent, 1000);
+		if (res != WAIT_OBJECT_0) {
+			/* There was a Timeout. */
+			register_winapi_error(dev, L"hid_write/WaitForSingleObject");
+			goto end_of_function;
+		}
+
+		/* Get the result. */
+		res = GetOverlappedResult(dev->device_handle, &dev->write_ol, &bytes_written, FALSE/*wait*/);
+		if (res) {
+			function_result = bytes_written;
+		}
+		else {
+			/* The Write operation failed. */
+			register_winapi_error(dev, L"hid_write/GetOverlappedResult");
 			goto end_of_function;
 		}
 	}
 
-	/* Wait here until the write is done. This makes hid_write() synchronous. */
-	res = WaitForSingleObject(dev->write_ol.hEvent, milliseconds);
-	if (res != WAIT_OBJECT_0)
-	{
-		// There was a Timeout.
-		bytes_written = (DWORD) -1;
-		register_error(dev, "WriteFile/WaitForSingleObject Timeout");
-		goto end_of_function;
-	}
-
-	res = GetOverlappedResult(dev->device_handle, &dev->write_ol, &bytes_written, FALSE/*F=don't_wait*/);
-	if (!res) {
-		/* The Write operation failed. */
-		register_error(dev, "WriteFile");
-		bytes_written = (DWORD) -1;
-		goto end_of_function;
-	}
-
 end_of_function:
-	if (buf != data)
-		free(buf);
-
-	return bytes_written;
+	return function_result;
 }
 
-int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
-{
-	return hid_write_timeout(dev, data, length, HID_WRITE_TIMEOUT_MILLISECONDS);
-}
 
 int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
 {
 	DWORD bytes_read = 0;
 	size_t copy_len = 0;
-	BOOL res;
+	BOOL res = FALSE;
+	BOOL overlapped = FALSE;
+
+	if (!data || !length) {
+		register_string_error(dev, L"Zero buffer/length");
+		return -1;
+	}
+
+	register_string_error(dev, NULL);
 
 	/* Copy the handle for convenience. */
 	HANDLE ev = dev->ol.hEvent;
@@ -1157,33 +1097,40 @@
 		dev->read_pending = TRUE;
 		memset(dev->read_buf, 0, dev->input_report_length);
 		ResetEvent(ev);
-		res = ReadFile(dev->device_handle, dev->read_buf, (DWORD)dev->input_report_length, &bytes_read, &dev->ol);
+		res = ReadFile(dev->device_handle, dev->read_buf, (DWORD) dev->input_report_length, &bytes_read, &dev->ol);
 
 		if (!res) {
 			if (GetLastError() != ERROR_IO_PENDING) {
 				/* ReadFile() has failed.
 				   Clean up and return error. */
+				register_winapi_error(dev, L"ReadFile");
 				CancelIo(dev->device_handle);
 				dev->read_pending = FALSE;
 				goto end_of_function;
 			}
+			overlapped = TRUE;
 		}
 	}
-
-	/* See if there is any data yet. */
-	res = WaitForSingleObject(ev, milliseconds >= 0 ? milliseconds : INFINITE);
-	if (res != WAIT_OBJECT_0) {
-		/* There was no data this time. Return zero bytes available,
-			but leave the Overlapped I/O running. */
-		return 0;
+	else {
+		overlapped = TRUE;
 	}
 
-	/* Get the number of bytes read. The actual data has been copied to the data[]
-	   array which was passed to ReadFile(). We must not wait here because we've
-	   already waited on our event above, and since it's auto-reset, it will have
-	   been reset back to unsignalled by now. */
-	res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, FALSE/*don't wait*/);
+	if (overlapped) {
+		if (milliseconds >= 0) {
+			/* See if there is any data yet. */
+			res = WaitForSingleObject(ev, milliseconds);
+			if (res != WAIT_OBJECT_0) {
+				/* There was no data this time. Return zero bytes available,
+				   but leave the Overlapped I/O running. */
+				return 0;
+			}
+		}
 
+		/* Either WaitForSingleObject() told us that ReadFile has completed, or
+		   we are in non-blocking mode. Get the number of bytes read. The actual
+		   data has been copied to the data[] array which was passed to ReadFile(). */
+		res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
+	}
 	/* Set pending back to false, even if GetOverlappedResult() returned error. */
 	dev->read_pending = FALSE;
 
@@ -1203,14 +1150,16 @@
 			memcpy(data, dev->read_buf, copy_len);
 		}
 	}
+	if (!res) {
+		register_winapi_error(dev, L"hid_read_timeout/GetOverlappedResult");
+	}
 
 end_of_function:
 	if (!res) {
-		register_error(dev, "GetOverlappedResult");
 		return -1;
 	}
 
-	return (int)copy_len;
+	return (int) copy_len;
 }
 
 int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)
@@ -1226,42 +1175,69 @@
 
 int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
 {
-	BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, (ULONG)length);
-	if (!res) {
-		register_error(dev, "HidD_SetFeature");
+	BOOL res = FALSE;
+	unsigned char *buf;
+	size_t length_to_send;
+
+	if (!data || !length) {
+		register_string_error(dev, L"Zero buffer/length");
 		return -1;
 	}
 
-	return (int)length;
+	register_string_error(dev, NULL);
+
+	/* Windows expects at least caps.FeatureReportByteLength bytes passed
+	   to HidD_SetFeature(), even if the report is shorter. Any less sent and
+	   the function fails with error ERROR_INVALID_PARAMETER set. Any more
+	   and HidD_SetFeature() silently truncates the data sent in the report
+	   to caps.FeatureReportByteLength. */
+	if (length >= dev->feature_report_length) {
+		buf = (unsigned char *) data;
+		length_to_send = length;
+	} else {
+		if (dev->feature_buf == NULL)
+			dev->feature_buf = (unsigned char *) malloc(dev->feature_report_length);
+		buf = dev->feature_buf;
+		memcpy(buf, data, length);
+		memset(buf + length, 0, dev->feature_report_length - length);
+		length_to_send = dev->feature_report_length;
+	}
+
+	res = HidD_SetFeature(dev->device_handle, (PVOID)buf, (DWORD) length_to_send);
+
+	if (!res) {
+		register_winapi_error(dev, L"HidD_SetFeature");
+		return -1;
+	}
+
+	return (int) length;
 }
 
-
-int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
+static int hid_get_report(hid_device *dev, DWORD report_type, unsigned char *data, size_t length)
 {
 	BOOL res;
-#if 0
-	res = HidD_GetFeature(dev->device_handle, (PVOID)data, (ULONG)length);
-	if (!res) {
-		register_error(dev, "HidD_GetFeature");
-		return -1;
-	}
-	return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */
-#else
-	DWORD bytes_returned;
+	DWORD bytes_returned = 0;
 
 	OVERLAPPED ol;
 	memset(&ol, 0, sizeof(ol));
 
+	if (!data || !length) {
+		register_string_error(dev, L"Zero buffer/length");
+		return -1;
+	}
+
+	register_string_error(dev, NULL);
+
 	res = DeviceIoControl(dev->device_handle,
-		IOCTL_HID_GET_FEATURE,
-		data, (DWORD)length,
-		data, (DWORD)length,
+		report_type,
+		data, (DWORD) length,
+		data, (DWORD) length,
 		&bytes_returned, &ol);
 
 	if (!res) {
 		if (GetLastError() != ERROR_IO_PENDING) {
 			/* DeviceIoControl() failed. Return error. */
-			register_error(dev, "Send Feature Report DeviceIoControl");
+			register_winapi_error(dev, L"Get Input/Feature Report DeviceIoControl");
 			return -1;
 		}
 	}
@@ -1271,157 +1247,209 @@
 	res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
 	if (!res) {
 		/* The operation failed. */
-		register_error(dev, "Send Feature Report GetOverLappedResult");
+		register_winapi_error(dev, L"Get Input/Feature Report GetOverLappedResult");
 		return -1;
 	}
 
+	/* When numbered reports aren't used,
+	   bytes_returned seem to include only what is actually received from the device
+	   (not including the first byte with 0, as an indication "no numbered reports"). */
+	if (data[0] == 0x0) {
+		bytes_returned++;
+	}
+
 	return bytes_returned;
-#endif
+}
+
+int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
+{
+	/* We could use HidD_GetFeature() instead, but it doesn't give us an actual length, unfortunately */
+	return hid_get_report(dev, IOCTL_HID_GET_FEATURE, data, length);
+}
+
+int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length)
+{
+	/* We could use HidD_GetInputReport() instead, but it doesn't give us an actual length, unfortunately */
+	return hid_get_report(dev, IOCTL_HID_GET_INPUT_REPORT, data, length);
 }
 
 void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
 {
-	typedef BOOL (WINAPI *CancelIoEx_t)(HANDLE hFile, LPOVERLAPPED lpOverlapped);
-	CancelIoEx_t CancelIoExFunc = (CancelIoEx_t)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "CancelIoEx");
-
 	if (!dev)
 		return;
 
-	if (CancelIoExFunc) {
-		CancelIoExFunc(dev->device_handle, NULL);
-	} else {
-		/* Windows XP, this will only cancel I/O on the current thread */
-		CancelIo(dev->device_handle);
-	}
-	if (dev->read_pending) {
-		DWORD bytes_read = 0;
-
-		GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
-	}
+	CancelIo(dev->device_handle);
 	free_hid_device(dev);
 }
 
 int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
 {
-	BOOL res;
-
-	res = HidD_GetManufacturerString(dev->device_handle, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
-	if (!res) {
-		register_error(dev, "HidD_GetManufacturerString");
+	if (!string || !maxlen) {
+		register_string_error(dev, L"Zero buffer/length");
 		return -1;
 	}
 
+	if (!dev->device_info) {
+		register_string_error(dev, L"NULL device info");
+		return -1;
+	}
+
+	wcsncpy(string, dev->device_info->manufacturer_string, maxlen);
+	string[maxlen - 1] = L'\0';
+
+	register_string_error(dev, NULL);
+
 	return 0;
 }
 
 int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
 {
-	BOOL res;
-
-	res = HidD_GetProductString(dev->device_handle, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
-	if (!res) {
-		register_error(dev, "HidD_GetProductString");
+	if (!string || !maxlen) {
+		register_string_error(dev, L"Zero buffer/length");
 		return -1;
 	}
 
+	if (!dev->device_info) {
+		register_string_error(dev, L"NULL device info");
+		return -1;
+	}
+
+	wcsncpy(string, dev->device_info->product_string, maxlen);
+	string[maxlen - 1] = L'\0';
+
+	register_string_error(dev, NULL);
+
 	return 0;
 }
 
 int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
 {
-	BOOL res;
-
-	res = HidD_GetSerialNumberString(dev->device_handle, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
-	if (!res) {
-		register_error(dev, "HidD_GetSerialNumberString");
+	if (!string || !maxlen) {
+		register_string_error(dev, L"Zero buffer/length");
 		return -1;
 	}
 
+	if (!dev->device_info) {
+		register_string_error(dev, L"NULL device info");
+		return -1;
+	}
+
+	wcsncpy(string, dev->device_info->serial_number, maxlen);
+	string[maxlen - 1] = L'\0';
+
+	register_string_error(dev, NULL);
+
 	return 0;
 }
 
+HID_API_EXPORT struct hid_device_info * HID_API_CALL hid_get_device_info(hid_device *dev) {
+	if (!dev->device_info)
+	{
+		register_string_error(dev, L"NULL device info");
+		return NULL;
+	}
+
+	return dev->device_info;
+}
+
 int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
 {
 	BOOL res;
 
-	res = HidD_GetIndexedString(dev->device_handle, string_index, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
+	res = HidD_GetIndexedString(dev->device_handle, string_index, string, sizeof(wchar_t) * (DWORD) MIN(maxlen, MAX_STRING_WCHARS));
 	if (!res) {
-		register_error(dev, "HidD_GetIndexedString");
+		register_winapi_error(dev, L"HidD_GetIndexedString");
 		return -1;
 	}
 
+	register_string_error(dev, NULL);
+
 	return 0;
 }
 
+int HID_API_EXPORT_CALL hid_winapi_get_container_id(hid_device *dev, GUID *container_id)
+{
+	wchar_t *interface_path = NULL, *device_id = NULL;
+	CONFIGRET cr = CR_FAILURE;
+	DEVINST dev_node;
+	DEVPROPTYPE property_type;
+	ULONG len;
+
+	if (!container_id) {
+		register_string_error(dev, L"Invalid Container ID");
+		return -1;
+	}
+
+	register_string_error(dev, NULL);
+
+	interface_path = hid_internal_UTF8toUTF16(dev->device_info->path);
+	if (!interface_path) {
+		register_string_error(dev, L"Path conversion failure");
+		goto end;
+	}
+
+	/* Get the device id from interface path */
+	device_id = hid_internal_get_device_interface_property(interface_path, &DEVPKEY_Device_InstanceId, DEVPROP_TYPE_STRING);
+	if (!device_id) {
+		register_string_error(dev, L"Failed to get device interface property InstanceId");
+		goto end;
+	}
+
+	/* Open devnode from device id */
+	cr = CM_Locate_DevNodeW(&dev_node, (DEVINSTID_W)device_id, CM_LOCATE_DEVNODE_NORMAL);
+	if (cr != CR_SUCCESS) {
+		register_string_error(dev, L"Failed to locate device node");
+		goto end;
+	}
+
+	/* Get the container id from devnode */
+	len = sizeof(*container_id);
+	cr = CM_Get_DevNode_PropertyW(dev_node, &DEVPKEY_Device_ContainerId, &property_type, (PBYTE)container_id, &len, 0);
+	if (cr == CR_SUCCESS && property_type != DEVPROP_TYPE_GUID)
+		cr = CR_FAILURE;
+
+	if (cr != CR_SUCCESS)
+		register_string_error(dev, L"Failed to read ContainerId property from device node");
+
+end:
+	free(interface_path);
+	free(device_id);
+
+	return cr == CR_SUCCESS ? 0 : -1;
+}
+
+
+int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size)
+{
+	PHIDP_PREPARSED_DATA pp_data = NULL;
+
+	if (!HidD_GetPreparsedData(dev->device_handle, &pp_data) || pp_data == NULL) {
+		register_string_error(dev, L"HidD_GetPreparsedData");
+		return -1;
+	}
+
+	int res = hid_winapi_descriptor_reconstruct_pp_data(pp_data, buf, buf_size);
+
+	HidD_FreePreparsedData(pp_data);
+
+	return res;
+}
+
 HID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)
 {
-	return (wchar_t*)dev->last_error_str;
+	if (dev) {
+		if (dev->last_error_str == NULL)
+			return L"Success";
+		return (wchar_t*)dev->last_error_str;
+	}
+
+	if (last_global_error_str == NULL)
+		return L"Success";
+	return last_global_error_str;
 }
 
-
-#if 0
-
-/*#define PICPGM*/
-/*#define S11*/
-#define P32
-#ifdef S11
-	unsigned short VendorID = 0xa0a0;
-	unsigned short ProductID = 0x0001;
-#endif
-
-#ifdef P32
-	unsigned short VendorID = 0x04d8;
-	unsigned short ProductID = 0x3f;
-#endif
-
-#ifdef PICPGM
-	unsigned short VendorID = 0x04d8;
-	unsigned short ProductID = 0x0033;
-#endif
-
-int __cdecl main(int argc, char* argv[])
-{
-	int i, res;
-	unsigned char buf[65];
-
-	UNREFERENCED_PARAMETER(argc);
-	UNREFERENCED_PARAMETER(argv);
-
-	/* Set up the command buffer. */
-	memset(buf,0x00,sizeof(buf));
-	buf[0] = 0;
-	buf[1] = 0x81;
-
-
-	/* Open the device. */
-	int handle = open(VendorID, ProductID, L"12345");
-	if (handle < 0)
-		printf("unable to open device\n");
-
-
-	/* Toggle LED (cmd 0x80) */
-	buf[1] = 0x80;
-	res = write(handle, buf, 65);
-	if (res < 0)
-		printf("Unable to write()\n");
-
-	/* Request state (cmd 0x81) */
-	buf[1] = 0x81;
-	write(handle, buf, 65);
-	if (res < 0)
-		printf("Unable to write() (2)\n");
-
-	/* Read requested state */
-	read(handle, buf, 65);
-	if (res < 0)
-		printf("Unable to read()\n");
-
-	/* Print out the returned buffer. */
-	for (i = 0; i < 4; i++)
-		printf("buf[%d]: %d\n", i, buf[i]);
-
-	return 0;
-}
+#ifndef hidapi_winapi_EXPORTS
+#include "hidapi_descriptor_reconstruct.c"
 #endif
 
 #ifdef __cplusplus
diff --git a/src/hidapi/windows/hidapi.rc b/src/hidapi/windows/hidapi.rc
new file mode 100644
index 0000000..530917e
--- /dev/null
+++ b/src/hidapi/windows/hidapi.rc
@@ -0,0 +1,35 @@
+#include "winresrc.h"
+
+#include "hidapi.h"
+
+// English
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION HID_API_VERSION_MAJOR,HID_API_VERSION_MINOR,HID_API_VERSION_PATCH,0
+ PRODUCTVERSION HID_API_VERSION_MAJOR,HID_API_VERSION_MINOR,HID_API_VERSION_PATCH,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS 0
+#ifdef _DEBUG
+  | VS_FF_DEBUG
+#endif
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VFT_DLL
+BEGIN
+	BLOCK "StringFileInfo"
+	BEGIN
+		BLOCK "04090000"
+		BEGIN
+			VALUE "CompanyName", "libusb/hidapi Team"
+			VALUE "FileDescription", "A multi-platform library to interface with HID devices (USB, Bluetooth, etc.)"
+			VALUE "FileVersion", HID_API_VERSION_STR
+			VALUE "ProductName", "HIDAPI"
+			VALUE "ProductVersion", HID_API_VERSION_STR
+			VALUE "Licence", "https://github.com/libusb/hidapi/blob/master/LICENSE.txt"
+			VALUE "Comments", "https://github.com/libusb/hidapi"
+		END
+	END
+	BLOCK "VarFileInfo"
+	BEGIN
+		VALUE "Translation", 0x409, 0
+	END
+END
diff --git a/src/hidapi/windows/hidapi.sln b/src/hidapi/windows/hidapi.sln
index af4076c..aeb2660 100644
--- a/src/hidapi/windows/hidapi.sln
+++ b/src/hidapi/windows/hidapi.sln
@@ -1,29 +1,41 @@
-

-Microsoft Visual Studio Solution File, Format Version 10.00

-# Visual C++ Express 2008

-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hidapi", "hidapi.vcproj", "{A107C21C-418A-4697-BB10-20C3AA60E2E4}"

-EndProject

-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hidtest", "hidtest.vcproj", "{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}"

-	ProjectSection(ProjectDependencies) = postProject

-		{A107C21C-418A-4697-BB10-20C3AA60E2E4} = {A107C21C-418A-4697-BB10-20C3AA60E2E4}

-	EndProjectSection

-EndProject

-Global

-	GlobalSection(SolutionConfigurationPlatforms) = preSolution

-		Debug|Win32 = Debug|Win32

-		Release|Win32 = Release|Win32

-	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}.Release|Win32.ActiveCfg = Release|Win32

-		{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|Win32.Build.0 = Release|Win32

-		{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}.Release|Win32.ActiveCfg = Release|Win32

-		{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|Win32.Build.0 = Release|Win32

-	EndGlobalSection

-	GlobalSection(SolutionProperties) = preSolution

-		HideSolutionNode = FALSE

-	EndGlobalSection

-EndGlobal

+
+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
diff --git a/src/hidapi/windows/hidapi.vcproj b/src/hidapi/windows/hidapi.vcproj
index aea5a0b..e331064 100644
--- a/src/hidapi/windows/hidapi.vcproj
+++ b/src/hidapi/windows/hidapi.vcproj
@@ -1,201 +1,200 @@
-<?xml version="1.0" encoding="Windows-1252"?>

-<VisualStudioProject

-	ProjectType="Visual C++"

-	Version="9.00"

-	Name="hidapi"

-	ProjectGUID="{A107C21C-418A-4697-BB10-20C3AA60E2E4}"

-	RootNamespace="hidapi"

-	Keyword="Win32Proj"

-	TargetFrameworkVersion="196613"

-	>

-	<Platforms>

-		<Platform

-			Name="Win32"

-		/>

-	</Platforms>

-	<ToolFiles>

-	</ToolFiles>

-	<Configurations>

-		<Configuration

-			Name="Debug|Win32"

-			OutputDirectory="$(SolutionDir)$(ConfigurationName)"

-			IntermediateDirectory="$(ConfigurationName)"

-			ConfigurationType="2"

-			CharacterSet="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				Optimization="0"

-				AdditionalIncludeDirectories="..\hidapi"

-				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS"

-				MinimalRebuild="true"

-				BasicRuntimeChecks="3"

-				RuntimeLibrary="3"

-				UsePrecompiledHeader="0"

-				WarningLevel="3"

-				DebugInformationFormat="4"

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="setupapi.lib"

-				LinkIncremental="2"

-				GenerateDebugInformation="true"

-				SubSystem="2"

-				TargetMachine="1"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCManifestTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCFxCopTool"

-			/>

-			<Tool

-				Name="VCAppVerifierTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-			/>

-		</Configuration>

-		<Configuration

-			Name="Release|Win32"

-			OutputDirectory="$(SolutionDir)$(ConfigurationName)"

-			IntermediateDirectory="$(ConfigurationName)"

-			ConfigurationType="2"

-			CharacterSet="1"

-			WholeProgramOptimization="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				Optimization="2"

-				EnableIntrinsicFunctions="true"

-				AdditionalIncludeDirectories="..\hidapi"

-				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS"

-				RuntimeLibrary="2"

-				EnableFunctionLevelLinking="true"

-				UsePrecompiledHeader="0"

-				WarningLevel="3"

-				DebugInformationFormat="3"

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="setupapi.lib"

-				LinkIncremental="1"

-				GenerateDebugInformation="true"

-				SubSystem="2"

-				OptimizeReferences="2"

-				EnableCOMDATFolding="2"

-				TargetMachine="1"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCManifestTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCFxCopTool"

-			/>

-			<Tool

-				Name="VCAppVerifierTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-			/>

-		</Configuration>

-	</Configurations>

-	<References>

-	</References>

-	<Files>

-		<Filter

-			Name="Source Files"

-			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

-			>

-			<File

-				RelativePath=".\hid.c"

-				>

-			</File>

-		</Filter>

-		<Filter

-			Name="Header Files"

-			Filter="h;hpp;hxx;hm;inl;inc;xsd"

-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

-			>

-			<File

-				RelativePath="..\hidapi\hidapi.h"

-				>

-			</File>

-		</Filter>

-		<Filter

-			Name="Resource Files"

-			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"

-			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"

-			>

-		</Filter>

-	</Files>

-	<Globals>

-	</Globals>

-</VisualStudioProject>

+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="hidapi"
+	ProjectGUID="{A107C21C-418A-4697-BB10-20C3AA60E2E4}"
+	RootNamespace="hidapi"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\hidapi"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="1"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\hidapi"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS"
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="setupapi.lib"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\hid.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\hidapi\hidapi.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/hidapi/windows/hidapi.vcxproj b/src/hidapi/windows/hidapi.vcxproj
new file mode 100644
index 0000000..7f7a95d
--- /dev/null
+++ b/src/hidapi/windows/hidapi.vcxproj
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{A107C21C-418A-4697-BB10-20C3AA60E2E4}</ProjectGuid>
+    <RootNamespace>hidapi</RootNamespace>
+    <Keyword>Win32Proj</Keyword>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>DynamicLibrary</ConfigurationType>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <_ProjectFileVersion>14.0.25431.1</_ProjectFileVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>..\hidapi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MinimalRebuild>true</MinimalRebuild>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <PrecompiledHeader />
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>..\hidapi</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>_DEBUG</PreprocessorDefinitions>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>..\hidapi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>..\hidapi</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>_DEBUG</PreprocessorDefinitions>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <Optimization>MaxSpeed</Optimization>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <AdditionalIncludeDirectories>..\hidapi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <PrecompiledHeader />
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <OptimizeReferences>true</OptimizeReferences>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>..\hidapi</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>NDEBUG</PreprocessorDefinitions>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <Optimization>MaxSpeed</Optimization>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <AdditionalIncludeDirectories>..\hidapi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Windows</SubSystem>
+      <OptimizeReferences>true</OptimizeReferences>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>..\hidapi</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>NDEBUG</PreprocessorDefinitions>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="hid.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\hidapi\hidapi.h" />
+    <ClInclude Include="hidapi_winapi.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="hidapi.rc" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/src/hidapi/windows/hidapi_cfgmgr32.h b/src/hidapi/windows/hidapi_cfgmgr32.h
index 071c5b4..638512a 100644
--- a/src/hidapi/windows/hidapi_cfgmgr32.h
+++ b/src/hidapi/windows/hidapi_cfgmgr32.h
@@ -28,18 +28,14 @@
 #include <propkey.h>
 
 #else
-#ifndef PROPERTYKEY_DEFINED
-#define PROPERTYKEY_DEFINED
-typedef struct
-{
-    GUID fmtid;
-    DWORD pid;
-} PROPERTYKEY;
-#endif /* PROPERTYKEY_DEFINED */
 
 /* This part of the header mimics cfgmgr32.h,
     but only what is used by HIDAPI */
 
+#include <initguid.h>
+#include <devpropdef.h>
+#include <propkeydef.h>
+
 typedef DWORD RETURN_TYPE;
 typedef RETURN_TYPE CONFIGRET;
 typedef DWORD DEVNODE, DEVINST;
@@ -59,18 +55,20 @@
 typedef CONFIGRET(__stdcall* CM_Get_DevNode_PropertyW_)(DEVINST dnDevInst, CONST DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, PULONG PropertyBufferSize, ULONG ulFlags);
 typedef CONFIGRET(__stdcall* CM_Get_Device_Interface_PropertyW_)(LPCWSTR pszDeviceInterface, CONST DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, PULONG PropertyBufferSize, ULONG ulFlags);
 typedef CONFIGRET(__stdcall* CM_Get_Device_Interface_List_SizeW_)(PULONG pulLen, LPGUID InterfaceClassGuid, DEVINSTID_W pDeviceID, ULONG ulFlags);
-typedef CONFIGRET(__stdcall* CM_Get_Device_Interface_ListW_)(LPGUID InterfaceClassGuid, DEVINSTID_W pDeviceID, WCHAR* Buffer, ULONG BufferLen, ULONG ulFlags);
+typedef CONFIGRET(__stdcall* CM_Get_Device_Interface_ListW_)(LPGUID InterfaceClassGuid, DEVINSTID_W pDeviceID, PZZWSTR Buffer, ULONG BufferLen, ULONG ulFlags);
 
 // from devpkey.h
-static DEVPROPKEY DEVPKEY_NAME = { { 0xb725f130, 0x47ef, 0x101a, {0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac} }, 10 }; // DEVPROP_TYPE_STRING
-static DEVPROPKEY DEVPKEY_Device_InstanceId = { { 0x78c34fc8, 0x104a, 0x4aca, {0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57} }, 256 }; // DEVPROP_TYPE_STRING
-//static DEVPROPKEY DEVPKEY_Device_HardwareIds = { { 0xa45c254e, 0xdf1c, 0x4efd, {0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0} }, 3 }; // DEVPROP_TYPE_STRING_LIST
-static DEVPROPKEY DEVPKEY_Device_CompatibleIds = { { 0xa45c254e, 0xdf1c, 0x4efd, {0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0} }, 4 }; // DEVPROP_TYPE_STRING_LIST
-//static DEVPROPKEY DEVPKEY_Device_ContainerId = { { 0x8c7ed206, 0x3f8a, 0x4827, {0xb3, 0xab, 0xae, 0x9e, 0x1f, 0xae, 0xfc, 0x6c} }, 2 }; // DEVPROP_TYPE_GUID
+DEFINE_DEVPROPKEY(DEVPKEY_NAME, 0xb725f130, 0x47ef, 0x101a, 0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac, 10); // DEVPROP_TYPE_STRING
+DEFINE_DEVPROPKEY(DEVPKEY_Device_Manufacturer, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 13); // DEVPROP_TYPE_STRING
+DEFINE_DEVPROPKEY(DEVPKEY_Device_InstanceId, 0x78c34fc8, 0x104a, 0x4aca, 0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57, 256); // DEVPROP_TYPE_STRING
+DEFINE_DEVPROPKEY(DEVPKEY_Device_HardwareIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 3); // DEVPROP_TYPE_STRING_LIST
+DEFINE_DEVPROPKEY(DEVPKEY_Device_CompatibleIds, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 4); // DEVPROP_TYPE_STRING_LIST
+DEFINE_DEVPROPKEY(DEVPKEY_Device_ContainerId, 0x8c7ed206, 0x3f8a, 0x4827, 0xb3, 0xab, 0xae, 0x9e, 0x1f, 0xae, 0xfc, 0x6c, 2); // DEVPROP_TYPE_GUID
 
 // from propkey.h
-static PROPERTYKEY PKEY_DeviceInterface_Bluetooth_DeviceAddress = { { 0x2bd67d8b, 0x8beb, 0x48d5, {0x87, 0xe0, 0x6c, 0xda, 0x34, 0x28, 0x04, 0x0a} }, 1 }; // DEVPROP_TYPE_STRING
-static PROPERTYKEY PKEY_DeviceInterface_Bluetooth_Manufacturer = { { 0x2bd67d8b, 0x8beb, 0x48d5, {0x87, 0xe0, 0x6c, 0xda, 0x34, 0x28, 0x04, 0x0a} }, 4 }; // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceInterface_Bluetooth_DeviceAddress, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A, 1); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceInterface_Bluetooth_Manufacturer, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A, 4); // DEVPROP_TYPE_STRING
+DEFINE_PROPERTYKEY(PKEY_DeviceInterface_Bluetooth_ModelNumber, 0x2BD67D8B, 0x8BEB, 0x48D5, 0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A, 5); // DEVPROP_TYPE_STRING
 
 #endif
 
diff --git a/src/hidapi/windows/hidapi_descriptor_reconstruct.c b/src/hidapi/windows/hidapi_descriptor_reconstruct.c
new file mode 100644
index 0000000..a4efb25
--- /dev/null
+++ b/src/hidapi/windows/hidapi_descriptor_reconstruct.c
@@ -0,0 +1,987 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ libusb/hidapi Team
+
+ Copyright 2022, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+        https://github.com/libusb/hidapi .
+********************************************************/
+#include "hidapi_descriptor_reconstruct.h"
+
+/**
+ * @brief References to report descriptor buffer.
+ * 
+ */
+struct rd_buffer {
+	unsigned char* buf; /* Pointer to the array which stores the reconstructed descriptor */
+	size_t buf_size; /* Size of the buffer in bytes */
+	size_t byte_idx; /* Index of the next report byte to write to buf array */
+};
+
+/**
+ * @brief Function that appends a byte to encoded report descriptor buffer.
+ *
+ * @param[in]  byte     Single byte to append.
+ * @param      rpt_desc Pointer to report descriptor buffer struct.
+ */
+static void rd_append_byte(unsigned char byte, struct rd_buffer* rpt_desc) {
+	if (rpt_desc->byte_idx < rpt_desc->buf_size) {
+		rpt_desc->buf[rpt_desc->byte_idx] = byte;
+		rpt_desc->byte_idx++;
+	}
+}
+
+/**
+ * @brief Writes a short report descriptor item according USB HID spec 1.11 chapter 6.2.2.2.
+ *
+ * @param[in]  rd_item  Enumeration identifying type (Main, Global, Local) and function (e.g Usage or Report Count) of the item.
+ * @param[in]  data     Data (Size depends on rd_item 0,1,2 or 4bytes).
+ * @param      list     Chained list of report descriptor bytes.
+ *
+ * @return Returns 0 if successful, -1 for error.
+ */
+static int rd_write_short_item(rd_items rd_item, LONG64 data, struct rd_buffer* rpt_desc) {
+	if (rd_item & 0x03) {
+		// Invalid input data, last to bits are reserved for data size
+		return -1;
+	}
+
+	if (rd_item == rd_main_collection_end) {
+		// Item without data (1Byte prefix only)
+		unsigned char oneBytePrefix = (unsigned char) rd_item + 0x00;
+		rd_append_byte(oneBytePrefix, rpt_desc);
+	}
+	else if ((rd_item == rd_global_logical_minimum) ||
+		(rd_item == rd_global_logical_maximum) ||
+		(rd_item == rd_global_physical_minimum) ||
+		(rd_item == rd_global_physical_maximum)) {
+		// Item with signed integer data
+		if ((data >= -128) && (data <= 127)) {
+			// 1Byte prefix + 1Byte data
+			unsigned char oneBytePrefix = (unsigned char) rd_item + 0x01;
+			char localData = (char)data;
+			rd_append_byte(oneBytePrefix, rpt_desc);
+			rd_append_byte(localData & 0xFF, rpt_desc);
+		}
+		else if ((data >= -32768) && (data <= 32767)) {
+			// 1Byte prefix + 2Byte data
+			unsigned char oneBytePrefix = (unsigned char) rd_item + 0x02;
+			INT16 localData = (INT16)data;
+			rd_append_byte(oneBytePrefix, rpt_desc);
+			rd_append_byte(localData & 0xFF, rpt_desc);
+			rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
+		}
+		else if ((data >= -2147483648LL) && (data <= 2147483647)) {
+			// 1Byte prefix + 4Byte data
+			unsigned char oneBytePrefix = (unsigned char) rd_item + 0x03;
+			INT32 localData = (INT32)data;
+			rd_append_byte(oneBytePrefix, rpt_desc);
+			rd_append_byte(localData & 0xFF, rpt_desc);
+			rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
+			rd_append_byte(localData >> 16 & 0xFF, rpt_desc);
+			rd_append_byte(localData >> 24 & 0xFF, rpt_desc);
+		}
+		else {
+			// Data out of 32 bit signed integer range
+			return -1;
+		}
+	}
+	else {
+		// Item with unsigned integer data
+		if ((data >= 0) && (data <= 0xFF)) {
+			// 1Byte prefix + 1Byte data
+			unsigned char oneBytePrefix = (unsigned char) rd_item + 0x01;
+			unsigned char localData = (unsigned char)data;
+			rd_append_byte(oneBytePrefix, rpt_desc);
+			rd_append_byte(localData & 0xFF, rpt_desc);
+		}
+		else if ((data >= 0) && (data <= 0xFFFF)) {
+			// 1Byte prefix + 2Byte data
+			unsigned char oneBytePrefix = (unsigned char) rd_item + 0x02;
+			UINT16 localData = (UINT16)data;
+			rd_append_byte(oneBytePrefix, rpt_desc);
+			rd_append_byte(localData & 0xFF, rpt_desc);
+			rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
+		}
+		else if ((data >= 0) && (data <= 0xFFFFFFFF)) {
+			// 1Byte prefix + 4Byte data
+			unsigned char oneBytePrefix = (unsigned char) rd_item + 0x03;
+			UINT32 localData = (UINT32)data;
+			rd_append_byte(oneBytePrefix, rpt_desc);
+			rd_append_byte(localData & 0xFF, rpt_desc);
+			rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
+			rd_append_byte(localData >> 16 & 0xFF, rpt_desc);
+			rd_append_byte(localData >> 24 & 0xFF, rpt_desc);
+		}
+		else {
+			// Data out of 32 bit unsigned integer range
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static struct rd_main_item_node * rd_append_main_item_node(int first_bit, int last_bit, rd_node_type type_of_node, int caps_index, int collection_index, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) {
+	struct rd_main_item_node *new_list_node;
+
+	// Determine last node in the list
+	while (*list != NULL)
+	{
+		list = &(*list)->next;
+	}
+
+	new_list_node = malloc(sizeof(*new_list_node)); // Create new list entry
+	new_list_node->FirstBit = first_bit;
+	new_list_node->LastBit = last_bit;
+	new_list_node->TypeOfNode = type_of_node;
+	new_list_node->CapsIndex = caps_index;
+	new_list_node->CollectionIndex = collection_index;
+	new_list_node->MainItemType = main_item_type;
+	new_list_node->ReportID = report_id;
+	new_list_node->next = NULL; // NULL marks last node in the list
+
+	*list = new_list_node;
+	return new_list_node;
+}
+
+static struct  rd_main_item_node * rd_insert_main_item_node(int first_bit, int last_bit, rd_node_type type_of_node, int caps_index, int collection_index, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) {
+	// Insert item after the main item node referenced by list
+	struct rd_main_item_node *next_item = (*list)->next;
+	(*list)->next = NULL;
+	rd_append_main_item_node(first_bit, last_bit, type_of_node, caps_index, collection_index, main_item_type, report_id, list);
+	(*list)->next->next = next_item;
+	return (*list)->next;
+}
+
+static struct rd_main_item_node * rd_search_main_item_list_for_bit_position(int search_bit, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) {
+	// Determine first INPUT/OUTPUT/FEATURE main item, where the last bit position is equal or greater than the search bit position
+
+	while (((*list)->next->MainItemType != rd_collection) &&
+		((*list)->next->MainItemType != rd_collection_end) &&
+		!(((*list)->next->LastBit >= search_bit) &&
+			((*list)->next->ReportID == report_id) &&
+			((*list)->next->MainItemType == main_item_type))
+		)
+	{
+		list = &(*list)->next;
+	}
+	return *list;
+}
+
+int hid_winapi_descriptor_reconstruct_pp_data(void *preparsed_data, unsigned char *buf, size_t buf_size)
+{
+	hidp_preparsed_data *pp_data = (hidp_preparsed_data *) preparsed_data;
+
+	// Check if MagicKey is correct, to ensure that pp_data points to an valid preparse data structure
+	if (memcmp(pp_data->MagicKey, "HidP KDR", 8) != 0) {
+		return -1;
+	}
+
+	struct rd_buffer rpt_desc = {
+		.buf = buf,
+		.buf_size = buf_size,
+		.byte_idx = 0
+	};
+
+	// Set pointer to the first node of link_collection_nodes
+	phid_pp_link_collection_node link_collection_nodes = (phid_pp_link_collection_node)(((unsigned char*)&pp_data->caps[0]) + pp_data->FirstByteOfLinkCollectionArray);
+
+	// ****************************************************************************************************************************
+	// Create lookup tables for the bit range of each report per collection (position of first bit and last bit in each collection)
+	// coll_bit_range[COLLECTION_INDEX][REPORT_ID][INPUT/OUTPUT/FEATURE]
+	// ****************************************************************************************************************************
+	
+	// Allocate memory and initialize lookup table
+	rd_bit_range ****coll_bit_range;
+	coll_bit_range = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_bit_range));
+	for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
+		coll_bit_range[collection_node_idx] = malloc(256 * sizeof(*coll_bit_range[0])); // 256 possible report IDs (incl. 0x00)
+		for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
+			coll_bit_range[collection_node_idx][reportid_idx] = malloc(NUM_OF_HIDP_REPORT_TYPES * sizeof(*coll_bit_range[0][0]));
+			for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
+				coll_bit_range[collection_node_idx][reportid_idx][rt_idx] = malloc(sizeof(rd_bit_range));
+				coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit = -1;
+				coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit = -1;
+			}
+		}
+	}
+
+	// Fill the lookup table where caps exist
+	for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
+		for (USHORT caps_idx = pp_data->caps_info[rt_idx].FirstCap; caps_idx < pp_data->caps_info[rt_idx].LastCap; caps_idx++) {
+			int first_bit, last_bit;
+			first_bit = (pp_data->caps[caps_idx].BytePosition - 1) * 8
+			           + pp_data->caps[caps_idx].BitPosition;
+			last_bit = first_bit + pp_data->caps[caps_idx].ReportSize
+			                     * pp_data->caps[caps_idx].ReportCount - 1;
+			if (coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit == -1 ||
+				coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit > first_bit) {
+				coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit = first_bit;
+			}
+			if (coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->LastBit < last_bit) {
+				coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->LastBit = last_bit;
+			}
+		}
+	}
+
+	// *************************************************************************
+	// -Determine hierachy levels of each collections and store it in:
+	//  coll_levels[COLLECTION_INDEX]
+	// -Determine number of direct childs of each collections and store it in:
+	//  coll_number_of_direct_childs[COLLECTION_INDEX]
+	// *************************************************************************
+	int max_coll_level = 0;
+	int *coll_levels = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_levels[0]));
+	int *coll_number_of_direct_childs = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_number_of_direct_childs[0]));
+	for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
+		coll_levels[collection_node_idx] = -1;
+		coll_number_of_direct_childs[collection_node_idx] = 0;
+	}
+
+	{
+		int actual_coll_level = 0;
+		USHORT collection_node_idx = 0;
+		while (actual_coll_level >= 0) {
+			coll_levels[collection_node_idx] = actual_coll_level;
+			if ((link_collection_nodes[collection_node_idx].NumberOfChildren > 0) &&
+				(coll_levels[link_collection_nodes[collection_node_idx].FirstChild] == -1)) {
+				actual_coll_level++;
+				coll_levels[collection_node_idx] = actual_coll_level;
+				if (max_coll_level < actual_coll_level) {
+					max_coll_level = actual_coll_level;
+				}
+				coll_number_of_direct_childs[collection_node_idx]++;
+				collection_node_idx = link_collection_nodes[collection_node_idx].FirstChild;
+			}
+			else if (link_collection_nodes[collection_node_idx].NextSibling != 0) {
+				coll_number_of_direct_childs[link_collection_nodes[collection_node_idx].Parent]++;
+				collection_node_idx = link_collection_nodes[collection_node_idx].NextSibling;
+			}
+			else {
+				actual_coll_level--;
+				if (actual_coll_level >= 0) {
+					collection_node_idx = link_collection_nodes[collection_node_idx].Parent;
+				}
+			}
+		}
+	}
+
+	// *********************************************************************************
+	// Propagate the bit range of each report from the child collections to their parent
+	// and store the merged result for the parent
+	// *********************************************************************************
+	for (int actual_coll_level = max_coll_level - 1; actual_coll_level >= 0; actual_coll_level--) {
+		for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
+			if (coll_levels[collection_node_idx] == actual_coll_level) {
+				USHORT child_idx = link_collection_nodes[collection_node_idx].FirstChild;
+				while (child_idx) {
+					for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
+						for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
+							// Merge bit range from childs
+							if ((coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit != -1) &&
+								(coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit > coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit)) {
+								coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit = coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit;
+							}
+							if (coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit < coll_bit_range[child_idx][reportid_idx][rt_idx]->LastBit) {
+								coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit = coll_bit_range[child_idx][reportid_idx][rt_idx]->LastBit;
+							}
+							child_idx = link_collection_nodes[child_idx].NextSibling;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	// *************************************************************************************************
+	// Determine child collection order of the whole hierachy, based on previously determined bit ranges
+	// and store it this index coll_child_order[COLLECTION_INDEX][DIRECT_CHILD_INDEX]
+	// *************************************************************************************************
+	USHORT **coll_child_order;
+	coll_child_order = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_child_order));
+	{
+		BOOLEAN *coll_parsed_flag;
+		coll_parsed_flag = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_parsed_flag[0]));
+		for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
+			coll_parsed_flag[collection_node_idx] = FALSE;
+		}
+		int actual_coll_level = 0;
+		USHORT collection_node_idx = 0;
+		while (actual_coll_level >= 0) {
+			if ((coll_number_of_direct_childs[collection_node_idx] != 0) &&
+				(coll_parsed_flag[link_collection_nodes[collection_node_idx].FirstChild] == FALSE)) {
+				coll_parsed_flag[link_collection_nodes[collection_node_idx].FirstChild] = TRUE;
+				coll_child_order[collection_node_idx] = malloc((coll_number_of_direct_childs[collection_node_idx]) * sizeof(*coll_child_order[0]));
+
+				{
+					// Create list of child collection indices
+					// sorted reverse to the order returned to HidP_GetLinkCollectionNodeschild
+					// which seems to match teh original order, as long as no bit position needs to be considered
+					USHORT child_idx = link_collection_nodes[collection_node_idx].FirstChild;
+					int child_count = coll_number_of_direct_childs[collection_node_idx] - 1;
+					coll_child_order[collection_node_idx][child_count] = child_idx;
+					while (link_collection_nodes[child_idx].NextSibling) {
+						child_count--;
+						child_idx = link_collection_nodes[child_idx].NextSibling;
+						coll_child_order[collection_node_idx][child_count] = child_idx;
+					}
+				}
+
+				if (coll_number_of_direct_childs[collection_node_idx] > 1) {
+					// Sort child collections indices by bit positions
+					for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
+						for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
+							for (int child_idx = 1; child_idx < coll_number_of_direct_childs[collection_node_idx]; child_idx++) {
+								// since the coll_bit_range array is not sorted, we need to reference the collection index in 
+								// our sorted coll_child_order array, and look up the corresponding bit ranges for comparing values to sort
+								int prev_coll_idx = coll_child_order[collection_node_idx][child_idx - 1];
+								int cur_coll_idx = coll_child_order[collection_node_idx][child_idx];
+								if ((coll_bit_range[prev_coll_idx][reportid_idx][rt_idx]->FirstBit != -1) &&
+									(coll_bit_range[cur_coll_idx][reportid_idx][rt_idx]->FirstBit != -1) &&
+									(coll_bit_range[prev_coll_idx][reportid_idx][rt_idx]->FirstBit > coll_bit_range[cur_coll_idx][reportid_idx][rt_idx]->FirstBit)) {
+									// Swap position indices of the two compared child collections
+									USHORT idx_latch = coll_child_order[collection_node_idx][child_idx - 1];
+									coll_child_order[collection_node_idx][child_idx - 1] = coll_child_order[collection_node_idx][child_idx];
+									coll_child_order[collection_node_idx][child_idx] = idx_latch;
+								}
+							}
+						}
+					}
+				}
+				actual_coll_level++;
+				collection_node_idx = link_collection_nodes[collection_node_idx].FirstChild;
+			}
+			else if (link_collection_nodes[collection_node_idx].NextSibling != 0) {
+				collection_node_idx = link_collection_nodes[collection_node_idx].NextSibling;
+			}
+			else {
+				actual_coll_level--;
+				if (actual_coll_level >= 0) {
+					collection_node_idx = link_collection_nodes[collection_node_idx].Parent;
+				}
+			}
+		}
+		free(coll_parsed_flag);
+	}
+
+
+	// ***************************************************************************************
+	// Create sorted main_item_list containing all the Collection and CollectionEnd main items
+	// ***************************************************************************************
+	struct rd_main_item_node *main_item_list = NULL; // List root
+	// Lookup table to find the Collection items in the list by index
+	struct rd_main_item_node **coll_begin_lookup = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_begin_lookup));
+	struct rd_main_item_node **coll_end_lookup = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_end_lookup));
+	{
+		int *coll_last_written_child = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_last_written_child[0]));
+		for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
+			coll_last_written_child[collection_node_idx] = -1;
+		}
+
+		int actual_coll_level = 0;
+		USHORT collection_node_idx = 0;
+		struct rd_main_item_node *firstDelimiterNode = NULL;
+		struct rd_main_item_node *delimiterCloseNode = NULL;
+		coll_begin_lookup[0] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list);
+		while (actual_coll_level >= 0) {
+			if ((coll_number_of_direct_childs[collection_node_idx] != 0) &&
+				(coll_last_written_child[collection_node_idx] == -1)) {
+				// Collection has child collections, but none is written to the list yet
+
+				coll_last_written_child[collection_node_idx] = coll_child_order[collection_node_idx][0];
+				collection_node_idx = coll_child_order[collection_node_idx][0];
+
+				// In a HID Report Descriptor, the first usage declared is the most preferred usage for the control.
+				// While the order in the WIN32 capabiliy strutures is the opposite:
+				// Here the preferred usage is the last aliased usage in the sequence.
+
+				if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode == NULL)) {
+					// Alliased Collection (First node in link_collection_nodes -> Last entry in report descriptor output)
+					firstDelimiterNode = main_item_list;
+					coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &main_item_list);
+					coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_close, 0, &main_item_list);
+					delimiterCloseNode = main_item_list;
+				}
+				else {
+					// Normal not aliased collection
+					coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list);
+					actual_coll_level++;
+				}
+
+
+			}
+			else if ((coll_number_of_direct_childs[collection_node_idx] > 1) &&
+				(coll_last_written_child[collection_node_idx] != coll_child_order[collection_node_idx][coll_number_of_direct_childs[collection_node_idx] - 1])) {
+				// Collection has child collections, and this is not the first child
+
+				int nextChild = 1;
+				while (coll_last_written_child[collection_node_idx] != coll_child_order[collection_node_idx][nextChild - 1]) {
+					nextChild++;
+				}
+				coll_last_written_child[collection_node_idx] = coll_child_order[collection_node_idx][nextChild];
+				collection_node_idx = coll_child_order[collection_node_idx][nextChild];
+												
+				if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode == NULL)) {
+					// Alliased Collection (First node in link_collection_nodes -> Last entry in report descriptor output)
+					firstDelimiterNode = main_item_list;
+					coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &main_item_list);
+					coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_close, 0, &main_item_list);
+					delimiterCloseNode = main_item_list;
+				}
+				else if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode != NULL)) {
+					coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &firstDelimiterNode);
+				}
+				else if (!link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode != NULL)) {
+					coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &firstDelimiterNode);
+					coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_open, 0, &firstDelimiterNode);
+					firstDelimiterNode = NULL;
+					main_item_list = delimiterCloseNode;
+					delimiterCloseNode = NULL; // Last entry of alias has .IsAlias == FALSE
+				}
+				if (!link_collection_nodes[collection_node_idx].IsAlias) {
+					coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list);
+					actual_coll_level++;
+				}
+			}
+			else {
+				actual_coll_level--;
+				coll_end_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection_end, 0, &main_item_list);
+				collection_node_idx = link_collection_nodes[collection_node_idx].Parent;
+			}
+		}
+		free(coll_last_written_child);
+	}
+
+
+	// ****************************************************************
+	// Inserted Input/Output/Feature main items into the main_item_list
+	// in order of reconstructed bit positions
+	// ****************************************************************
+	for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
+		// Add all value caps to node list
+		struct rd_main_item_node *firstDelimiterNode = NULL;
+		struct rd_main_item_node *delimiterCloseNode = NULL;
+		for (USHORT caps_idx = pp_data->caps_info[rt_idx].FirstCap; caps_idx < pp_data->caps_info[rt_idx].LastCap; caps_idx++) {
+			struct rd_main_item_node *coll_begin = coll_begin_lookup[pp_data->caps[caps_idx].LinkCollection];
+			int first_bit, last_bit;
+			first_bit = (pp_data->caps[caps_idx].BytePosition - 1) * 8 +
+				pp_data->caps[caps_idx].BitPosition;
+			last_bit = first_bit + pp_data->caps[caps_idx].ReportSize *
+				pp_data->caps[caps_idx].ReportCount - 1;
+
+			for (int child_idx = 0; child_idx < coll_number_of_direct_childs[pp_data->caps[caps_idx].LinkCollection]; child_idx++) {
+				// Determine in which section before/between/after child collection the item should be inserted
+				if (first_bit < coll_bit_range[coll_child_order[pp_data->caps[caps_idx].LinkCollection][child_idx]][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit)
+				{
+					// Note, that the default value for undefined coll_bit_range is -1, which can't be greater than the bit position
+					break;
+				}
+				coll_begin = coll_end_lookup[coll_child_order[pp_data->caps[caps_idx].LinkCollection][child_idx]];
+			}
+			struct rd_main_item_node *list_node;
+			list_node = rd_search_main_item_list_for_bit_position(first_bit, (rd_main_items) rt_idx, pp_data->caps[caps_idx].ReportID, &coll_begin);
+
+			// In a HID Report Descriptor, the first usage declared is the most preferred usage for the control.
+			// While the order in the WIN32 capabiliy strutures is the opposite:
+			// Here the preferred usage is the last aliased usage in the sequence.
+
+			if (pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode == NULL)) {
+				// Alliased Usage (First node in pp_data->caps -> Last entry in report descriptor output)
+				firstDelimiterNode = list_node;
+				rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node);
+				rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_close, pp_data->caps[caps_idx].ReportID, &list_node);
+				delimiterCloseNode = list_node;
+			} else if (pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode != NULL)) {
+				rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node);
+			}
+			else if (!pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode != NULL)) {
+				// Alliased Collection (Last node in pp_data->caps -> First entry in report descriptor output)
+				rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node);
+				rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_open, pp_data->caps[caps_idx].ReportID, &list_node);
+				firstDelimiterNode = NULL;
+				list_node = delimiterCloseNode;
+				delimiterCloseNode = NULL; // Last entry of alias has .IsAlias == FALSE
+			}
+			if (!pp_data->caps[caps_idx].IsAlias) {
+				rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, (rd_main_items) rt_idx, pp_data->caps[caps_idx].ReportID, &list_node);
+			}
+		}
+	}
+
+
+	// ***********************************************************
+	// Add const main items for padding to main_item_list
+	// -To fill all bit gaps
+	// -At each report end for 8bit padding
+	//  Note that information about the padding at the report end,
+	//  is not stored in the preparsed data, but in practice all
+	//  report descriptors seem to have it, as assumed here.
+	// ***********************************************************
+	{
+		int last_bit_position[NUM_OF_HIDP_REPORT_TYPES][256];
+		struct rd_main_item_node *last_report_item_lookup[NUM_OF_HIDP_REPORT_TYPES][256];
+		for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
+			for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
+				last_bit_position[rt_idx][reportid_idx] = -1;
+				last_report_item_lookup[rt_idx][reportid_idx] = NULL;
+			}
+		}
+
+		struct rd_main_item_node *list = main_item_list; // List root;
+
+		while (list->next != NULL)
+		{
+			if ((list->MainItemType >= rd_input) &&
+				(list->MainItemType <= rd_feature)) {
+				// INPUT, OUTPUT or FEATURE
+				if (list->FirstBit != -1) {
+					if ((last_bit_position[list->MainItemType][list->ReportID] + 1 != list->FirstBit) &&
+						(last_report_item_lookup[list->MainItemType][list->ReportID] != NULL) &&
+						(last_report_item_lookup[list->MainItemType][list->ReportID]->FirstBit != list->FirstBit) // Happens in case of IsMultipleItemsForArray for multiple dedicated usages for a multi-button array
+						) {
+						struct rd_main_item_node *list_node = rd_search_main_item_list_for_bit_position(last_bit_position[list->MainItemType][list->ReportID], list->MainItemType, list->ReportID, &last_report_item_lookup[list->MainItemType][list->ReportID]);
+						rd_insert_main_item_node(last_bit_position[list->MainItemType][list->ReportID] + 1, list->FirstBit - 1, rd_item_node_padding, -1, 0, list->MainItemType, list->ReportID, &list_node);
+					}
+					last_bit_position[list->MainItemType][list->ReportID] = list->LastBit;
+					last_report_item_lookup[list->MainItemType][list->ReportID] = list;
+				}
+			}
+			list = list->next;
+		}
+		// Add 8 bit padding at each report end
+		for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
+			for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
+				if (last_bit_position[rt_idx][reportid_idx] != -1) {
+					int padding = 8 - ((last_bit_position[rt_idx][reportid_idx] + 1) % 8);
+					if (padding < 8) {
+						// Insert padding item after item referenced in last_report_item_lookup
+						rd_insert_main_item_node(last_bit_position[rt_idx][reportid_idx] + 1, last_bit_position[rt_idx][reportid_idx] + padding, rd_item_node_padding, -1, 0, (rd_main_items) rt_idx, (unsigned char) reportid_idx, &last_report_item_lookup[rt_idx][reportid_idx]);
+					}
+				}
+			}
+		}
+	}
+
+
+	// ***********************************
+	// Encode the report descriptor output
+	// ***********************************
+	UCHAR last_report_id = 0;
+	USAGE last_usage_page = 0;
+	LONG last_physical_min = 0;// If both, Physical Minimum and Physical Maximum are 0, the logical limits should be taken as physical limits according USB HID spec 1.11 chapter 6.2.2.7
+	LONG last_physical_max = 0;
+	ULONG last_unit_exponent = 0; // If Unit Exponent is Undefined it should be considered as 0 according USB HID spec 1.11 chapter 6.2.2.7
+	ULONG last_unit = 0; // If the first nibble is 7, or second nibble of Unit is 0, the unit is None according USB HID spec 1.11 chapter 6.2.2.7
+	BOOLEAN inhibit_write_of_usage = FALSE; // Needed in case of delimited usage print, before the normal collection or cap
+	int report_count = 0;
+	while (main_item_list != NULL)
+	{
+		int rt_idx = main_item_list->MainItemType;
+		int	caps_idx = main_item_list->CapsIndex;
+		if (main_item_list->MainItemType == rd_collection) {
+			if (last_usage_page != link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage) {
+				// Write "Usage Page" at the begin of a collection - except it refers the same table as wrote last 
+				rd_write_short_item(rd_global_usage_page, link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage, &rpt_desc);
+				last_usage_page = link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage;
+			}
+			if (inhibit_write_of_usage) {
+				// Inhibit only once after DELIMITER statement
+				inhibit_write_of_usage = FALSE;
+			}
+			else {
+				// Write "Usage" of collection
+				rd_write_short_item(rd_local_usage, link_collection_nodes[main_item_list->CollectionIndex].LinkUsage, &rpt_desc);
+			}
+			// Write begin of "Collection" 
+			rd_write_short_item(rd_main_collection, link_collection_nodes[main_item_list->CollectionIndex].CollectionType, &rpt_desc);
+		}
+		else if (main_item_list->MainItemType == rd_collection_end) {
+			// Write "End Collection"
+			rd_write_short_item(rd_main_collection_end, 0, &rpt_desc);
+		}
+		else if (main_item_list->MainItemType == rd_delimiter_open) {
+			if (main_item_list->CollectionIndex != -1) {
+				// Write "Usage Page" inside of a collection delmiter section
+				if (last_usage_page != link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage) {
+					rd_write_short_item(rd_global_usage_page, link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage, &rpt_desc);
+					last_usage_page = link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage;
+				}
+			}
+			else if (main_item_list->CapsIndex != 0) {
+				// Write "Usage Page" inside of a main item delmiter section
+				if (pp_data->caps[caps_idx].UsagePage != last_usage_page) {
+					rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc);
+					last_usage_page = pp_data->caps[caps_idx].UsagePage;
+				}
+			}
+			// Write "Delimiter Open"
+			rd_write_short_item(rd_local_delimiter, 1, &rpt_desc); // 1 = open set of aliased usages
+		}
+		else if (main_item_list->MainItemType == rd_delimiter_usage) {
+			if (main_item_list->CollectionIndex != -1) {
+				// Write aliased collection "Usage"
+				rd_write_short_item(rd_local_usage, link_collection_nodes[main_item_list->CollectionIndex].LinkUsage, &rpt_desc);
+			}  if (main_item_list->CapsIndex != 0) {
+				// Write aliased main item range from "Usage Minimum" to "Usage Maximum"
+				if (pp_data->caps[caps_idx].IsRange) {
+					rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc);
+					rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc);
+				}
+				else {
+					// Write single aliased main item "Usage"
+					rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc);
+				}
+			}
+		}
+		else if (main_item_list->MainItemType == rd_delimiter_close) {
+			// Write "Delimiter Close"
+			rd_write_short_item(rd_local_delimiter, 0, &rpt_desc); // 0 = close set of aliased usages
+			// Inhibit next usage write
+			inhibit_write_of_usage = TRUE;
+		}
+		else if (main_item_list->TypeOfNode == rd_item_node_padding) {
+			// Padding
+			// The preparsed data doesn't contain any information about padding. Therefore all undefined gaps
+			// in the reports are filled with the same style of constant padding. 
+
+			// Write "Report Size" with number of padding bits
+			rd_write_short_item(rd_global_report_size, (main_item_list->LastBit - main_item_list->FirstBit + 1), &rpt_desc);
+
+			// Write "Report Count" for padding always as 1
+			rd_write_short_item(rd_global_report_count, 1, &rpt_desc);
+
+			if (rt_idx == HidP_Input) {
+				// Write "Input" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const
+				rd_write_short_item(rd_main_input, 0x03, &rpt_desc); // Const / Abs
+			}
+			else if (rt_idx == HidP_Output) {
+				// Write "Output" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const
+				rd_write_short_item(rd_main_output, 0x03, &rpt_desc); // Const / Abs
+			}
+			else if (rt_idx == HidP_Feature) {
+				// Write "Feature" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const
+				rd_write_short_item(rd_main_feature, 0x03, &rpt_desc); // Const / Abs
+			}
+			report_count = 0;
+		}
+		else if (pp_data->caps[caps_idx].IsButtonCap) {
+			// Button
+			// (The preparsed data contain different data for 1 bit Button caps, than for parametric Value caps)
+
+			if (last_report_id != pp_data->caps[caps_idx].ReportID) {
+				// Write "Report ID" if changed
+				rd_write_short_item(rd_global_report_id, pp_data->caps[caps_idx].ReportID, &rpt_desc);
+				last_report_id = pp_data->caps[caps_idx].ReportID;
+			}
+
+			// Write "Usage Page" when changed
+			if (pp_data->caps[caps_idx].UsagePage != last_usage_page) {
+				rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc);
+				last_usage_page = pp_data->caps[caps_idx].UsagePage;
+			}
+
+			// Write only local report items for each cap, if ReportCount > 1
+			if (pp_data->caps[caps_idx].IsRange) {
+				report_count += (pp_data->caps[caps_idx].Range.DataIndexMax - pp_data->caps[caps_idx].Range.DataIndexMin);
+			}
+
+			if (inhibit_write_of_usage) {
+				// Inhibit only once after Delimiter - Reset flag
+				inhibit_write_of_usage = FALSE;
+			}
+			else {
+				if (pp_data->caps[caps_idx].IsRange) {
+					// Write range from "Usage Minimum" to "Usage Maximum"
+					rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc);
+					rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc);
+				}
+				else {
+					// Write single "Usage"
+					rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc);
+				}
+			}
+
+			if (pp_data->caps[caps_idx].IsDesignatorRange) {
+				// Write physical descriptor indices range from "Designator Minimum" to "Designator Maximum"
+				rd_write_short_item(rd_local_designator_minimum, pp_data->caps[caps_idx].Range.DesignatorMin, &rpt_desc);
+				rd_write_short_item(rd_local_designator_maximum, pp_data->caps[caps_idx].Range.DesignatorMax, &rpt_desc);
+			}
+			else if (pp_data->caps[caps_idx].NotRange.DesignatorIndex != 0) {
+				// Designator set 0 is a special descriptor set (of the HID Physical Descriptor),
+				// that specifies the number of additional descriptor sets.
+				// Therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
+				// Write single "Designator Index"
+				rd_write_short_item(rd_local_designator_index, pp_data->caps[caps_idx].NotRange.DesignatorIndex, &rpt_desc);
+			}
+
+			if (pp_data->caps[caps_idx].IsStringRange) {
+				// Write range of indices of the USB string descriptor, from "String Minimum" to "String Maximum"
+				rd_write_short_item(rd_local_string_minimum, pp_data->caps[caps_idx].Range.StringMin, &rpt_desc);
+				rd_write_short_item(rd_local_string_maximum, pp_data->caps[caps_idx].Range.StringMax, &rpt_desc);
+			}
+			else if (pp_data->caps[caps_idx].NotRange.StringIndex != 0) {
+				// String Index 0 is a special entry of the USB string descriptor, that contains a list of supported languages,
+				// therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
+				// Write single "String Index"
+				rd_write_short_item(rd_local_string, pp_data->caps[caps_idx].NotRange.StringIndex, &rpt_desc);
+			}
+
+			if ((main_item_list->next != NULL) &&
+				((int)main_item_list->next->MainItemType == rt_idx) &&
+				(main_item_list->next->TypeOfNode == rd_item_node_cap) &&
+				(pp_data->caps[main_item_list->next->CapsIndex].IsButtonCap) &&
+				(!pp_data->caps[caps_idx].IsRange) && // This node in list is no array
+				(!pp_data->caps[main_item_list->next->CapsIndex].IsRange) && // Next node in list is no array
+				(pp_data->caps[main_item_list->next->CapsIndex].UsagePage == pp_data->caps[caps_idx].UsagePage) &&
+				(pp_data->caps[main_item_list->next->CapsIndex].ReportID == pp_data->caps[caps_idx].ReportID) &&
+				(pp_data->caps[main_item_list->next->CapsIndex].BitField == pp_data->caps[caps_idx].BitField)
+				) {
+				if (main_item_list->next->FirstBit != main_item_list->FirstBit) {
+					// In case of IsMultipleItemsForArray for multiple dedicated usages for a multi-button array, the report count should be incremented 
+							
+					// Skip global items until any of them changes, than use ReportCount item to write the count of identical report fields
+					report_count++;
+				}
+			}
+			else {
+
+				if ((pp_data->caps[caps_idx].Button.LogicalMin == 0) &&
+					(pp_data->caps[caps_idx].Button.LogicalMax == 0)) {
+					// While a HID report descriptor must always contain LogicalMinimum and LogicalMaximum,
+					// the preparsed data contain both fields set to zero, for the case of simple buttons
+					// Write "Logical Minimum" set to 0 and "Logical Maximum" set to 1
+					rd_write_short_item(rd_global_logical_minimum, 0, &rpt_desc);
+					rd_write_short_item(rd_global_logical_maximum, 1, &rpt_desc);
+				}
+				else {
+					// Write logical range from "Logical Minimum" to "Logical Maximum"
+					rd_write_short_item(rd_global_logical_minimum, pp_data->caps[caps_idx].Button.LogicalMin, &rpt_desc);
+					rd_write_short_item(rd_global_logical_maximum, pp_data->caps[caps_idx].Button.LogicalMax, &rpt_desc);
+				}
+
+				// Write "Report Size"
+				rd_write_short_item(rd_global_report_size, pp_data->caps[caps_idx].ReportSize, &rpt_desc);
+
+				// Write "Report Count"
+				if (!pp_data->caps[caps_idx].IsRange) {
+					// Variable bit field with one bit per button
+					// In case of multiple usages with the same items, only "Usage" is written per cap, and "Report Count" is incremented
+					rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount + report_count, &rpt_desc);
+				}
+				else {
+					// Button array of "Report Size" x "Report Count
+					rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount, &rpt_desc);
+				}
+
+
+				// Buttons have only 1 bit and therefore no physical limits/units -> Set to undefined state
+				if (last_physical_min != 0) {
+					// Write "Physical Minimum", but only if changed
+					last_physical_min = 0;
+					rd_write_short_item(rd_global_physical_minimum, last_physical_min, &rpt_desc);
+				}
+				if (last_physical_max != 0) {
+					// Write "Physical Maximum", but only if changed
+					last_physical_max = 0;
+					rd_write_short_item(rd_global_physical_maximum, last_physical_max, &rpt_desc);
+				}
+				if (last_unit_exponent != 0) {
+					// Write "Unit Exponent", but only if changed
+					last_unit_exponent = 0;
+					rd_write_short_item(rd_global_unit_exponent, last_unit_exponent, &rpt_desc);
+				}
+				if (last_unit != 0) {
+					// Write "Unit",but only if changed
+					last_unit = 0;
+					rd_write_short_item(rd_global_unit, last_unit, &rpt_desc);
+				}
+
+				// Write "Input" main item
+				if (rt_idx == HidP_Input) {
+					rd_write_short_item(rd_main_input, pp_data->caps[caps_idx].BitField, &rpt_desc);
+				}
+				// Write "Output" main item
+				else if (rt_idx == HidP_Output) {
+					rd_write_short_item(rd_main_output, pp_data->caps[caps_idx].BitField, &rpt_desc);
+				}
+				// Write "Feature" main item
+				else if (rt_idx == HidP_Feature) {
+					rd_write_short_item(rd_main_feature, pp_data->caps[caps_idx].BitField, &rpt_desc);
+				}
+				report_count = 0;
+			}
+		}
+		else {
+
+			if (last_report_id != pp_data->caps[caps_idx].ReportID) {
+				// Write "Report ID" if changed
+				rd_write_short_item(rd_global_report_id, pp_data->caps[caps_idx].ReportID, &rpt_desc);
+				last_report_id = pp_data->caps[caps_idx].ReportID;
+			}
+
+			// Write "Usage Page" if changed
+			if (pp_data->caps[caps_idx].UsagePage != last_usage_page) {
+				rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc);
+				last_usage_page = pp_data->caps[caps_idx].UsagePage;
+			}
+
+			if (inhibit_write_of_usage) {
+				// Inhibit only once after Delimiter - Reset flag
+				inhibit_write_of_usage = FALSE;
+			}
+			else {
+				if (pp_data->caps[caps_idx].IsRange) {
+					// Write usage range from "Usage Minimum" to "Usage Maximum"
+					rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc);
+					rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc);
+				}
+				else {
+					// Write single "Usage"
+					rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc);
+				}
+			}
+
+			if (pp_data->caps[caps_idx].IsDesignatorRange) {
+				// Write physical descriptor indices range from "Designator Minimum" to "Designator Maximum"
+				rd_write_short_item(rd_local_designator_minimum, pp_data->caps[caps_idx].Range.DesignatorMin, &rpt_desc);
+				rd_write_short_item(rd_local_designator_maximum, pp_data->caps[caps_idx].Range.DesignatorMax, &rpt_desc);
+			}
+			else if (pp_data->caps[caps_idx].NotRange.DesignatorIndex != 0) {
+				// Designator set 0 is a special descriptor set (of the HID Physical Descriptor),
+				// that specifies the number of additional descriptor sets.
+				// Therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
+				// Write single "Designator Index"
+				rd_write_short_item(rd_local_designator_index, pp_data->caps[caps_idx].NotRange.DesignatorIndex, &rpt_desc);
+			}
+
+			if (pp_data->caps[caps_idx].IsStringRange) {
+				// Write range of indices of the USB string descriptor, from "String Minimum" to "String Maximum"
+				rd_write_short_item(rd_local_string_minimum, pp_data->caps[caps_idx].Range.StringMin, &rpt_desc);
+				rd_write_short_item(rd_local_string_maximum, pp_data->caps[caps_idx].Range.StringMax, &rpt_desc);
+			}
+			else if (pp_data->caps[caps_idx].NotRange.StringIndex != 0) {
+				// String Index 0 is a special entry of the USB string descriptor, that contains a list of supported languages,
+				// therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
+				// Write single "String Index"
+				rd_write_short_item(rd_local_string, pp_data->caps[caps_idx].NotRange.StringIndex, &rpt_desc);
+			}
+
+			if ((pp_data->caps[caps_idx].BitField & 0x02) != 0x02) {
+				// In case of an value array overwrite "Report Count"
+				pp_data->caps[caps_idx].ReportCount = pp_data->caps[caps_idx].Range.DataIndexMax - pp_data->caps[caps_idx].Range.DataIndexMin + 1;
+			}
+
+
+			// Print only local report items for each cap, if ReportCount > 1
+			if ((main_item_list->next != NULL) &&
+				((int) main_item_list->next->MainItemType == rt_idx) &&
+				(main_item_list->next->TypeOfNode == rd_item_node_cap) &&
+				(!pp_data->caps[main_item_list->next->CapsIndex].IsButtonCap) &&
+				(!pp_data->caps[caps_idx].IsRange) && // This node in list is no array
+				(!pp_data->caps[main_item_list->next->CapsIndex].IsRange) && // Next node in list is no array
+				(pp_data->caps[main_item_list->next->CapsIndex].UsagePage == pp_data->caps[caps_idx].UsagePage) &&
+				(pp_data->caps[main_item_list->next->CapsIndex].NotButton.LogicalMin == pp_data->caps[caps_idx].NotButton.LogicalMin) &&
+				(pp_data->caps[main_item_list->next->CapsIndex].NotButton.LogicalMax == pp_data->caps[caps_idx].NotButton.LogicalMax) &&
+				(pp_data->caps[main_item_list->next->CapsIndex].NotButton.PhysicalMin == pp_data->caps[caps_idx].NotButton.PhysicalMin) &&
+				(pp_data->caps[main_item_list->next->CapsIndex].NotButton.PhysicalMax == pp_data->caps[caps_idx].NotButton.PhysicalMax) &&
+				(pp_data->caps[main_item_list->next->CapsIndex].UnitsExp == pp_data->caps[caps_idx].UnitsExp) &&
+				(pp_data->caps[main_item_list->next->CapsIndex].Units == pp_data->caps[caps_idx].Units) &&
+				(pp_data->caps[main_item_list->next->CapsIndex].ReportSize == pp_data->caps[caps_idx].ReportSize) &&
+				(pp_data->caps[main_item_list->next->CapsIndex].ReportID == pp_data->caps[caps_idx].ReportID) &&
+				(pp_data->caps[main_item_list->next->CapsIndex].BitField == pp_data->caps[caps_idx].BitField) &&
+				(pp_data->caps[main_item_list->next->CapsIndex].ReportCount == 1) &&
+				(pp_data->caps[caps_idx].ReportCount == 1)
+				) {
+				// Skip global items until any of them changes, than use ReportCount item to write the count of identical report fields
+				report_count++;
+			}
+			else {
+				// Value
+
+				// Write logical range from "Logical Minimum" to "Logical Maximum"
+				rd_write_short_item(rd_global_logical_minimum, pp_data->caps[caps_idx].NotButton.LogicalMin, &rpt_desc);
+				rd_write_short_item(rd_global_logical_maximum, pp_data->caps[caps_idx].NotButton.LogicalMax, &rpt_desc);
+
+				if ((last_physical_min != pp_data->caps[caps_idx].NotButton.PhysicalMin) ||
+					(last_physical_max != pp_data->caps[caps_idx].NotButton.PhysicalMax)) {
+					// Write range from "Physical Minimum" to " Physical Maximum", but only if one of them changed
+					rd_write_short_item(rd_global_physical_minimum, pp_data->caps[caps_idx].NotButton.PhysicalMin, &rpt_desc);
+					last_physical_min = pp_data->caps[caps_idx].NotButton.PhysicalMin;
+					rd_write_short_item(rd_global_physical_maximum, pp_data->caps[caps_idx].NotButton.PhysicalMax, &rpt_desc);
+					last_physical_max = pp_data->caps[caps_idx].NotButton.PhysicalMax;
+				}
+
+
+				if (last_unit_exponent != pp_data->caps[caps_idx].UnitsExp) {
+					// Write "Unit Exponent", but only if changed
+					rd_write_short_item(rd_global_unit_exponent, pp_data->caps[caps_idx].UnitsExp, &rpt_desc);
+					last_unit_exponent = pp_data->caps[caps_idx].UnitsExp;
+				}
+
+				if (last_unit != pp_data->caps[caps_idx].Units) {
+					// Write physical "Unit", but only if changed
+					rd_write_short_item(rd_global_unit, pp_data->caps[caps_idx].Units, &rpt_desc);
+					last_unit = pp_data->caps[caps_idx].Units;
+				}
+
+				// Write "Report Size"
+				rd_write_short_item(rd_global_report_size, pp_data->caps[caps_idx].ReportSize, &rpt_desc);
+
+				// Write "Report Count"
+				rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount + report_count, &rpt_desc);
+
+				if (rt_idx == HidP_Input) {
+					// Write "Input" main item
+					rd_write_short_item(rd_main_input, pp_data->caps[caps_idx].BitField, &rpt_desc);
+				}
+				else if (rt_idx == HidP_Output) {
+					// Write "Output" main item
+					rd_write_short_item(rd_main_output, pp_data->caps[caps_idx].BitField, &rpt_desc);
+				}
+				else if (rt_idx == HidP_Feature) {
+					// Write "Feature" main item
+					rd_write_short_item(rd_main_feature, pp_data->caps[caps_idx].BitField, &rpt_desc);
+				}
+				report_count = 0;
+			}
+		}
+
+		// Go to next item in main_item_list and free the memory of the actual item
+		struct rd_main_item_node *main_item_list_prev = main_item_list;
+		main_item_list = main_item_list->next;
+		free(main_item_list_prev);
+	}
+
+	// Free multidimensionable array: coll_bit_range[COLLECTION_INDEX][REPORT_ID][INPUT/OUTPUT/FEATURE]
+	// Free multidimensionable array: coll_child_order[COLLECTION_INDEX][DIRECT_CHILD_INDEX]
+	for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
+		for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
+			for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
+				free(coll_bit_range[collection_node_idx][reportid_idx][rt_idx]);
+			}
+			free(coll_bit_range[collection_node_idx][reportid_idx]);
+		}
+		free(coll_bit_range[collection_node_idx]);
+		if (coll_number_of_direct_childs[collection_node_idx] != 0) free(coll_child_order[collection_node_idx]);
+	}
+	free(coll_bit_range);
+	free(coll_child_order);
+
+	// Free one dimensional arrays
+	free(coll_begin_lookup);
+	free(coll_end_lookup);
+	free(coll_levels);
+	free(coll_number_of_direct_childs);
+
+	return (int) rpt_desc.byte_idx;
+}
diff --git a/src/hidapi/windows/hidapi_descriptor_reconstruct.h b/src/hidapi/windows/hidapi_descriptor_reconstruct.h
new file mode 100644
index 0000000..2ec8b20
--- /dev/null
+++ b/src/hidapi/windows/hidapi_descriptor_reconstruct.h
@@ -0,0 +1,238 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ libusb/hidapi Team
+
+ Copyright 2022, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+        https://github.com/libusb/hidapi .
+********************************************************/
+#ifndef HIDAPI_DESCRIPTOR_RECONSTRUCT_H__
+#define HIDAPI_DESCRIPTOR_RECONSTRUCT_H__
+
+#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
+/* Do not warn about wcsncpy usage.
+   https://docs.microsoft.com/cpp/c-runtime-library/security-features-in-the-crt */
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include "hidapi_winapi.h"
+
+#if _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4200)
+#pragma warning(disable: 4201)
+#endif
+
+#include <windows.h>
+
+#include "hidapi_hidsdi.h"
+
+#define NUM_OF_HIDP_REPORT_TYPES 3
+
+typedef enum rd_items_ {
+	rd_main_input               = 0x80, /* 1000 00 nn */
+	rd_main_output              = 0x90, /* 1001 00 nn */
+	rd_main_feature             = 0xB0, /* 1011 00 nn */
+	rd_main_collection          = 0xA0, /* 1010 00 nn */
+	rd_main_collection_end      = 0xC0, /* 1100 00 nn */
+	rd_global_usage_page        = 0x04, /* 0000 01 nn */
+	rd_global_logical_minimum   = 0x14, /* 0001 01 nn */
+	rd_global_logical_maximum   = 0x24, /* 0010 01 nn */
+	rd_global_physical_minimum  = 0x34, /* 0011 01 nn */
+	rd_global_physical_maximum  = 0x44, /* 0100 01 nn */
+	rd_global_unit_exponent     = 0x54, /* 0101 01 nn */
+	rd_global_unit              = 0x64, /* 0110 01 nn */
+	rd_global_report_size       = 0x74, /* 0111 01 nn */
+	rd_global_report_id         = 0x84, /* 1000 01 nn */
+	rd_global_report_count      = 0x94, /* 1001 01 nn */
+	rd_global_push              = 0xA4, /* 1010 01 nn */
+	rd_global_pop               = 0xB4, /* 1011 01 nn */
+	rd_local_usage              = 0x08, /* 0000 10 nn */
+	rd_local_usage_minimum      = 0x18, /* 0001 10 nn */
+	rd_local_usage_maximum      = 0x28, /* 0010 10 nn */
+	rd_local_designator_index   = 0x38, /* 0011 10 nn */
+	rd_local_designator_minimum = 0x48, /* 0100 10 nn */
+	rd_local_designator_maximum = 0x58, /* 0101 10 nn */
+	rd_local_string             = 0x78, /* 0111 10 nn */
+	rd_local_string_minimum     = 0x88, /* 1000 10 nn */
+	rd_local_string_maximum     = 0x98, /* 1001 10 nn */
+	rd_local_delimiter          = 0xA8  /* 1010 10 nn */
+} rd_items;
+
+typedef enum rd_main_items_ {
+	rd_input = HidP_Input,
+	rd_output = HidP_Output,
+	rd_feature = HidP_Feature,
+	rd_collection,
+	rd_collection_end,
+	rd_delimiter_open,
+	rd_delimiter_usage,
+	rd_delimiter_close,
+} rd_main_items;
+
+typedef struct rd_bit_range_ {
+	int FirstBit;
+	int LastBit;
+} rd_bit_range;
+
+typedef enum rd_item_node_type_ {
+	rd_item_node_cap,
+	rd_item_node_padding,
+	rd_item_node_collection,
+} rd_node_type;
+
+struct rd_main_item_node {
+	int FirstBit; /* Position of first bit in report (counting from 0) */
+	int LastBit; /* Position of last bit in report (counting from 0) */
+	rd_node_type TypeOfNode; /* Information if caps index refers to the array of button caps, value caps,
+	                            or if the node is just a padding element to fill unused bit positions.
+	                            The node can also be a collection node without any bits in the report. */
+	int CapsIndex; /* Index in the array of caps */
+	int CollectionIndex; /* Index in the array of link collections */
+	rd_main_items MainItemType; /* Input, Output, Feature, Collection or Collection End */
+	unsigned char ReportID;
+	struct rd_main_item_node* next;
+};
+
+typedef struct hid_pp_caps_info_ {
+	USHORT FirstCap;
+	USHORT NumberOfCaps; // Includes empty caps after LastCap 
+	USHORT LastCap;
+	USHORT ReportByteLength;
+} hid_pp_caps_info, *phid_pp_caps_info;
+
+typedef struct hid_pp_link_collection_node_ {
+	USAGE  LinkUsage;
+	USAGE  LinkUsagePage;
+	USHORT Parent;
+	USHORT NumberOfChildren;
+	USHORT NextSibling;
+	USHORT FirstChild;
+	ULONG  CollectionType : 8;
+	ULONG  IsAlias : 1;
+	ULONG  Reserved : 23;
+	// Same as the public API structure HIDP_LINK_COLLECTION_NODE, but without PVOID UserContext at the end
+} hid_pp_link_collection_node, *phid_pp_link_collection_node;
+
+typedef struct hidp_unknown_token_ {
+	UCHAR Token; /* Specifies the one-byte prefix of a global item. */
+	UCHAR Reserved[3];
+	ULONG BitField; /* Specifies the data part of the global item. */
+} hidp_unknown_token, * phidp_unknown_token;
+
+typedef struct hid_pp_cap_ {
+	USAGE   UsagePage;
+	UCHAR   ReportID;
+	UCHAR   BitPosition;
+	USHORT  ReportSize; // WIN32 term for this is BitSize
+	USHORT  ReportCount;
+	USHORT  BytePosition;
+	USHORT  BitCount;
+	ULONG   BitField;
+	USHORT  NextBytePosition;
+	USHORT  LinkCollection;
+	USAGE   LinkUsagePage;
+	USAGE   LinkUsage;
+
+	// Start of 8 Flags in one byte
+	BOOLEAN IsMultipleItemsForArray:1;
+
+	BOOLEAN IsPadding:1;
+	BOOLEAN IsButtonCap:1;
+	BOOLEAN IsAbsolute:1;
+	BOOLEAN IsRange:1;
+	BOOLEAN IsAlias:1; // IsAlias is set to TRUE in the first n-1 capability structures added to the capability array. IsAlias set to FALSE in the nth capability structure.
+	BOOLEAN IsStringRange:1;
+	BOOLEAN IsDesignatorRange:1;
+	// End of 8 Flags in one byte
+	BOOLEAN Reserved1[3];
+
+	hidp_unknown_token UnknownTokens[4]; // 4 x 8 Byte
+
+	union {
+		struct {
+			USAGE  UsageMin;
+			USAGE  UsageMax;
+			USHORT StringMin;
+			USHORT StringMax;
+			USHORT DesignatorMin;
+			USHORT DesignatorMax;
+			USHORT DataIndexMin;
+			USHORT DataIndexMax;
+		} Range;
+		struct {
+			USAGE  Usage;
+			USAGE  Reserved1;
+			USHORT StringIndex;
+			USHORT Reserved2;
+			USHORT DesignatorIndex;
+			USHORT Reserved3;
+			USHORT DataIndex;
+			USHORT Reserved4;
+		} NotRange;
+	};
+	union {
+		struct {
+			LONG    LogicalMin;
+			LONG    LogicalMax;
+		} Button;
+		struct {
+			BOOLEAN HasNull;
+			UCHAR   Reserved4[3];
+			LONG    LogicalMin;
+			LONG    LogicalMax;
+			LONG    PhysicalMin;
+			LONG    PhysicalMax;
+		} NotButton;
+	};
+	ULONG   Units;
+	ULONG   UnitsExp;
+
+} hid_pp_cap, *phid_pp_cap;
+
+typedef struct hidp_preparsed_data_ {
+	UCHAR MagicKey[8];
+	USAGE Usage;
+	USAGE UsagePage;
+	USHORT Reserved[2];
+
+	// CAPS structure for Input, Output and Feature
+	hid_pp_caps_info caps_info[3];
+
+	USHORT FirstByteOfLinkCollectionArray;
+	USHORT NumberLinkCollectionNodes;
+
+#if defined(__MINGW32__) || defined(__CYGWIN__)
+	// MINGW fails with: Flexible array member in union not supported
+	// Solution: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
+	union {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpedantic"
+		hid_pp_cap caps[0];
+		hid_pp_link_collection_node LinkCollectionArray[0];
+#pragma GCC diagnostic pop
+	};
+#else
+	union {
+		hid_pp_cap caps[];
+		hid_pp_link_collection_node LinkCollectionArray[];
+	};
+#endif
+
+} hidp_preparsed_data;
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/src/hidapi/windows/hidapi_hidpi.h b/src/hidapi/windows/hidapi_hidpi.h
index 343ddeb..75a5812 100644
--- a/src/hidapi/windows/hidapi_hidpi.h
+++ b/src/hidapi/windows/hidapi_hidpi.h
@@ -29,6 +29,13 @@
 /* This part of the header mimics hidpi.h,
     but only what is used by HIDAPI */
 
+typedef enum _HIDP_REPORT_TYPE
+{
+    HidP_Input,
+    HidP_Output,
+    HidP_Feature
+} HIDP_REPORT_TYPE;
+
 typedef struct _HIDP_PREPARSED_DATA * PHIDP_PREPARSED_DATA;
 
 typedef struct _HIDP_CAPS
diff --git a/src/hidapi/windows/hidapi_hidsdi.h b/src/hidapi/windows/hidapi_hidsdi.h
index a820d96..453f899 100644
--- a/src/hidapi/windows/hidapi_hidsdi.h
+++ b/src/hidapi/windows/hidapi_hidsdi.h
@@ -40,6 +40,8 @@
 	USHORT VersionNumber;
 } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
 
+typedef struct _HIDP_PREPARSED_DATA * PHIDP_PREPARSED_DATA;
+
 typedef void (__stdcall *HidD_GetHidGuid_)(LPGUID hid_guid);
 typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);
 typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);
@@ -52,7 +54,6 @@
 typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);
 typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);
 typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
-typedef BOOLEAN (__stdcall *HidD_SetOutputReport_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
 
 #endif
 
diff --git a/src/hidapi/windows/hidapi_winapi.h b/src/hidapi/windows/hidapi_winapi.h
new file mode 100644
index 0000000..43071f5
--- /dev/null
+++ b/src/hidapi/windows/hidapi_winapi.h
@@ -0,0 +1,74 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ libusb/hidapi Team
+
+ Copyright 2022, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+        https://github.com/libusb/hidapi .
+********************************************************/
+
+/** @file
+ * @defgroup API hidapi API
+ *
+ * Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
+ */
+
+#ifndef HIDAPI_WINAPI_H__
+#define HIDAPI_WINAPI_H__
+
+#include <stdint.h>
+
+#include <guiddef.h>
+
+#include "hidapi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+		/** @brief Get the container ID for a HID device.
+
+			Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
+
+			This function returns the `DEVPKEY_Device_ContainerId` property of
+			the given device. This can be used to correlate different
+			interfaces/ports on the same hardware device.
+
+			@ingroup API
+			@param dev A device handle returned from hid_open().
+			@param guid The device's container ID on return.
+
+			@returns
+				This function returns 0 on success and -1 on error.
+		*/
+		int HID_API_EXPORT_CALL hid_winapi_get_container_id(hid_device *dev, GUID *container_id);
+
+		/**
+		 * @brief Reconstructs a HID Report Descriptor from a Win32 HIDP_PREPARSED_DATA structure.
+		 *  This reconstructed report descriptor is logical identical to the real report descriptor,
+		 *  but not byte wise identical.
+		 *
+		 * @param[in]  hidp_preparsed_data Pointer to the HIDP_PREPARSED_DATA to read, i.e.: the value of PHIDP_PREPARSED_DATA,
+		 *   as returned by HidD_GetPreparsedData WinAPI function.
+		 * @param      buf       Pointer to the buffer where the report descriptor should be stored.
+		 * @param[in]  buf_size  Size of the buffer. The recommended size for the buffer is @ref HID_API_MAX_REPORT_DESCRIPTOR_SIZE bytes.
+		 *
+		 * @return Returns size of reconstructed report descriptor if successful, -1 for error.
+		 */
+		int HID_API_EXPORT_CALL hid_winapi_descriptor_reconstruct_pp_data(void *hidp_preparsed_data, unsigned char *buf, size_t buf_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/hidapi/windows/hidtest.vcproj b/src/hidapi/windows/hidtest.vcproj
index cf71195..2918fc4 100644
--- a/src/hidapi/windows/hidtest.vcproj
+++ b/src/hidapi/windows/hidtest.vcproj
@@ -1,196 +1,196 @@
-<?xml version="1.0" encoding="Windows-1252"?>

-<VisualStudioProject

-	ProjectType="Visual C++"

-	Version="9.00"

-	Name="hidtest"

-	ProjectGUID="{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}"

-	RootNamespace="hidtest"

-	TargetFrameworkVersion="196613"

-	>

-	<Platforms>

-		<Platform

-			Name="Win32"

-		/>

-	</Platforms>

-	<ToolFiles>

-	</ToolFiles>

-	<Configurations>

-		<Configuration

-			Name="Debug|Win32"

-			OutputDirectory="$(SolutionDir)$(ConfigurationName)"

-			IntermediateDirectory="$(ConfigurationName)"

-			ConfigurationType="1"

-			CharacterSet="2"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				Optimization="0"

-				AdditionalIncludeDirectories="..\hidapi"

-				MinimalRebuild="true"

-				BasicRuntimeChecks="3"

-				RuntimeLibrary="3"

-				WarningLevel="3"

-				DebugInformationFormat="4"

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="hidapi.lib"

-				AdditionalLibraryDirectories="..\windows\Debug"

-				GenerateDebugInformation="true"

-				SubSystem="1"

-				TargetMachine="1"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCManifestTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCFxCopTool"

-			/>

-			<Tool

-				Name="VCAppVerifierTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-				Description="Copying hidapi.dll to the local direcotry."

-				CommandLine=""

-			/>

-		</Configuration>

-		<Configuration

-			Name="Release|Win32"

-			OutputDirectory="$(SolutionDir)$(ConfigurationName)"

-			IntermediateDirectory="$(ConfigurationName)"

-			ConfigurationType="1"

-			CharacterSet="2"

-			WholeProgramOptimization="1"

-			>

-			<Tool

-				Name="VCPreBuildEventTool"

-			/>

-			<Tool

-				Name="VCCustomBuildTool"

-			/>

-			<Tool

-				Name="VCXMLDataGeneratorTool"

-			/>

-			<Tool

-				Name="VCWebServiceProxyGeneratorTool"

-			/>

-			<Tool

-				Name="VCMIDLTool"

-			/>

-			<Tool

-				Name="VCCLCompilerTool"

-				Optimization="2"

-				EnableIntrinsicFunctions="true"

-				AdditionalIncludeDirectories="..\hidapi"

-				RuntimeLibrary="2"

-				EnableFunctionLevelLinking="true"

-				WarningLevel="3"

-				DebugInformationFormat="3"

-			/>

-			<Tool

-				Name="VCManagedResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCResourceCompilerTool"

-			/>

-			<Tool

-				Name="VCPreLinkEventTool"

-			/>

-			<Tool

-				Name="VCLinkerTool"

-				AdditionalDependencies="hidapi.lib"

-				AdditionalLibraryDirectories="..\windows\Release"

-				GenerateDebugInformation="true"

-				SubSystem="1"

-				OptimizeReferences="2"

-				EnableCOMDATFolding="2"

-				TargetMachine="1"

-			/>

-			<Tool

-				Name="VCALinkTool"

-			/>

-			<Tool

-				Name="VCManifestTool"

-			/>

-			<Tool

-				Name="VCXDCMakeTool"

-			/>

-			<Tool

-				Name="VCBscMakeTool"

-			/>

-			<Tool

-				Name="VCFxCopTool"

-			/>

-			<Tool

-				Name="VCAppVerifierTool"

-			/>

-			<Tool

-				Name="VCPostBuildEventTool"

-				Description="Copying hidapi.dll to the local direcotry."

-				CommandLine=""

-			/>

-		</Configuration>

-	</Configurations>

-	<References>

-	</References>

-	<Files>

-		<Filter

-			Name="Source Files"

-			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

-			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

-			>

-			<File

-				RelativePath="..\hidtest\hidtest.cpp"

-				>

-			</File>

-		</Filter>

-		<Filter

-			Name="Header Files"

-			Filter="h;hpp;hxx;hm;inl;inc;xsd"

-			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

-			>

-		</Filter>

-		<Filter

-			Name="Resource Files"

-			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"

-			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"

-			>

-		</Filter>

-	</Files>

-	<Globals>

-	</Globals>

-</VisualStudioProject>

+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9.00"
+	Name="hidtest"
+	ProjectGUID="{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}"
+	RootNamespace="hidtest"
+	TargetFrameworkVersion="196613"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\hidapi;."
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				WarningLevel="3"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="hidapi.lib"
+				AdditionalLibraryDirectories="..\windows\Debug"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				Description="Copying hidapi.dll to the local directory."
+				CommandLine=""
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="1"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				EnableIntrinsicFunctions="true"
+				AdditionalIncludeDirectories="..\hidapi;."
+				RuntimeLibrary="2"
+				EnableFunctionLevelLinking="true"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="hidapi.lib"
+				AdditionalLibraryDirectories="..\windows\Release"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+				Description="Copying hidapi.dll to the local directory."
+				CommandLine=""
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\hidtest\test.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/hidapi/windows/hidtest.vcxproj b/src/hidapi/windows/hidtest.vcxproj
new file mode 100644
index 0000000..a468d8b
--- /dev/null
+++ b/src/hidapi/windows/hidtest.vcxproj
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}</ProjectGuid>
+    <RootNamespace>hidtest</RootNamespace>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+      <PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
+      <PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
+      <PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
+      <PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
+      <PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
+      <PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
+    <PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
+    <CharacterSet>MultiByte</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <_ProjectFileVersion>14.0.25431.1</_ProjectFileVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>..\hidapi;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <MinimalRebuild>true</MinimalRebuild>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>hidapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>$(SolutionDir)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <AdditionalIncludeDirectories>..\hidapi;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>hidapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <Optimization>MaxSpeed</Optimization>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <AdditionalIncludeDirectories>..\hidapi;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>hidapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>$(SolutionDir)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+      <OptimizeReferences>true</OptimizeReferences>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <Optimization>MaxSpeed</Optimization>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <AdditionalIncludeDirectories>..\hidapi;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>hidapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+      <OptimizeReferences>true</OptimizeReferences>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="..\hidtest\test.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="hidapi.vcxproj">
+      <Project>{a107c21c-418a-4697-bb10-20c3aa60e2e4}</Project>
+      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
diff --git a/src/hidapi/windows/pp_data_dump/CMakeLists.txt b/src/hidapi/windows/pp_data_dump/CMakeLists.txt
new file mode 100644
index 0000000..f017de9
--- /dev/null
+++ b/src/hidapi/windows/pp_data_dump/CMakeLists.txt
@@ -0,0 +1,15 @@
+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}"
+)
diff --git a/src/hidapi/windows/pp_data_dump/README.md b/src/hidapi/windows/pp_data_dump/README.md
new file mode 100644
index 0000000..a0989cd
--- /dev/null
+++ b/src/hidapi/windows/pp_data_dump/README.md
@@ -0,0 +1,122 @@
+## pp_data_dump.exe for Windows
+
+
+pp_data_dump.exe is a small command line tool for Windows, which dumps the content of the [Preparsed Data](https://learn.microsoft.com/en-us/windows-hardware/drivers/hid/preparsed-data) structure, provided by the Windows HID subsystem, into a file.
+
+The generated file is in a text format, which is readable for human, as by the hid_report_reconstructor_test.exe unit test executable of the HIDAPI project. This unit test allows it to test the HIDAPIs report descriptor reconstructor - offline, without the hardware device connected.
+
+pp_data_dump.exe has no arguments, just connect you HID device and execute pp_data_dump.exe. It will generate one file with the name
+```
+<vendor_id>_<product_id>_<usage>_<usage_table>.pp_data
+```
+for each top-level collection, of each connected HID device.
+
+
+## File content
+
+The content of such a .pp_data file looks like the struct, which HIDAPI uses internally to represent the Preparsed Data.
+
+*NOTE:
+Windows parses HID report descriptors into opaque `_HIDP_PREPARSED_DATA` objects.
+The internal structure of `_HIDP_PREPARSED_DATA` is reserved for internal system use.\
+Microsoft doesn't document this structure. [hid_preparsed_data.cc](https://chromium.googlesource.com/chromium/src/+/73fdaaf605bb60caf34d5f30bb84a417688aa528/services/device/hid/hid_preparsed_data.cc) is taken as a reference for its parsing.*
+
+```
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xB010
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "Logitech Bluetooth Wireless Mouse"
+dev->release_number      = 0x0000
+dev->interface_number    = -1
+dev->usage               = 0x0001
+dev->usage_page          = 0x000C
+dev->path                = "\\?\hid#{00001124-0000-1000-8000-00805f9b34fb}_vid&0002046d_pid&b010&col02#8&1cf1c1b9&3&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0001
+pp_data->UsagePage                            = 0x000C
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 1
+pp_data->caps_info[0]->NumberOfCaps       = 1
+pp_data->caps_info[0]->ReportByteLength   = 2
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 1
+pp_data->caps_info[1]->LastCap            = 1
+pp_data->caps_info[1]->NumberOfCaps       = 0
+pp_data->caps_info[1]->ReportByteLength   = 0
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 1
+pp_data->caps_info[2]->LastCap            = 1
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x0068
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x0006
+pp_data->cap[0]->ReportID                     = 0x03
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 8
+pp_data->cap[0]->ReportCount                  = 1
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 8
+pp_data->cap[0]->BitField                     = 0x02
+pp_data->cap[0]->NextBytePosition             = 0x0002
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0x000C
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 0
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x0020
+pp_data->cap[0]->NotRange.Reserved1                    = 0x0020
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->NotButton.HasNull                   = 0
+pp_data->cap[0]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[0]->NotButton.LogicalMin                = 0
+pp_data->cap[0]->NotButton.LogicalMax                = 100
+pp_data->cap[0]->NotButton.PhysicalMin               = 0
+pp_data->cap[0]->NotButton.PhysicalMax               = 0
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x000C
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
+```
\ No newline at end of file
diff --git a/src/hidapi/windows/pp_data_dump/pp_data_dump.c b/src/hidapi/windows/pp_data_dump/pp_data_dump.c
new file mode 100644
index 0000000..561dc96
--- /dev/null
+++ b/src/hidapi/windows/pp_data_dump/pp_data_dump.c
@@ -0,0 +1,238 @@
+
+
+#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;
+}
diff --git a/src/hidapi/windows/test/CMakeLists.txt b/src/hidapi/windows/test/CMakeLists.txt
new file mode 100644
index 0000000..eae3217
--- /dev/null
+++ b/src/hidapi/windows/test/CMakeLists.txt
@@ -0,0 +1,76 @@
+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()
diff --git a/src/hidapi/windows/test/data/045E_02FF_0005_0001.pp_data b/src/hidapi/windows/test/data/045E_02FF_0005_0001.pp_data
new file mode 100644
index 0000000..6226996
--- /dev/null
+++ b/src/hidapi/windows/test/data/045E_02FF_0005_0001.pp_data
@@ -0,0 +1,420 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x045E
+dev->product_id          = 0x02FF
+dev->manufacturer_string = ""
+dev->product_string      = "Controller (Xbox One For Windows)"
+dev->release_number      = 0x0000
+dev->interface_number    = -1
+dev->usage               = 0x0005
+dev->usage_page          = 0x0001
+dev->path                = "\\?\HID#VID_045E&PID_02FF&IG_00#7&5ea4a81&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0005
+pp_data->UsagePage                            = 0x0001
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 7
+pp_data->caps_info[0]->NumberOfCaps       = 7
+pp_data->caps_info[0]->ReportByteLength   = 16
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 7
+pp_data->caps_info[1]->LastCap            = 7
+pp_data->caps_info[1]->NumberOfCaps       = 0
+pp_data->caps_info[1]->ReportByteLength   = 0
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 7
+pp_data->caps_info[2]->LastCap            = 7
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x02D8
+pp_data->NumberLinkCollectionNodes            = 4
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x0001
+pp_data->cap[0]->ReportID                     = 0x00
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 16
+pp_data->cap[0]->ReportCount                  = 1
+pp_data->cap[0]->BytePosition                 = 0x0003
+pp_data->cap[0]->BitCount                     = 16
+pp_data->cap[0]->BitField                     = 0x02
+pp_data->cap[0]->NextBytePosition             = 0x0005
+pp_data->cap[0]->LinkCollection               = 0x0001
+pp_data->cap[0]->LinkUsagePage                = 0x0001
+pp_data->cap[0]->LinkUsage                    = 0x0000
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 0
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x0031
+pp_data->cap[0]->NotRange.Reserved1                    = 0x0031
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->NotButton.HasNull                   = 0
+pp_data->cap[0]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[0]->NotButton.LogicalMin                = 0
+pp_data->cap[0]->NotButton.LogicalMax                = -1
+pp_data->cap[0]->NotButton.PhysicalMin               = 0
+pp_data->cap[0]->NotButton.PhysicalMax               = -1
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0x0001
+pp_data->cap[1]->ReportID                     = 0x00
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 16
+pp_data->cap[1]->ReportCount                  = 1
+pp_data->cap[1]->BytePosition                 = 0x0001
+pp_data->cap[1]->BitCount                     = 16
+pp_data->cap[1]->BitField                     = 0x02
+pp_data->cap[1]->NextBytePosition             = 0x0003
+pp_data->cap[1]->LinkCollection               = 0x0001
+pp_data->cap[1]->LinkUsagePage                = 0x0001
+pp_data->cap[1]->LinkUsage                    = 0x0000
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 0
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0030
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0030
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 1
+pp_data->cap[1]->NotRange.Reserved4                    = 1
+pp_data->cap[1]->NotButton.HasNull                   = 0
+pp_data->cap[1]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[1]->NotButton.LogicalMin                = 0
+pp_data->cap[1]->NotButton.LogicalMax                = -1
+pp_data->cap[1]->NotButton.PhysicalMin               = 0
+pp_data->cap[1]->NotButton.PhysicalMax               = -1
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+pp_data->cap[2]->UsagePage                    = 0x0001
+pp_data->cap[2]->ReportID                     = 0x00
+pp_data->cap[2]->BitPosition                  = 0
+pp_data->cap[2]->BitSize                      = 16
+pp_data->cap[2]->ReportCount                  = 1
+pp_data->cap[2]->BytePosition                 = 0x0007
+pp_data->cap[2]->BitCount                     = 16
+pp_data->cap[2]->BitField                     = 0x02
+pp_data->cap[2]->NextBytePosition             = 0x0009
+pp_data->cap[2]->LinkCollection               = 0x0002
+pp_data->cap[2]->LinkUsagePage                = 0x0001
+pp_data->cap[2]->LinkUsage                    = 0x0000
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 0
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 1
+pp_data->cap[2]->IsRange                      = 0
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->NotRange.Usage                        = 0x0034
+pp_data->cap[2]->NotRange.Reserved1                    = 0x0034
+pp_data->cap[2]->NotRange.StringIndex                  = 0
+pp_data->cap[2]->NotRange.Reserved2                    = 0
+pp_data->cap[2]->NotRange.DesignatorIndex              = 0
+pp_data->cap[2]->NotRange.Reserved3                    = 0
+pp_data->cap[2]->NotRange.DataIndex                    = 2
+pp_data->cap[2]->NotRange.Reserved4                    = 2
+pp_data->cap[2]->NotButton.HasNull                   = 0
+pp_data->cap[2]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[2]->NotButton.LogicalMin                = 0
+pp_data->cap[2]->NotButton.LogicalMax                = -1
+pp_data->cap[2]->NotButton.PhysicalMin               = 0
+pp_data->cap[2]->NotButton.PhysicalMax               = -1
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+pp_data->cap[3]->UsagePage                    = 0x0001
+pp_data->cap[3]->ReportID                     = 0x00
+pp_data->cap[3]->BitPosition                  = 0
+pp_data->cap[3]->BitSize                      = 16
+pp_data->cap[3]->ReportCount                  = 1
+pp_data->cap[3]->BytePosition                 = 0x0005
+pp_data->cap[3]->BitCount                     = 16
+pp_data->cap[3]->BitField                     = 0x02
+pp_data->cap[3]->NextBytePosition             = 0x0007
+pp_data->cap[3]->LinkCollection               = 0x0002
+pp_data->cap[3]->LinkUsagePage                = 0x0001
+pp_data->cap[3]->LinkUsage                    = 0x0000
+pp_data->cap[3]->IsMultipleItemsForArray      = 0
+pp_data->cap[3]->IsButtonCap                  = 0
+pp_data->cap[3]->IsPadding                    = 0
+pp_data->cap[3]->IsAbsolute                   = 1
+pp_data->cap[3]->IsRange                      = 0
+pp_data->cap[3]->IsAlias                      = 0
+pp_data->cap[3]->IsStringRange                = 0
+pp_data->cap[3]->IsDesignatorRange            = 0
+pp_data->cap[3]->Reserved1                    = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[3]->NotRange.Usage                        = 0x0033
+pp_data->cap[3]->NotRange.Reserved1                    = 0x0033
+pp_data->cap[3]->NotRange.StringIndex                  = 0
+pp_data->cap[3]->NotRange.Reserved2                    = 0
+pp_data->cap[3]->NotRange.DesignatorIndex              = 0
+pp_data->cap[3]->NotRange.Reserved3                    = 0
+pp_data->cap[3]->NotRange.DataIndex                    = 3
+pp_data->cap[3]->NotRange.Reserved4                    = 3
+pp_data->cap[3]->NotButton.HasNull                   = 0
+pp_data->cap[3]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[3]->NotButton.LogicalMin                = 0
+pp_data->cap[3]->NotButton.LogicalMax                = -1
+pp_data->cap[3]->NotButton.PhysicalMin               = 0
+pp_data->cap[3]->NotButton.PhysicalMax               = -1
+pp_data->cap[3]->Units                    = 0
+pp_data->cap[3]->UnitsExp                 = 0
+
+pp_data->cap[4]->UsagePage                    = 0x0001
+pp_data->cap[4]->ReportID                     = 0x00
+pp_data->cap[4]->BitPosition                  = 0
+pp_data->cap[4]->BitSize                      = 16
+pp_data->cap[4]->ReportCount                  = 1
+pp_data->cap[4]->BytePosition                 = 0x0009
+pp_data->cap[4]->BitCount                     = 16
+pp_data->cap[4]->BitField                     = 0x02
+pp_data->cap[4]->NextBytePosition             = 0x000B
+pp_data->cap[4]->LinkCollection               = 0x0003
+pp_data->cap[4]->LinkUsagePage                = 0x0001
+pp_data->cap[4]->LinkUsage                    = 0x0000
+pp_data->cap[4]->IsMultipleItemsForArray      = 0
+pp_data->cap[4]->IsButtonCap                  = 0
+pp_data->cap[4]->IsPadding                    = 0
+pp_data->cap[4]->IsAbsolute                   = 1
+pp_data->cap[4]->IsRange                      = 0
+pp_data->cap[4]->IsAlias                      = 0
+pp_data->cap[4]->IsStringRange                = 0
+pp_data->cap[4]->IsDesignatorRange            = 0
+pp_data->cap[4]->Reserved1                    = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[4]->NotRange.Usage                        = 0x0032
+pp_data->cap[4]->NotRange.Reserved1                    = 0x0032
+pp_data->cap[4]->NotRange.StringIndex                  = 0
+pp_data->cap[4]->NotRange.Reserved2                    = 0
+pp_data->cap[4]->NotRange.DesignatorIndex              = 0
+pp_data->cap[4]->NotRange.Reserved3                    = 0
+pp_data->cap[4]->NotRange.DataIndex                    = 4
+pp_data->cap[4]->NotRange.Reserved4                    = 4
+pp_data->cap[4]->NotButton.HasNull                   = 0
+pp_data->cap[4]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[4]->NotButton.LogicalMin                = 0
+pp_data->cap[4]->NotButton.LogicalMax                = -1
+pp_data->cap[4]->NotButton.PhysicalMin               = 0
+pp_data->cap[4]->NotButton.PhysicalMax               = -1
+pp_data->cap[4]->Units                    = 0
+pp_data->cap[4]->UnitsExp                 = 0
+
+pp_data->cap[5]->UsagePage                    = 0x0009
+pp_data->cap[5]->ReportID                     = 0x00
+pp_data->cap[5]->BitPosition                  = 0
+pp_data->cap[5]->BitSize                      = 1
+pp_data->cap[5]->ReportCount                  = 16
+pp_data->cap[5]->BytePosition                 = 0x000B
+pp_data->cap[5]->BitCount                     = 16
+pp_data->cap[5]->BitField                     = 0x02
+pp_data->cap[5]->NextBytePosition             = 0x000D
+pp_data->cap[5]->LinkCollection               = 0x0000
+pp_data->cap[5]->LinkUsagePage                = 0x0001
+pp_data->cap[5]->LinkUsage                    = 0x0005
+pp_data->cap[5]->IsMultipleItemsForArray      = 0
+pp_data->cap[5]->IsButtonCap                  = 1
+pp_data->cap[5]->IsPadding                    = 0
+pp_data->cap[5]->IsAbsolute                   = 1
+pp_data->cap[5]->IsRange                      = 1
+pp_data->cap[5]->IsAlias                      = 0
+pp_data->cap[5]->IsStringRange                = 0
+pp_data->cap[5]->IsDesignatorRange            = 0
+pp_data->cap[5]->Reserved1                    = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[5]->Range.UsageMin                     = 0x0001
+pp_data->cap[5]->Range.UsageMax                     = 0x0010
+pp_data->cap[5]->Range.StringMin                    = 0
+pp_data->cap[5]->Range.StringMax                    = 0
+pp_data->cap[5]->Range.DesignatorMin                = 0
+pp_data->cap[5]->Range.DesignatorMax                = 0
+pp_data->cap[5]->Range.DataIndexMin                 = 5
+pp_data->cap[5]->Range.DataIndexMax                 = 20
+pp_data->cap[5]->Button.LogicalMin                   = 0
+pp_data->cap[5]->Button.LogicalMax                   = 0
+pp_data->cap[5]->Units                    = 0
+pp_data->cap[5]->UnitsExp                 = 0
+
+pp_data->cap[6]->UsagePage                    = 0x0001
+pp_data->cap[6]->ReportID                     = 0x00
+pp_data->cap[6]->BitPosition                  = 0
+pp_data->cap[6]->BitSize                      = 4
+pp_data->cap[6]->ReportCount                  = 1
+pp_data->cap[6]->BytePosition                 = 0x000D
+pp_data->cap[6]->BitCount                     = 4
+pp_data->cap[6]->BitField                     = 0x42
+pp_data->cap[6]->NextBytePosition             = 0x000E
+pp_data->cap[6]->LinkCollection               = 0x0000
+pp_data->cap[6]->LinkUsagePage                = 0x0001
+pp_data->cap[6]->LinkUsage                    = 0x0005
+pp_data->cap[6]->IsMultipleItemsForArray      = 0
+pp_data->cap[6]->IsButtonCap                  = 0
+pp_data->cap[6]->IsPadding                    = 0
+pp_data->cap[6]->IsAbsolute                   = 1
+pp_data->cap[6]->IsRange                      = 0
+pp_data->cap[6]->IsAlias                      = 0
+pp_data->cap[6]->IsStringRange                = 0
+pp_data->cap[6]->IsDesignatorRange            = 0
+pp_data->cap[6]->Reserved1                    = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[6]->NotRange.Usage                        = 0x0039
+pp_data->cap[6]->NotRange.Reserved1                    = 0x0039
+pp_data->cap[6]->NotRange.StringIndex                  = 0
+pp_data->cap[6]->NotRange.Reserved2                    = 0
+pp_data->cap[6]->NotRange.DesignatorIndex              = 0
+pp_data->cap[6]->NotRange.Reserved3                    = 0
+pp_data->cap[6]->NotRange.DataIndex                    = 21
+pp_data->cap[6]->NotRange.Reserved4                    = 21
+pp_data->cap[6]->NotButton.HasNull                   = 1
+pp_data->cap[6]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[6]->NotButton.LogicalMin                = 1
+pp_data->cap[6]->NotButton.LogicalMax                = 8
+pp_data->cap[6]->NotButton.PhysicalMin               = 0
+pp_data->cap[6]->NotButton.PhysicalMax               = 4155
+pp_data->cap[6]->Units                    = 14
+pp_data->cap[6]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0005
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 3
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 3
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[1]->LinkUsage          = 0x0000
+pp_data->LinkCollectionArray[1]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[1]->Parent             = 0
+pp_data->LinkCollectionArray[1]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[1]->NextSibling        = 0
+pp_data->LinkCollectionArray[1]->FirstChild         = 0
+pp_data->LinkCollectionArray[1]->CollectionType     = 0
+pp_data->LinkCollectionArray[1]->IsAlias            = 0
+pp_data->LinkCollectionArray[1]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[2]->LinkUsage          = 0x0000
+pp_data->LinkCollectionArray[2]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[2]->Parent             = 0
+pp_data->LinkCollectionArray[2]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[2]->NextSibling        = 1
+pp_data->LinkCollectionArray[2]->FirstChild         = 0
+pp_data->LinkCollectionArray[2]->CollectionType     = 0
+pp_data->LinkCollectionArray[2]->IsAlias            = 0
+pp_data->LinkCollectionArray[2]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[3]->LinkUsage          = 0x0000
+pp_data->LinkCollectionArray[3]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[3]->Parent             = 0
+pp_data->LinkCollectionArray[3]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[3]->NextSibling        = 2
+pp_data->LinkCollectionArray[3]->FirstChild         = 0
+pp_data->LinkCollectionArray[3]->CollectionType     = 0
+pp_data->LinkCollectionArray[3]->IsAlias            = 0
+pp_data->LinkCollectionArray[3]->Reserved           = 0x00000000
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/045E_02FF_0005_0001_expected.rpt_desc b/src/hidapi/windows/test/data/045E_02FF_0005_0001_expected.rpt_desc
new file mode 100644
index 0000000..58f80e4
--- /dev/null
+++ b/src/hidapi/windows/test/data/045E_02FF_0005_0001_expected.rpt_desc
@@ -0,0 +1,12 @@
+0x05, 0x01, 0x09, 0x05, 0xA1, 0x01, 0x09, 0x00, 0xA1, 0x00, 
+0x09, 0x30, 0x09, 0x31, 0x15, 0x00, 0x25, 0xFF, 0x35, 0x00, 
+0x45, 0xFF, 0x75, 0x10, 0x95, 0x02, 0x81, 0x02, 0xC0, 0x09, 
+0x00, 0xA1, 0x00, 0x09, 0x33, 0x09, 0x34, 0x15, 0x00, 0x25, 
+0xFF, 0x75, 0x10, 0x95, 0x02, 0x81, 0x02, 0xC0, 0x09, 0x00, 
+0xA1, 0x00, 0x09, 0x32, 0x15, 0x00, 0x25, 0xFF, 0x75, 0x10, 
+0x95, 0x01, 0x81, 0x02, 0xC0, 0x05, 0x09, 0x19, 0x01, 0x29, 
+0x10, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x10, 0x45, 
+0x00, 0x81, 0x02, 0x05, 0x01, 0x09, 0x39, 0x15, 0x01, 0x25, 
+0x08, 0x35, 0x00, 0x46, 0x3B, 0x10, 0x65, 0x0E, 0x75, 0x04, 
+0x95, 0x01, 0x81, 0x42, 0x75, 0x04, 0x95, 0x01, 0x81, 0x03, 
+0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/045E_02FF_0005_0001_real.rpt_desc b/src/hidapi/windows/test/data/045E_02FF_0005_0001_real.rpt_desc
new file mode 100644
index 0000000..11cc78b
--- /dev/null
+++ b/src/hidapi/windows/test/data/045E_02FF_0005_0001_real.rpt_desc
@@ -0,0 +1,64 @@
+// Special cases of this device:
+//   2 full padding bytes at the end
+//   Multiple child collections inside of the same report (byte position of Input items defines collection order)
+
+0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
+0x09, 0x05,        // Usage (Game Pad)
+0xA1, 0x01,        // Collection (Application)
+0xA1, 0x00,        //   Collection (Physical)
+0x09, 0x30,        //     Usage (X)
+0x09, 0x31,        //     Usage (Y)
+0x15, 0x00,        //     Logical Minimum (0)
+0x26, 0xFF, 0xFF,  //     Logical Maximum (-1)
+0x35, 0x00,        //     Physical Minimum (0)
+0x46, 0xFF, 0xFF,  //     Physical Maximum (-1)
+0x95, 0x02,        //     Report Count (2)
+0x75, 0x10,        //     Report Size (16)
+0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0xC0,              //   End Collection
+0xA1, 0x00,        //   Collection (Physical)
+0x09, 0x33,        //     Usage (Rx)
+0x09, 0x34,        //     Usage (Ry)
+0x15, 0x00,        //     Logical Minimum (0)
+0x26, 0xFF, 0xFF,  //     Logical Maximum (-1)
+0x35, 0x00,        //     Physical Minimum (0)
+0x46, 0xFF, 0xFF,  //     Physical Maximum (-1)
+0x95, 0x02,        //     Report Count (2)
+0x75, 0x10,        //     Report Size (16)
+0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0xC0,              //   End Collection
+0xA1, 0x00,        //   Collection (Physical)
+0x09, 0x32,        //     Usage (Z)
+0x15, 0x00,        //     Logical Minimum (0)
+0x26, 0xFF, 0xFF,  //     Logical Maximum (-1)
+0x35, 0x00,        //     Physical Minimum (0)
+0x46, 0xFF, 0xFF,  //     Physical Maximum (-1)
+0x95, 0x01,        //     Report Count (1)
+0x75, 0x10,        //     Report Size (16)
+0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0xC0,              //   End Collection
+0x05, 0x09,        //   Usage Page (Button)
+0x19, 0x01,        //   Usage Minimum (0x01)
+0x29, 0x10,        //   Usage Maximum (0x10)
+0x95, 0x10,        //   Report Count (16)
+0x75, 0x01,        //   Report Size (1)
+0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x05, 0x01,        //   Usage Page (Generic Desktop Ctrls)
+0x09, 0x39,        //   Usage (Hat switch)
+0x15, 0x01,        //   Logical Minimum (1)
+0x25, 0x08,        //   Logical Maximum (8)
+0x35, 0x00,        //   Physical Minimum (0)
+0x46, 0x3B, 0x10,  //   Physical Maximum (4155)
+0x66, 0x0E, 0x00,  //   Unit (None)
+0x75, 0x04,        //   Report Size (4)
+0x95, 0x01,        //   Report Count (1)
+0x81, 0x42,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
+0x75, 0x04,        //   Report Size (4)
+0x95, 0x01,        //   Report Count (1)
+0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x75, 0x08,        //   Report Size (8)
+0x95, 0x02,        //   Report Count (2)
+0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0xC0,              // End Collection
+
+// 120 bytes
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046A_0011_0006_0001.pp_data b/src/hidapi/windows/test/data/046A_0011_0006_0001.pp_data
new file mode 100644
index 0000000..59eb600
--- /dev/null
+++ b/src/hidapi/windows/test/data/046A_0011_0006_0001.pp_data
@@ -0,0 +1,183 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046A
+dev->product_id          = 0x0011
+dev->manufacturer_string = "dev->product_string      = "dev->release_number      = 0x0100
+dev->interface_number    = -1
+dev->usage               = 0x0006
+dev->usage_page          = 0x0001
+dev->path                = "\\?\hid#vid_046a&pid_0011#7&2c7fd0a5&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0006
+pp_data->UsagePage                            = 0x0001
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 2
+pp_data->caps_info[0]->NumberOfCaps       = 2
+pp_data->caps_info[0]->ReportByteLength   = 9
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 2
+pp_data->caps_info[1]->LastCap            = 3
+pp_data->caps_info[1]->NumberOfCaps       = 1
+pp_data->caps_info[1]->ReportByteLength   = 2
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 3
+pp_data->caps_info[2]->LastCap            = 3
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x0138
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x0007
+pp_data->cap[0]->ReportID                     = 0x00
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 1
+pp_data->cap[0]->ReportCount                  = 8
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 8
+pp_data->cap[0]->BitField                     = 0x02
+pp_data->cap[0]->NextBytePosition             = 0x0002
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0x0001
+pp_data->cap[0]->LinkUsage                    = 0x0006
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 1
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->Range.UsageMin                     = 0x00E0
+pp_data->cap[0]->Range.UsageMax                     = 0x00E7
+pp_data->cap[0]->Range.StringMin                    = 0
+pp_data->cap[0]->Range.StringMax                    = 0
+pp_data->cap[0]->Range.DesignatorMin                = 0
+pp_data->cap[0]->Range.DesignatorMax                = 0
+pp_data->cap[0]->Range.DataIndexMin                 = 0
+pp_data->cap[0]->Range.DataIndexMax                 = 7
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 0
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0x0007
+pp_data->cap[1]->ReportID                     = 0x00
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 8
+pp_data->cap[1]->ReportCount                  = 6
+pp_data->cap[1]->BytePosition                 = 0x0003
+pp_data->cap[1]->BitCount                     = 48
+pp_data->cap[1]->BitField                     = 0x00
+pp_data->cap[1]->NextBytePosition             = 0x0009
+pp_data->cap[1]->LinkCollection               = 0x0000
+pp_data->cap[1]->LinkUsagePage                = 0x0001
+pp_data->cap[1]->LinkUsage                    = 0x0006
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 1
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 1
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->Range.UsageMin                     = 0x0000
+pp_data->cap[1]->Range.UsageMax                     = 0x00DD
+pp_data->cap[1]->Range.StringMin                    = 0
+pp_data->cap[1]->Range.StringMax                    = 0
+pp_data->cap[1]->Range.DesignatorMin                = 0
+pp_data->cap[1]->Range.DesignatorMax                = 0
+pp_data->cap[1]->Range.DataIndexMin                 = 8
+pp_data->cap[1]->Range.DataIndexMax                 = 229
+pp_data->cap[1]->Button.LogicalMin                   = 0
+pp_data->cap[1]->Button.LogicalMax                   = 221
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[2]->UsagePage                    = 0x0008
+pp_data->cap[2]->ReportID                     = 0x00
+pp_data->cap[2]->BitPosition                  = 0
+pp_data->cap[2]->BitSize                      = 1
+pp_data->cap[2]->ReportCount                  = 3
+pp_data->cap[2]->BytePosition                 = 0x0001
+pp_data->cap[2]->BitCount                     = 3
+pp_data->cap[2]->BitField                     = 0x02
+pp_data->cap[2]->NextBytePosition             = 0x0002
+pp_data->cap[2]->LinkCollection               = 0x0000
+pp_data->cap[2]->LinkUsagePage                = 0x0001
+pp_data->cap[2]->LinkUsage                    = 0x0006
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 1
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 1
+pp_data->cap[2]->IsRange                      = 1
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->Range.UsageMin                     = 0x0001
+pp_data->cap[2]->Range.UsageMax                     = 0x0003
+pp_data->cap[2]->Range.StringMin                    = 0
+pp_data->cap[2]->Range.StringMax                    = 0
+pp_data->cap[2]->Range.DesignatorMin                = 0
+pp_data->cap[2]->Range.DesignatorMax                = 0
+pp_data->cap[2]->Range.DataIndexMin                 = 0
+pp_data->cap[2]->Range.DataIndexMax                 = 2
+pp_data->cap[2]->Button.LogicalMin                   = 0
+pp_data->cap[2]->Button.LogicalMax                   = 0
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0006
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046A_0011_0006_0001_expected.rpt_desc b/src/hidapi/windows/test/data/046A_0011_0006_0001_expected.rpt_desc
new file mode 100644
index 0000000..e9bc501
--- /dev/null
+++ b/src/hidapi/windows/test/data/046A_0011_0006_0001_expected.rpt_desc
@@ -0,0 +1,7 @@
+0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xE0, 
+0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 
+0x81, 0x02, 0x75, 0x08, 0x95, 0x01, 0x81, 0x03, 0x19, 0x00, 
+0x29, 0xDD, 0x15, 0x00, 0x26, 0xDD, 0x00, 0x75, 0x08, 0x95, 
+0x06, 0x81, 0x00, 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x15, 
+0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x03, 0x91, 0x02, 0x75, 
+0x05, 0x95, 0x01, 0x91, 0x03, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046A_0011_0006_0001_real.rpt_desc b/src/hidapi/windows/test/data/046A_0011_0006_0001_real.rpt_desc
new file mode 100644
index 0000000..e9bc501
--- /dev/null
+++ b/src/hidapi/windows/test/data/046A_0011_0006_0001_real.rpt_desc
@@ -0,0 +1,7 @@
+0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xE0, 
+0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 
+0x81, 0x02, 0x75, 0x08, 0x95, 0x01, 0x81, 0x03, 0x19, 0x00, 
+0x29, 0xDD, 0x15, 0x00, 0x26, 0xDD, 0x00, 0x75, 0x08, 0x95, 
+0x06, 0x81, 0x00, 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x15, 
+0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x03, 0x91, 0x02, 0x75, 
+0x05, 0x95, 0x01, 0x91, 0x03, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_0A37_0001_000C.pp_data b/src/hidapi/windows/test/data/046D_0A37_0001_000C.pp_data
new file mode 100644
index 0000000..3bc7aad
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_0A37_0001_000C.pp_data
@@ -0,0 +1,532 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0x0A37
+dev->manufacturer_string = "Logitech Inc "
+dev->product_string      = "Logitech USB Headset H540"
+dev->release_number      = 0x0122
+dev->interface_number    = 3
+dev->usage               = 0x0001
+dev->usage_page          = 0x000C
+dev->path                = "\\?\hid#vid_046d&pid_0a37&mi_03#8&1717f300&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0001
+pp_data->UsagePage                            = 0x000C
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 7
+pp_data->caps_info[0]->NumberOfCaps       = 9
+pp_data->caps_info[0]->ReportByteLength   = 33
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 9
+pp_data->caps_info[1]->LastCap            = 12
+pp_data->caps_info[1]->NumberOfCaps       = 3
+pp_data->caps_info[1]->ReportByteLength   = 37
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 12
+pp_data->caps_info[2]->LastCap            = 12
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x04E0
+pp_data->NumberLinkCollectionNodes            = 2
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x000C
+pp_data->cap[0]->ReportID                     = 0x01
+pp_data->cap[0]->BitPosition                  = 1
+pp_data->cap[0]->BitSize                      = 1
+pp_data->cap[0]->ReportCount                  = 1
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 1
+pp_data->cap[0]->BitField                     = 0x02
+pp_data->cap[0]->NextBytePosition             = 0x0002
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0x000C
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x00EA
+pp_data->cap[0]->NotRange.Reserved1                    = 0x00EA
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 0
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0x000C
+pp_data->cap[1]->ReportID                     = 0x01
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 1
+pp_data->cap[1]->ReportCount                  = 1
+pp_data->cap[1]->BytePosition                 = 0x0001
+pp_data->cap[1]->BitCount                     = 1
+pp_data->cap[1]->BitField                     = 0x02
+pp_data->cap[1]->NextBytePosition             = 0x0002
+pp_data->cap[1]->LinkCollection               = 0x0000
+pp_data->cap[1]->LinkUsagePage                = 0x000C
+pp_data->cap[1]->LinkUsage                    = 0x0001
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 1
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x00E9
+pp_data->cap[1]->NotRange.Reserved1                    = 0x00E9
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 1
+pp_data->cap[1]->NotRange.Reserved4                    = 1
+pp_data->cap[1]->Button.LogicalMin                   = 0
+pp_data->cap[1]->Button.LogicalMax                   = 0
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+pp_data->cap[2]->UsagePage                    = 0x000C
+pp_data->cap[2]->ReportID                     = 0x01
+pp_data->cap[2]->BitPosition                  = 2
+pp_data->cap[2]->BitSize                      = 1
+pp_data->cap[2]->ReportCount                  = 1
+pp_data->cap[2]->BytePosition                 = 0x0001
+pp_data->cap[2]->BitCount                     = 1
+pp_data->cap[2]->BitField                     = 0x06
+pp_data->cap[2]->NextBytePosition             = 0x0002
+pp_data->cap[2]->LinkCollection               = 0x0000
+pp_data->cap[2]->LinkUsagePage                = 0x000C
+pp_data->cap[2]->LinkUsage                    = 0x0001
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 1
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 0
+pp_data->cap[2]->IsRange                      = 0
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->NotRange.Usage                        = 0x00E2
+pp_data->cap[2]->NotRange.Reserved1                    = 0x00E2
+pp_data->cap[2]->NotRange.StringIndex                  = 0
+pp_data->cap[2]->NotRange.Reserved2                    = 0
+pp_data->cap[2]->NotRange.DesignatorIndex              = 0
+pp_data->cap[2]->NotRange.Reserved3                    = 0
+pp_data->cap[2]->NotRange.DataIndex                    = 2
+pp_data->cap[2]->NotRange.Reserved4                    = 2
+pp_data->cap[2]->Button.LogicalMin                   = 0
+pp_data->cap[2]->Button.LogicalMax                   = 0
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+pp_data->cap[3]->UsagePage                    = 0x0009
+pp_data->cap[3]->ReportID                     = 0x01
+pp_data->cap[3]->BitPosition                  = 5
+pp_data->cap[3]->BitSize                      = 2
+pp_data->cap[3]->ReportCount                  = 1
+pp_data->cap[3]->BytePosition                 = 0x0001
+pp_data->cap[3]->BitCount                     = 2
+pp_data->cap[3]->BitField                     = 0x40
+pp_data->cap[3]->NextBytePosition             = 0x0002
+pp_data->cap[3]->LinkCollection               = 0x0001
+pp_data->cap[3]->LinkUsagePage                = 0x000C
+pp_data->cap[3]->LinkUsage                    = 0x0036
+pp_data->cap[3]->IsMultipleItemsForArray      = 0
+pp_data->cap[3]->IsButtonCap                  = 1
+pp_data->cap[3]->IsPadding                    = 0
+pp_data->cap[3]->IsAbsolute                   = 1
+pp_data->cap[3]->IsRange                      = 1
+pp_data->cap[3]->IsAlias                      = 0
+pp_data->cap[3]->IsStringRange                = 0
+pp_data->cap[3]->IsDesignatorRange            = 0
+pp_data->cap[3]->Reserved1                    = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[3]->Range.UsageMin                     = 0x0001
+pp_data->cap[3]->Range.UsageMax                     = 0x0002
+pp_data->cap[3]->Range.StringMin                    = 0
+pp_data->cap[3]->Range.StringMax                    = 0
+pp_data->cap[3]->Range.DesignatorMin                = 0
+pp_data->cap[3]->Range.DesignatorMax                = 0
+pp_data->cap[3]->Range.DataIndexMin                 = 3
+pp_data->cap[3]->Range.DataIndexMax                 = 4
+pp_data->cap[3]->Button.LogicalMin                   = 1
+pp_data->cap[3]->Button.LogicalMax                   = 2
+pp_data->cap[3]->Units                    = 0
+pp_data->cap[3]->UnitsExp                 = 0
+
+pp_data->cap[4]->UsagePage                    = 0x000C
+pp_data->cap[4]->ReportID                     = 0x02
+pp_data->cap[4]->BitPosition                  = 0
+pp_data->cap[4]->BitSize                      = 1
+pp_data->cap[4]->ReportCount                  = 16
+pp_data->cap[4]->BytePosition                 = 0x0001
+pp_data->cap[4]->BitCount                     = 16
+pp_data->cap[4]->BitField                     = 0x02
+pp_data->cap[4]->NextBytePosition             = 0x0003
+pp_data->cap[4]->LinkCollection               = 0x0000
+pp_data->cap[4]->LinkUsagePage                = 0x000C
+pp_data->cap[4]->LinkUsage                    = 0x0001
+pp_data->cap[4]->IsMultipleItemsForArray      = 0
+pp_data->cap[4]->IsButtonCap                  = 1
+pp_data->cap[4]->IsPadding                    = 0
+pp_data->cap[4]->IsAbsolute                   = 1
+pp_data->cap[4]->IsRange                      = 0
+pp_data->cap[4]->IsAlias                      = 0
+pp_data->cap[4]->IsStringRange                = 0
+pp_data->cap[4]->IsDesignatorRange            = 0
+pp_data->cap[4]->Reserved1                    = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[4]->NotRange.Usage                        = 0x0000
+pp_data->cap[4]->NotRange.Reserved1                    = 0x0000
+pp_data->cap[4]->NotRange.StringIndex                  = 0
+pp_data->cap[4]->NotRange.Reserved2                    = 0
+pp_data->cap[4]->NotRange.DesignatorIndex              = 0
+pp_data->cap[4]->NotRange.Reserved3                    = 0
+pp_data->cap[4]->NotRange.DataIndex                    = 5
+pp_data->cap[4]->NotRange.Reserved4                    = 5
+pp_data->cap[4]->Button.LogicalMin                   = 0
+pp_data->cap[4]->Button.LogicalMax                   = 0
+pp_data->cap[4]->Units                    = 0
+pp_data->cap[4]->UnitsExp                 = 0
+
+pp_data->cap[5]->UsagePage                    = 0x000C
+pp_data->cap[5]->ReportID                     = 0x05
+pp_data->cap[5]->BitPosition                  = 0
+pp_data->cap[5]->BitSize                      = 8
+pp_data->cap[5]->ReportCount                  = 32
+pp_data->cap[5]->BytePosition                 = 0x0001
+pp_data->cap[5]->BitCount                     = 256
+pp_data->cap[5]->BitField                     = 0x02
+pp_data->cap[5]->NextBytePosition             = 0x0021
+pp_data->cap[5]->LinkCollection               = 0x0000
+pp_data->cap[5]->LinkUsagePage                = 0x000C
+pp_data->cap[5]->LinkUsage                    = 0x0001
+pp_data->cap[5]->IsMultipleItemsForArray      = 0
+pp_data->cap[5]->IsButtonCap                  = 0
+pp_data->cap[5]->IsPadding                    = 0
+pp_data->cap[5]->IsAbsolute                   = 1
+pp_data->cap[5]->IsRange                      = 0
+pp_data->cap[5]->IsAlias                      = 0
+pp_data->cap[5]->IsStringRange                = 0
+pp_data->cap[5]->IsDesignatorRange            = 0
+pp_data->cap[5]->Reserved1                    = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[5]->NotRange.Usage                        = 0x0000
+pp_data->cap[5]->NotRange.Reserved1                    = 0x0000
+pp_data->cap[5]->NotRange.StringIndex                  = 0
+pp_data->cap[5]->NotRange.Reserved2                    = 0
+pp_data->cap[5]->NotRange.DesignatorIndex              = 0
+pp_data->cap[5]->NotRange.Reserved3                    = 0
+pp_data->cap[5]->NotRange.DataIndex                    = 6
+pp_data->cap[5]->NotRange.Reserved4                    = 6
+pp_data->cap[5]->NotButton.HasNull                   = 0
+pp_data->cap[5]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[5]->NotButton.LogicalMin                = 0
+pp_data->cap[5]->NotButton.LogicalMax                = 1
+pp_data->cap[5]->NotButton.PhysicalMin               = 0
+pp_data->cap[5]->NotButton.PhysicalMax               = 0
+pp_data->cap[5]->Units                    = 0
+pp_data->cap[5]->UnitsExp                 = 0
+
+pp_data->cap[6]->UsagePage                    = 0x000C
+pp_data->cap[6]->ReportID                     = 0x07
+pp_data->cap[6]->BitPosition                  = 0
+pp_data->cap[6]->BitSize                      = 8
+pp_data->cap[6]->ReportCount                  = 32
+pp_data->cap[6]->BytePosition                 = 0x0001
+pp_data->cap[6]->BitCount                     = 256
+pp_data->cap[6]->BitField                     = 0x02
+pp_data->cap[6]->NextBytePosition             = 0x0021
+pp_data->cap[6]->LinkCollection               = 0x0000
+pp_data->cap[6]->LinkUsagePage                = 0x000C
+pp_data->cap[6]->LinkUsage                    = 0x0001
+pp_data->cap[6]->IsMultipleItemsForArray      = 0
+pp_data->cap[6]->IsButtonCap                  = 0
+pp_data->cap[6]->IsPadding                    = 0
+pp_data->cap[6]->IsAbsolute                   = 1
+pp_data->cap[6]->IsRange                      = 0
+pp_data->cap[6]->IsAlias                      = 0
+pp_data->cap[6]->IsStringRange                = 0
+pp_data->cap[6]->IsDesignatorRange            = 0
+pp_data->cap[6]->Reserved1                    = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[6]->NotRange.Usage                        = 0x0000
+pp_data->cap[6]->NotRange.Reserved1                    = 0x0000
+pp_data->cap[6]->NotRange.StringIndex                  = 0
+pp_data->cap[6]->NotRange.Reserved2                    = 0
+pp_data->cap[6]->NotRange.DesignatorIndex              = 0
+pp_data->cap[6]->NotRange.Reserved3                    = 0
+pp_data->cap[6]->NotRange.DataIndex                    = 7
+pp_data->cap[6]->NotRange.Reserved4                    = 7
+pp_data->cap[6]->NotButton.HasNull                   = 0
+pp_data->cap[6]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[6]->NotButton.LogicalMin                = 0
+pp_data->cap[6]->NotButton.LogicalMax                = 1
+pp_data->cap[6]->NotButton.PhysicalMin               = 0
+pp_data->cap[6]->NotButton.PhysicalMax               = 0
+pp_data->cap[6]->Units                    = 0
+pp_data->cap[6]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[9]->UsagePage                    = 0x000C
+pp_data->cap[9]->ReportID                     = 0x03
+pp_data->cap[9]->BitPosition                  = 0
+pp_data->cap[9]->BitSize                      = 1
+pp_data->cap[9]->ReportCount                  = 16
+pp_data->cap[9]->BytePosition                 = 0x0001
+pp_data->cap[9]->BitCount                     = 16
+pp_data->cap[9]->BitField                     = 0x02
+pp_data->cap[9]->NextBytePosition             = 0x0003
+pp_data->cap[9]->LinkCollection               = 0x0000
+pp_data->cap[9]->LinkUsagePage                = 0x000C
+pp_data->cap[9]->LinkUsage                    = 0x0001
+pp_data->cap[9]->IsMultipleItemsForArray      = 0
+pp_data->cap[9]->IsButtonCap                  = 1
+pp_data->cap[9]->IsPadding                    = 0
+pp_data->cap[9]->IsAbsolute                   = 1
+pp_data->cap[9]->IsRange                      = 0
+pp_data->cap[9]->IsAlias                      = 0
+pp_data->cap[9]->IsStringRange                = 0
+pp_data->cap[9]->IsDesignatorRange            = 0
+pp_data->cap[9]->Reserved1                    = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[9]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[9]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[9]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[9]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[9]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[9]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[9]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[9]->NotRange.Usage                        = 0x0000
+pp_data->cap[9]->NotRange.Reserved1                    = 0x0000
+pp_data->cap[9]->NotRange.StringIndex                  = 0
+pp_data->cap[9]->NotRange.Reserved2                    = 0
+pp_data->cap[9]->NotRange.DesignatorIndex              = 0
+pp_data->cap[9]->NotRange.Reserved3                    = 0
+pp_data->cap[9]->NotRange.DataIndex                    = 0
+pp_data->cap[9]->NotRange.Reserved4                    = 0
+pp_data->cap[9]->Button.LogicalMin                   = 0
+pp_data->cap[9]->Button.LogicalMax                   = 0
+pp_data->cap[9]->Units                    = 0
+pp_data->cap[9]->UnitsExp                 = 0
+
+pp_data->cap[10]->UsagePage                    = 0x000C
+pp_data->cap[10]->ReportID                     = 0x04
+pp_data->cap[10]->BitPosition                  = 0
+pp_data->cap[10]->BitSize                      = 8
+pp_data->cap[10]->ReportCount                  = 36
+pp_data->cap[10]->BytePosition                 = 0x0001
+pp_data->cap[10]->BitCount                     = 288
+pp_data->cap[10]->BitField                     = 0x02
+pp_data->cap[10]->NextBytePosition             = 0x0025
+pp_data->cap[10]->LinkCollection               = 0x0000
+pp_data->cap[10]->LinkUsagePage                = 0x000C
+pp_data->cap[10]->LinkUsage                    = 0x0001
+pp_data->cap[10]->IsMultipleItemsForArray      = 0
+pp_data->cap[10]->IsButtonCap                  = 0
+pp_data->cap[10]->IsPadding                    = 0
+pp_data->cap[10]->IsAbsolute                   = 1
+pp_data->cap[10]->IsRange                      = 0
+pp_data->cap[10]->IsAlias                      = 0
+pp_data->cap[10]->IsStringRange                = 0
+pp_data->cap[10]->IsDesignatorRange            = 0
+pp_data->cap[10]->Reserved1                    = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[10]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[10]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[10]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[10]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[10]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[10]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[10]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[10]->NotRange.Usage                        = 0x0000
+pp_data->cap[10]->NotRange.Reserved1                    = 0x0000
+pp_data->cap[10]->NotRange.StringIndex                  = 0
+pp_data->cap[10]->NotRange.Reserved2                    = 0
+pp_data->cap[10]->NotRange.DesignatorIndex              = 0
+pp_data->cap[10]->NotRange.Reserved3                    = 0
+pp_data->cap[10]->NotRange.DataIndex                    = 1
+pp_data->cap[10]->NotRange.Reserved4                    = 1
+pp_data->cap[10]->NotButton.HasNull                   = 0
+pp_data->cap[10]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[10]->NotButton.LogicalMin                = 0
+pp_data->cap[10]->NotButton.LogicalMax                = 1
+pp_data->cap[10]->NotButton.PhysicalMin               = 0
+pp_data->cap[10]->NotButton.PhysicalMax               = 0
+pp_data->cap[10]->Units                    = 0
+pp_data->cap[10]->UnitsExp                 = 0
+
+pp_data->cap[11]->UsagePage                    = 0x000C
+pp_data->cap[11]->ReportID                     = 0x06
+pp_data->cap[11]->BitPosition                  = 0
+pp_data->cap[11]->BitSize                      = 8
+pp_data->cap[11]->ReportCount                  = 36
+pp_data->cap[11]->BytePosition                 = 0x0001
+pp_data->cap[11]->BitCount                     = 288
+pp_data->cap[11]->BitField                     = 0x02
+pp_data->cap[11]->NextBytePosition             = 0x0025
+pp_data->cap[11]->LinkCollection               = 0x0000
+pp_data->cap[11]->LinkUsagePage                = 0x000C
+pp_data->cap[11]->LinkUsage                    = 0x0001
+pp_data->cap[11]->IsMultipleItemsForArray      = 0
+pp_data->cap[11]->IsButtonCap                  = 0
+pp_data->cap[11]->IsPadding                    = 0
+pp_data->cap[11]->IsAbsolute                   = 1
+pp_data->cap[11]->IsRange                      = 0
+pp_data->cap[11]->IsAlias                      = 0
+pp_data->cap[11]->IsStringRange                = 0
+pp_data->cap[11]->IsDesignatorRange            = 0
+pp_data->cap[11]->Reserved1                    = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[11]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[11]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[11]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[11]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[11]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[11]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[11]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[11]->NotRange.Usage                        = 0x0000
+pp_data->cap[11]->NotRange.Reserved1                    = 0x0000
+pp_data->cap[11]->NotRange.StringIndex                  = 0
+pp_data->cap[11]->NotRange.Reserved2                    = 0
+pp_data->cap[11]->NotRange.DesignatorIndex              = 0
+pp_data->cap[11]->NotRange.Reserved3                    = 0
+pp_data->cap[11]->NotRange.DataIndex                    = 2
+pp_data->cap[11]->NotRange.Reserved4                    = 2
+pp_data->cap[11]->NotButton.HasNull                   = 0
+pp_data->cap[11]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[11]->NotButton.LogicalMin                = 0
+pp_data->cap[11]->NotButton.LogicalMax                = 1
+pp_data->cap[11]->NotButton.PhysicalMin               = 0
+pp_data->cap[11]->NotButton.PhysicalMax               = 0
+pp_data->cap[11]->Units                    = 0
+pp_data->cap[11]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x000C
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 1
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 1
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[1]->LinkUsage          = 0x0036
+pp_data->LinkCollectionArray[1]->LinkUsagePage      = 0x000C
+pp_data->LinkCollectionArray[1]->Parent             = 0
+pp_data->LinkCollectionArray[1]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[1]->NextSibling        = 0
+pp_data->LinkCollectionArray[1]->FirstChild         = 0
+pp_data->LinkCollectionArray[1]->CollectionType     = 2
+pp_data->LinkCollectionArray[1]->IsAlias            = 0
+pp_data->LinkCollectionArray[1]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_0A37_0001_000C_expected.rpt_desc b/src/hidapi/windows/test/data/046D_0A37_0001_000C_expected.rpt_desc
new file mode 100644
index 0000000..363a8f5
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_0A37_0001_000C_expected.rpt_desc
@@ -0,0 +1,16 @@
+0x05, 0x0C, 0x09, 0x01, 0xA1, 0x01, 0x85, 0x01, 0x09, 0xE9, 
+0x09, 0xEA, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x02, 
+0x81, 0x02, 0x09, 0xE2, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 
+0x95, 0x01, 0x81, 0x06, 0x75, 0x02, 0x95, 0x01, 0x81, 0x03, 
+0x09, 0x36, 0xA1, 0x02, 0x05, 0x09, 0x19, 0x01, 0x29, 0x02, 
+0x15, 0x01, 0x25, 0x02, 0x75, 0x02, 0x95, 0x01, 0x81, 0x40, 
+0x75, 0x01, 0x95, 0x01, 0x81, 0x03, 0xC0, 0x85, 0x02, 0x05, 
+0x0C, 0x09, 0x00, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 
+0x10, 0x81, 0x02, 0x85, 0x05, 0x09, 0x00, 0x15, 0x00, 0x25, 
+0x01, 0x75, 0x08, 0x95, 0x20, 0x81, 0x02, 0x85, 0x07, 0x09, 
+0x00, 0x15, 0x00, 0x25, 0x01, 0x75, 0x08, 0x95, 0x20, 0x81, 
+0x02, 0x85, 0x03, 0x09, 0x00, 0x15, 0x00, 0x25, 0x01, 0x75, 
+0x01, 0x95, 0x10, 0x91, 0x02, 0x85, 0x04, 0x09, 0x00, 0x15, 
+0x00, 0x25, 0x01, 0x75, 0x08, 0x95, 0x24, 0x91, 0x02, 0x85, 
+0x06, 0x09, 0x00, 0x15, 0x00, 0x25, 0x01, 0x75, 0x08, 0x95, 
+0x24, 0x91, 0x02, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_0A37_0001_000C_real.rpt_desc b/src/hidapi/windows/test/data/046D_0A37_0001_000C_real.rpt_desc
new file mode 100644
index 0000000..c784743
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_0A37_0001_000C_real.rpt_desc
@@ -0,0 +1,61 @@
+Usage Page (Consumer Devices) 05 0C  
+Usage (Consumer Control) 09 01  
+Collection (Application) A1 01  
+    Report ID (1) 85 01  
+    Logical Minimum (0) 15 00  
+    Logical Maximum (1) 25 01  
+    Usage (Volume Increment) 09 E9  
+    Usage (Volume Decrement) 09 EA  
+    Report Size (1) 75 01  
+    Report Count (2) 95 02  
+    Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02  
+    Usage (Mute) 09 E2  
+    Report Count (1) 95 01  
+    Input (Data,Var,Rel,NWrp,Lin,Pref,NNul,Bit) 81 06  
+    Usage (Undefined) 09 00  
+    Report Count (2) 95 02  
+    Input (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 03  
+    Usage (Function Buttons) 09 36  
+    Collection (Logical) A1 02  
+        Usage Page (Button) 05 09  
+        Usage Minimum (Button 1) 19 01  
+        Usage Maximum (Button 2) 29 02  
+        Report Size (2) 75 02  
+        Report Count (1) 95 01  
+        Logical Minimum (1) 15 01  
+        Logical Maximum (2) 25 02  
+        Input (Data,Ary,Abs) 81 40  
+    End Collection C0  
+    Usage Page (Consumer Devices) 05 0C  
+    Usage (Undefined) 09 00  
+    Logical Minimum (0) 15 00  
+    Logical Maximum (1) 25 01  
+    Report Size (1) 75 01  
+    Report Count (1) 95 01  
+    Input (Cnst,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 03  
+    Report ID (2) 85 02  
+    Usage Page (Consumer Devices) 05 0C  
+    Usage (Undefined) 09 00  
+    Report Count (16) 95 10  
+    Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02  
+    Report ID (3) 85 03  
+    Usage (Undefined) 09 00  
+    Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 02  
+    Report ID (4) 85 04  
+    Usage (Undefined) 09 00  
+    Report Size (8) 75 08  
+    Report Count (36) 95 24  
+    Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 02  
+    Report ID (5) 85 05  
+    Usage (Undefined) 09 00  
+    Report Count (32) 95 20  
+    Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02  
+    Report ID (6) 85 06  
+    Usage (Undefined) 09 00  
+    Report Count (36) 95 24  
+    Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 02  
+    Report ID (7) 85 07  
+    Usage (Undefined) 09 00  
+    Report Count (32) 95 20  
+    Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02  
+End Collection C0 
diff --git a/src/hidapi/windows/test/data/046D_B010_0001_000C.pp_data b/src/hidapi/windows/test/data/046D_B010_0001_000C.pp_data
new file mode 100644
index 0000000..047445b
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0001_000C.pp_data
@@ -0,0 +1,97 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xB010
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "Logitech Bluetooth Wireless Mouse"
+dev->release_number      = 0x0000
+dev->interface_number    = -1
+dev->usage               = 0x0001
+dev->usage_page          = 0x000C
+dev->path                = "\\?\hid#{00001124-0000-1000-8000-00805f9b34fb}_vid&0002046d_pid&b010&col02#8&1cf1c1b9&3&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0001
+pp_data->UsagePage                            = 0x000C
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 1
+pp_data->caps_info[0]->NumberOfCaps       = 1
+pp_data->caps_info[0]->ReportByteLength   = 2
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 1
+pp_data->caps_info[1]->LastCap            = 1
+pp_data->caps_info[1]->NumberOfCaps       = 0
+pp_data->caps_info[1]->ReportByteLength   = 0
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 1
+pp_data->caps_info[2]->LastCap            = 1
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x0068
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x0006
+pp_data->cap[0]->ReportID                     = 0x03
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 8
+pp_data->cap[0]->ReportCount                  = 1
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 8
+pp_data->cap[0]->BitField                     = 0x02
+pp_data->cap[0]->NextBytePosition             = 0x0002
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0x000C
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 0
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x0020
+pp_data->cap[0]->NotRange.Reserved1                    = 0x0020
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->NotButton.HasNull                   = 0
+pp_data->cap[0]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[0]->NotButton.LogicalMin                = 0
+pp_data->cap[0]->NotButton.LogicalMax                = 100
+pp_data->cap[0]->NotButton.PhysicalMin               = 0
+pp_data->cap[0]->NotButton.PhysicalMax               = 0
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x000C
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_B010_0001_000C_expected.rpt_desc b/src/hidapi/windows/test/data/046D_B010_0001_000C_expected.rpt_desc
new file mode 100644
index 0000000..c80dd13
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0001_000C_expected.rpt_desc
@@ -0,0 +1,3 @@
+0x05, 0x0C, 0x09, 0x01, 0xA1, 0x01, 0x85, 0x03, 0x05, 0x06, 
+0x09, 0x20, 0x15, 0x00, 0x25, 0x64, 0x75, 0x08, 0x95, 0x01, 
+0x81, 0x02, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_B010_0001_000C_real.rpt_desc b/src/hidapi/windows/test/data/046D_B010_0001_000C_real.rpt_desc
new file mode 100644
index 0000000..ff019a9
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0001_000C_real.rpt_desc
@@ -0,0 +1,38 @@
+
+mac-hid-dump on  main ❯ ./mac-hid-dump 
+mac-hid-dump:
+...
+046D B010: Unknown - Bluetooth Mouse M557
+DESCRIPTOR:
+  05  01  09  02  a1  01  85  02  09  01  a1  00  05  09  19  01 
+  29  08  15  00  25  01  75  01  95  08  81  02  05  01  09  30 
+  09  31  16  01  f8  26  ff  07  75  0c  95  02  81  06  09  38 
+  15  81  25  7f  75  08  95  01  81  06  05  0c  0a  38  02  75 
+  08  95  01  81  06  c0  c0  05  0c  09  01  a1  01  85  03  05 
+  06  09  20  15  00  26  64  00  75  08  95  01  81  02  c0  06 
+  00  ff  09  01  a1  01  85  10  75  08  95  06  15  00  26  ff 
+  00  09  01  81  00  09  01  91  00  c0  06  00  ff  09  02  a1 
+  01  85  11  75  08  95  13  15  00  26  ff  00  09  02  81  00 
+  09  02  91  00  c0  05  01  09  06  a1  01  85  04  75  01  95 
+  08  05  07  19  e0  29  e7  15  00  25  01  81  02  95  01  75 
+  08  81  03  95  05  75  01  05  08  19  01  29  05  91  02  95 
+  01  75  03  91  03  95  06  75  08  15  00  26  ff  00  05  07 
+  19  00  29  ff  81  00  c0  05  0c  09  01  a1  01  85  05  15 
+  00  25  01  75  01  95  02  0a  25  02  0a  24  02  81  02  95 
+  01  75  06  81  03  c0  
+  (246 bytes)
+
+Parser output:
+
+0x05, 0x0C,        // Usage Page (Consumer)
+0x09, 0x01,        // Usage (Consumer Control)
+0xA1, 0x01,        // Collection (Application)
+0x85, 0x03,        //   Report ID (3)
+0x05, 0x06,        //   Usage Page (Generic Dev Ctrls)
+0x09, 0x20,        //   Usage (Battery Strength)
+0x15, 0x00,        //   Logical Minimum (0)
+0x26, 0x64, 0x00,  //   Logical Maximum (100)
+0x75, 0x08,        //   Report Size (8)
+0x95, 0x01,        //   Report Count (1)
+0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0xC0,              // End Collection
diff --git a/src/hidapi/windows/test/data/046D_B010_0001_FF00.pp_data b/src/hidapi/windows/test/data/046D_B010_0001_FF00.pp_data
new file mode 100644
index 0000000..13b27da
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0001_FF00.pp_data
@@ -0,0 +1,139 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xB010
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "Logitech Bluetooth Wireless Mouse"
+dev->release_number      = 0x0000
+dev->interface_number    = -1
+dev->usage               = 0x0001
+dev->usage_page          = 0xFF00
+dev->path                = "\\?\hid#{00001124-0000-1000-8000-00805f9b34fb}_vid&0002046d_pid&b010&col03#8&1cf1c1b9&3&0002#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0001
+pp_data->UsagePage                            = 0xFF00
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 1
+pp_data->caps_info[0]->NumberOfCaps       = 1
+pp_data->caps_info[0]->ReportByteLength   = 7
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 1
+pp_data->caps_info[1]->LastCap            = 2
+pp_data->caps_info[1]->NumberOfCaps       = 1
+pp_data->caps_info[1]->ReportByteLength   = 7
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 2
+pp_data->caps_info[2]->LastCap            = 2
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x00D0
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0xFF00
+pp_data->cap[0]->ReportID                     = 0x10
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 8
+pp_data->cap[0]->ReportCount                  = 6
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 48
+pp_data->cap[0]->BitField                     = 0x00
+pp_data->cap[0]->NextBytePosition             = 0x0007
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0xFF00
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x0001
+pp_data->cap[0]->NotRange.Reserved1                    = 0x0001
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 255
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[1]->UsagePage                    = 0xFF00
+pp_data->cap[1]->ReportID                     = 0x10
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 8
+pp_data->cap[1]->ReportCount                  = 6
+pp_data->cap[1]->BytePosition                 = 0x0001
+pp_data->cap[1]->BitCount                     = 48
+pp_data->cap[1]->BitField                     = 0x00
+pp_data->cap[1]->NextBytePosition             = 0x0007
+pp_data->cap[1]->LinkCollection               = 0x0000
+pp_data->cap[1]->LinkUsagePage                = 0xFF00
+pp_data->cap[1]->LinkUsage                    = 0x0001
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 1
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0001
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0001
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 0
+pp_data->cap[1]->NotRange.Reserved4                    = 0
+pp_data->cap[1]->Button.LogicalMin                   = 0
+pp_data->cap[1]->Button.LogicalMax                   = 255
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0xFF00
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_B010_0001_FF00_expected.rpt_desc b/src/hidapi/windows/test/data/046D_B010_0001_FF00_expected.rpt_desc
new file mode 100644
index 0000000..812bd2a
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0001_FF00_expected.rpt_desc
@@ -0,0 +1,4 @@
+0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x85, 0x10, 0x09, 
+0x01, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x06, 
+0x81, 0x00, 0x09, 0x01, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x06, 0x91, 0x00, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_B010_0001_FF00_real.rpt_desc b/src/hidapi/windows/test/data/046D_B010_0001_FF00_real.rpt_desc
new file mode 100644
index 0000000..340d08d
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0001_FF00_real.rpt_desc
@@ -0,0 +1,39 @@
+
+mac-hid-dump on  main ❯ ./mac-hid-dump 
+mac-hid-dump:
+...
+046D B010: Unknown - Bluetooth Mouse M557
+DESCRIPTOR:
+  05  01  09  02  a1  01  85  02  09  01  a1  00  05  09  19  01 
+  29  08  15  00  25  01  75  01  95  08  81  02  05  01  09  30 
+  09  31  16  01  f8  26  ff  07  75  0c  95  02  81  06  09  38 
+  15  81  25  7f  75  08  95  01  81  06  05  0c  0a  38  02  75 
+  08  95  01  81  06  c0  c0  05  0c  09  01  a1  01  85  03  05 
+  06  09  20  15  00  26  64  00  75  08  95  01  81  02  c0  06 
+  00  ff  09  01  a1  01  85  10  75  08  95  06  15  00  26  ff 
+  00  09  01  81  00  09  01  91  00  c0  06  00  ff  09  02  a1 
+  01  85  11  75  08  95  13  15  00  26  ff  00  09  02  81  00 
+  09  02  91  00  c0  05  01  09  06  a1  01  85  04  75  01  95 
+  08  05  07  19  e0  29  e7  15  00  25  01  81  02  95  01  75 
+  08  81  03  95  05  75  01  05  08  19  01  29  05  91  02  95 
+  01  75  03  91  03  95  06  75  08  15  00  26  ff  00  05  07 
+  19  00  29  ff  81  00  c0  05  0c  09  01  a1  01  85  05  15 
+  00  25  01  75  01  95  02  0a  25  02  0a  24  02  81  02  95 
+  01  75  06  81  03  c0  
+  (246 bytes)
+
+Parser output:
+
+0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
+0x09, 0x01,        // Usage (0x01)
+0xA1, 0x01,        // Collection (Application)
+0x85, 0x10,        //   Report ID (16)
+0x75, 0x08,        //   Report Size (8)
+0x95, 0x06,        //   Report Count (6)
+0x15, 0x00,        //   Logical Minimum (0)
+0x26, 0xFF, 0x00,  //   Logical Maximum (255)
+0x09, 0x01,        //   Usage (0x01)
+0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x09, 0x01,        //   Usage (0x01)
+0x91, 0x00,        //   Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0xC0,              // End Collection
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_B010_0002_0001.pp_data b/src/hidapi/windows/test/data/046D_B010_0002_0001.pp_data
new file mode 100644
index 0000000..1976766
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0002_0001.pp_data
@@ -0,0 +1,302 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xB010
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "Logitech Bluetooth Wireless Mouse"
+dev->release_number      = 0x0000
+dev->interface_number    = -1
+dev->usage               = 0x0002
+dev->usage_page          = 0x0001
+dev->path                = "\\?\hid#{00001124-0000-1000-8000-00805f9b34fb}_vid&0002046d_pid&b010&col01#8&1cf1c1b9&3&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0002
+pp_data->UsagePage                            = 0x0001
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 5
+pp_data->caps_info[0]->NumberOfCaps       = 5
+pp_data->caps_info[0]->ReportByteLength   = 7
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 5
+pp_data->caps_info[1]->LastCap            = 5
+pp_data->caps_info[1]->NumberOfCaps       = 0
+pp_data->caps_info[1]->ReportByteLength   = 0
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 5
+pp_data->caps_info[2]->LastCap            = 5
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x0208
+pp_data->NumberLinkCollectionNodes            = 2
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x0009
+pp_data->cap[0]->ReportID                     = 0x02
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 1
+pp_data->cap[0]->ReportCount                  = 8
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 8
+pp_data->cap[0]->BitField                     = 0x02
+pp_data->cap[0]->NextBytePosition             = 0x0002
+pp_data->cap[0]->LinkCollection               = 0x0001
+pp_data->cap[0]->LinkUsagePage                = 0x0001
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 1
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->Range.UsageMin                     = 0x0001
+pp_data->cap[0]->Range.UsageMax                     = 0x0008
+pp_data->cap[0]->Range.StringMin                    = 0
+pp_data->cap[0]->Range.StringMax                    = 0
+pp_data->cap[0]->Range.DesignatorMin                = 0
+pp_data->cap[0]->Range.DesignatorMax                = 0
+pp_data->cap[0]->Range.DataIndexMin                 = 0
+pp_data->cap[0]->Range.DataIndexMax                 = 7
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 0
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0x0001
+pp_data->cap[1]->ReportID                     = 0x02
+pp_data->cap[1]->BitPosition                  = 4
+pp_data->cap[1]->BitSize                      = 12
+pp_data->cap[1]->ReportCount                  = 1
+pp_data->cap[1]->BytePosition                 = 0x0003
+pp_data->cap[1]->BitCount                     = 12
+pp_data->cap[1]->BitField                     = 0x06
+pp_data->cap[1]->NextBytePosition             = 0x0005
+pp_data->cap[1]->LinkCollection               = 0x0001
+pp_data->cap[1]->LinkUsagePage                = 0x0001
+pp_data->cap[1]->LinkUsage                    = 0x0001
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 0
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 0
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0031
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0031
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 8
+pp_data->cap[1]->NotRange.Reserved4                    = 8
+pp_data->cap[1]->NotButton.HasNull                   = 0
+pp_data->cap[1]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[1]->NotButton.LogicalMin                = -2047
+pp_data->cap[1]->NotButton.LogicalMax                = 2047
+pp_data->cap[1]->NotButton.PhysicalMin               = 0
+pp_data->cap[1]->NotButton.PhysicalMax               = 0
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+pp_data->cap[2]->UsagePage                    = 0x0001
+pp_data->cap[2]->ReportID                     = 0x02
+pp_data->cap[2]->BitPosition                  = 0
+pp_data->cap[2]->BitSize                      = 12
+pp_data->cap[2]->ReportCount                  = 1
+pp_data->cap[2]->BytePosition                 = 0x0002
+pp_data->cap[2]->BitCount                     = 12
+pp_data->cap[2]->BitField                     = 0x06
+pp_data->cap[2]->NextBytePosition             = 0x0004
+pp_data->cap[2]->LinkCollection               = 0x0001
+pp_data->cap[2]->LinkUsagePage                = 0x0001
+pp_data->cap[2]->LinkUsage                    = 0x0001
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 0
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 0
+pp_data->cap[2]->IsRange                      = 0
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->NotRange.Usage                        = 0x0030
+pp_data->cap[2]->NotRange.Reserved1                    = 0x0030
+pp_data->cap[2]->NotRange.StringIndex                  = 0
+pp_data->cap[2]->NotRange.Reserved2                    = 0
+pp_data->cap[2]->NotRange.DesignatorIndex              = 0
+pp_data->cap[2]->NotRange.Reserved3                    = 0
+pp_data->cap[2]->NotRange.DataIndex                    = 9
+pp_data->cap[2]->NotRange.Reserved4                    = 9
+pp_data->cap[2]->NotButton.HasNull                   = 0
+pp_data->cap[2]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[2]->NotButton.LogicalMin                = -2047
+pp_data->cap[2]->NotButton.LogicalMax                = 2047
+pp_data->cap[2]->NotButton.PhysicalMin               = 0
+pp_data->cap[2]->NotButton.PhysicalMax               = 0
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+pp_data->cap[3]->UsagePage                    = 0x0001
+pp_data->cap[3]->ReportID                     = 0x02
+pp_data->cap[3]->BitPosition                  = 0
+pp_data->cap[3]->BitSize                      = 8
+pp_data->cap[3]->ReportCount                  = 1
+pp_data->cap[3]->BytePosition                 = 0x0005
+pp_data->cap[3]->BitCount                     = 8
+pp_data->cap[3]->BitField                     = 0x06
+pp_data->cap[3]->NextBytePosition             = 0x0006
+pp_data->cap[3]->LinkCollection               = 0x0001
+pp_data->cap[3]->LinkUsagePage                = 0x0001
+pp_data->cap[3]->LinkUsage                    = 0x0001
+pp_data->cap[3]->IsMultipleItemsForArray      = 0
+pp_data->cap[3]->IsButtonCap                  = 0
+pp_data->cap[3]->IsPadding                    = 0
+pp_data->cap[3]->IsAbsolute                   = 0
+pp_data->cap[3]->IsRange                      = 0
+pp_data->cap[3]->IsAlias                      = 0
+pp_data->cap[3]->IsStringRange                = 0
+pp_data->cap[3]->IsDesignatorRange            = 0
+pp_data->cap[3]->Reserved1                    = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[3]->NotRange.Usage                        = 0x0038
+pp_data->cap[3]->NotRange.Reserved1                    = 0x0038
+pp_data->cap[3]->NotRange.StringIndex                  = 0
+pp_data->cap[3]->NotRange.Reserved2                    = 0
+pp_data->cap[3]->NotRange.DesignatorIndex              = 0
+pp_data->cap[3]->NotRange.Reserved3                    = 0
+pp_data->cap[3]->NotRange.DataIndex                    = 10
+pp_data->cap[3]->NotRange.Reserved4                    = 10
+pp_data->cap[3]->NotButton.HasNull                   = 0
+pp_data->cap[3]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[3]->NotButton.LogicalMin                = -127
+pp_data->cap[3]->NotButton.LogicalMax                = 127
+pp_data->cap[3]->NotButton.PhysicalMin               = 0
+pp_data->cap[3]->NotButton.PhysicalMax               = 0
+pp_data->cap[3]->Units                    = 0
+pp_data->cap[3]->UnitsExp                 = 0
+
+pp_data->cap[4]->UsagePage                    = 0x000C
+pp_data->cap[4]->ReportID                     = 0x02
+pp_data->cap[4]->BitPosition                  = 0
+pp_data->cap[4]->BitSize                      = 8
+pp_data->cap[4]->ReportCount                  = 1
+pp_data->cap[4]->BytePosition                 = 0x0006
+pp_data->cap[4]->BitCount                     = 8
+pp_data->cap[4]->BitField                     = 0x06
+pp_data->cap[4]->NextBytePosition             = 0x0007
+pp_data->cap[4]->LinkCollection               = 0x0001
+pp_data->cap[4]->LinkUsagePage                = 0x0001
+pp_data->cap[4]->LinkUsage                    = 0x0001
+pp_data->cap[4]->IsMultipleItemsForArray      = 0
+pp_data->cap[4]->IsButtonCap                  = 0
+pp_data->cap[4]->IsPadding                    = 0
+pp_data->cap[4]->IsAbsolute                   = 0
+pp_data->cap[4]->IsRange                      = 0
+pp_data->cap[4]->IsAlias                      = 0
+pp_data->cap[4]->IsStringRange                = 0
+pp_data->cap[4]->IsDesignatorRange            = 0
+pp_data->cap[4]->Reserved1                    = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[4]->NotRange.Usage                        = 0x0238
+pp_data->cap[4]->NotRange.Reserved1                    = 0x0238
+pp_data->cap[4]->NotRange.StringIndex                  = 0
+pp_data->cap[4]->NotRange.Reserved2                    = 0
+pp_data->cap[4]->NotRange.DesignatorIndex              = 0
+pp_data->cap[4]->NotRange.Reserved3                    = 0
+pp_data->cap[4]->NotRange.DataIndex                    = 11
+pp_data->cap[4]->NotRange.Reserved4                    = 11
+pp_data->cap[4]->NotButton.HasNull                   = 0
+pp_data->cap[4]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[4]->NotButton.LogicalMin                = -127
+pp_data->cap[4]->NotButton.LogicalMax                = 127
+pp_data->cap[4]->NotButton.PhysicalMin               = 0
+pp_data->cap[4]->NotButton.PhysicalMax               = 0
+pp_data->cap[4]->Units                    = 0
+pp_data->cap[4]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0002
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 1
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 1
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[1]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[1]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[1]->Parent             = 0
+pp_data->LinkCollectionArray[1]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[1]->NextSibling        = 0
+pp_data->LinkCollectionArray[1]->FirstChild         = 0
+pp_data->LinkCollectionArray[1]->CollectionType     = 0
+pp_data->LinkCollectionArray[1]->IsAlias            = 0
+pp_data->LinkCollectionArray[1]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_B010_0002_0001_expected.rpt_desc b/src/hidapi/windows/test/data/046D_B010_0002_0001_expected.rpt_desc
new file mode 100644
index 0000000..d782fa1
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0002_0001_expected.rpt_desc
@@ -0,0 +1,8 @@
+0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1, 0x00, 
+0x85, 0x02, 0x05, 0x09, 0x19, 0x01, 0x29, 0x08, 0x15, 0x00, 
+0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x05, 0x01, 
+0x09, 0x30, 0x09, 0x31, 0x16, 0x01, 0xF8, 0x26, 0xFF, 0x07, 
+0x75, 0x0C, 0x95, 0x02, 0x81, 0x06, 0x09, 0x38, 0x15, 0x81, 
+0x25, 0x7F, 0x75, 0x08, 0x95, 0x01, 0x81, 0x06, 0x05, 0x0C, 
+0x0A, 0x38, 0x02, 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08, 0x95, 
+0x01, 0x81, 0x06, 0xC0, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_B010_0002_0001_real.rpt_desc b/src/hidapi/windows/test/data/046D_B010_0002_0001_real.rpt_desc
new file mode 100644
index 0000000..483f659
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0002_0001_real.rpt_desc
@@ -0,0 +1,61 @@
+
+mac-hid-dump on  main ❯ ./mac-hid-dump 
+mac-hid-dump:
+...
+046D B010: Unknown - Bluetooth Mouse M557
+DESCRIPTOR:
+  05  01  09  02  a1  01  85  02  09  01  a1  00  05  09  19  01 
+  29  08  15  00  25  01  75  01  95  08  81  02  05  01  09  30 
+  09  31  16  01  f8  26  ff  07  75  0c  95  02  81  06  09  38 
+  15  81  25  7f  75  08  95  01  81  06  05  0c  0a  38  02  75 
+  08  95  01  81  06  c0  c0  05  0c  09  01  a1  01  85  03  05 
+  06  09  20  15  00  26  64  00  75  08  95  01  81  02  c0  06 
+  00  ff  09  01  a1  01  85  10  75  08  95  06  15  00  26  ff 
+  00  09  01  81  00  09  01  91  00  c0  06  00  ff  09  02  a1 
+  01  85  11  75  08  95  13  15  00  26  ff  00  09  02  81  00 
+  09  02  91  00  c0  05  01  09  06  a1  01  85  04  75  01  95 
+  08  05  07  19  e0  29  e7  15  00  25  01  81  02  95  01  75 
+  08  81  03  95  05  75  01  05  08  19  01  29  05  91  02  95 
+  01  75  03  91  03  95  06  75  08  15  00  26  ff  00  05  07 
+  19  00  29  ff  81  00  c0  05  0c  09  01  a1  01  85  05  15 
+  00  25  01  75  01  95  02  0a  25  02  0a  24  02  81  02  95 
+  01  75  06  81  03  c0  
+  (246 bytes)
+
+Parser output:
+
+0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
+0x09, 0x02,        // Usage (Mouse)
+0xA1, 0x01,        // Collection (Application)
+0x85, 0x02,        //   Report ID (2)
+0x09, 0x01,        //   Usage (Pointer)
+0xA1, 0x00,        //   Collection (Physical)
+0x05, 0x09,        //     Usage Page (Button)
+0x19, 0x01,        //     Usage Minimum (0x01)
+0x29, 0x08,        //     Usage Maximum (0x08)
+0x15, 0x00,        //     Logical Minimum (0)
+0x25, 0x01,        //     Logical Maximum (1)
+0x75, 0x01,        //     Report Size (1)
+0x95, 0x08,        //     Report Count (8)
+0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
+0x09, 0x30,        //     Usage (X)
+0x09, 0x31,        //     Usage (Y)
+0x16, 0x01, 0xF8,  //     Logical Minimum (-2047)
+0x26, 0xFF, 0x07,  //     Logical Maximum (2047)
+0x75, 0x0C,        //     Report Size (12)
+0x95, 0x02,        //     Report Count (2)
+0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+0x09, 0x38,        //     Usage (Wheel)
+0x15, 0x81,        //     Logical Minimum (-127)
+0x25, 0x7F,        //     Logical Maximum (127)
+0x75, 0x08,        //     Report Size (8)
+0x95, 0x01,        //     Report Count (1)
+0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+0x05, 0x0C,        //     Usage Page (Consumer)
+0x0A, 0x38, 0x02,  //     Usage (AC Pan)
+0x75, 0x08,        //     Report Size (8)
+0x95, 0x01,        //     Report Count (1)
+0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+0xC0,              //   End Collection
+0xC0,              // End Collection
diff --git a/src/hidapi/windows/test/data/046D_B010_0002_FF00.pp_data b/src/hidapi/windows/test/data/046D_B010_0002_FF00.pp_data
new file mode 100644
index 0000000..0dc64b2
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0002_FF00.pp_data
@@ -0,0 +1,139 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xB010
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "Logitech Bluetooth Wireless Mouse"
+dev->release_number      = 0x0000
+dev->interface_number    = -1
+dev->usage               = 0x0002
+dev->usage_page          = 0xFF00
+dev->path                = "\\?\hid#{00001124-0000-1000-8000-00805f9b34fb}_vid&0002046d_pid&b010&col04#8&1cf1c1b9&3&0003#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0002
+pp_data->UsagePage                            = 0xFF00
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 1
+pp_data->caps_info[0]->NumberOfCaps       = 1
+pp_data->caps_info[0]->ReportByteLength   = 20
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 1
+pp_data->caps_info[1]->LastCap            = 2
+pp_data->caps_info[1]->NumberOfCaps       = 1
+pp_data->caps_info[1]->ReportByteLength   = 20
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 2
+pp_data->caps_info[2]->LastCap            = 2
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x00D0
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0xFF00
+pp_data->cap[0]->ReportID                     = 0x11
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 8
+pp_data->cap[0]->ReportCount                  = 19
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 152
+pp_data->cap[0]->BitField                     = 0x00
+pp_data->cap[0]->NextBytePosition             = 0x0014
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0xFF00
+pp_data->cap[0]->LinkUsage                    = 0x0002
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x0002
+pp_data->cap[0]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 255
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[1]->UsagePage                    = 0xFF00
+pp_data->cap[1]->ReportID                     = 0x11
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 8
+pp_data->cap[1]->ReportCount                  = 19
+pp_data->cap[1]->BytePosition                 = 0x0001
+pp_data->cap[1]->BitCount                     = 152
+pp_data->cap[1]->BitField                     = 0x00
+pp_data->cap[1]->NextBytePosition             = 0x0014
+pp_data->cap[1]->LinkCollection               = 0x0000
+pp_data->cap[1]->LinkUsagePage                = 0xFF00
+pp_data->cap[1]->LinkUsage                    = 0x0002
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 1
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0002
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 0
+pp_data->cap[1]->NotRange.Reserved4                    = 0
+pp_data->cap[1]->Button.LogicalMin                   = 0
+pp_data->cap[1]->Button.LogicalMax                   = 255
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0002
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0xFF00
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_B010_0002_FF00_expected.rpt_desc b/src/hidapi/windows/test/data/046D_B010_0002_FF00_expected.rpt_desc
new file mode 100644
index 0000000..b1654e7
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0002_FF00_expected.rpt_desc
@@ -0,0 +1,4 @@
+0x06, 0x00, 0xFF, 0x09, 0x02, 0xA1, 0x01, 0x85, 0x11, 0x09, 
+0x02, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x13, 
+0x81, 0x00, 0x09, 0x02, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x13, 0x91, 0x00, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_B010_0002_FF00_real.rpt_desc b/src/hidapi/windows/test/data/046D_B010_0002_FF00_real.rpt_desc
new file mode 100644
index 0000000..8b8dbfc
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0002_FF00_real.rpt_desc
@@ -0,0 +1,39 @@
+
+mac-hid-dump on  main ❯ ./mac-hid-dump 
+mac-hid-dump:
+...
+046D B010: Unknown - Bluetooth Mouse M557
+DESCRIPTOR:
+  05  01  09  02  a1  01  85  02  09  01  a1  00  05  09  19  01 
+  29  08  15  00  25  01  75  01  95  08  81  02  05  01  09  30 
+  09  31  16  01  f8  26  ff  07  75  0c  95  02  81  06  09  38 
+  15  81  25  7f  75  08  95  01  81  06  05  0c  0a  38  02  75 
+  08  95  01  81  06  c0  c0  05  0c  09  01  a1  01  85  03  05 
+  06  09  20  15  00  26  64  00  75  08  95  01  81  02  c0  06 
+  00  ff  09  01  a1  01  85  10  75  08  95  06  15  00  26  ff 
+  00  09  01  81  00  09  01  91  00  c0  06  00  ff  09  02  a1 
+  01  85  11  75  08  95  13  15  00  26  ff  00  09  02  81  00 
+  09  02  91  00  c0  05  01  09  06  a1  01  85  04  75  01  95 
+  08  05  07  19  e0  29  e7  15  00  25  01  81  02  95  01  75 
+  08  81  03  95  05  75  01  05  08  19  01  29  05  91  02  95 
+  01  75  03  91  03  95  06  75  08  15  00  26  ff  00  05  07 
+  19  00  29  ff  81  00  c0  05  0c  09  01  a1  01  85  05  15 
+  00  25  01  75  01  95  02  0a  25  02  0a  24  02  81  02  95 
+  01  75  06  81  03  c0  
+  (246 bytes)
+
+Parser output:
+
+0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
+0x09, 0x02,        // Usage (0x02)
+0xA1, 0x01,        // Collection (Application)
+0x85, 0x11,        //   Report ID (17)
+0x75, 0x08,        //   Report Size (8)
+0x95, 0x13,        //   Report Count (19)
+0x15, 0x00,        //   Logical Minimum (0)
+0x26, 0xFF, 0x00,  //   Logical Maximum (255)
+0x09, 0x02,        //   Usage (0x02)
+0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x09, 0x02,        //   Usage (0x02)
+0x91, 0x00,        //   Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0xC0,              // End Collection
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_B010_0006_0001.pp_data b/src/hidapi/windows/test/data/046D_B010_0006_0001.pp_data
new file mode 100644
index 0000000..7682a0d
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0006_0001.pp_data
@@ -0,0 +1,185 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xB010
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "Logitech Bluetooth Wireless Mouse"
+dev->release_number      = 0x0000
+dev->interface_number    = -1
+dev->usage               = 0x0006
+dev->usage_page          = 0x0001
+dev->path                = "\\?\hid#{00001124-0000-1000-8000-00805f9b34fb}_vid&0002046d_pid&b010&col05#8&1cf1c1b9&3&0004#{4d1e55b2-f16f-11cf-88cb-001111000030}\kbd"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0006
+pp_data->UsagePage                            = 0x0001
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 2
+pp_data->caps_info[0]->NumberOfCaps       = 2
+pp_data->caps_info[0]->ReportByteLength   = 9
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 2
+pp_data->caps_info[1]->LastCap            = 3
+pp_data->caps_info[1]->NumberOfCaps       = 1
+pp_data->caps_info[1]->ReportByteLength   = 2
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 3
+pp_data->caps_info[2]->LastCap            = 3
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x0138
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x0007
+pp_data->cap[0]->ReportID                     = 0x04
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 1
+pp_data->cap[0]->ReportCount                  = 8
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 8
+pp_data->cap[0]->BitField                     = 0x02
+pp_data->cap[0]->NextBytePosition             = 0x0002
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0x0001
+pp_data->cap[0]->LinkUsage                    = 0x0006
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 1
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->Range.UsageMin                     = 0x00E0
+pp_data->cap[0]->Range.UsageMax                     = 0x00E7
+pp_data->cap[0]->Range.StringMin                    = 0
+pp_data->cap[0]->Range.StringMax                    = 0
+pp_data->cap[0]->Range.DesignatorMin                = 0
+pp_data->cap[0]->Range.DesignatorMax                = 0
+pp_data->cap[0]->Range.DataIndexMin                 = 0
+pp_data->cap[0]->Range.DataIndexMax                 = 7
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 0
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0x0007
+pp_data->cap[1]->ReportID                     = 0x04
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 8
+pp_data->cap[1]->ReportCount                  = 6
+pp_data->cap[1]->BytePosition                 = 0x0003
+pp_data->cap[1]->BitCount                     = 48
+pp_data->cap[1]->BitField                     = 0x00
+pp_data->cap[1]->NextBytePosition             = 0x0009
+pp_data->cap[1]->LinkCollection               = 0x0000
+pp_data->cap[1]->LinkUsagePage                = 0x0001
+pp_data->cap[1]->LinkUsage                    = 0x0006
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 1
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 1
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->Range.UsageMin                     = 0x0000
+pp_data->cap[1]->Range.UsageMax                     = 0x00FF
+pp_data->cap[1]->Range.StringMin                    = 0
+pp_data->cap[1]->Range.StringMax                    = 0
+pp_data->cap[1]->Range.DesignatorMin                = 0
+pp_data->cap[1]->Range.DesignatorMax                = 0
+pp_data->cap[1]->Range.DataIndexMin                 = 8
+pp_data->cap[1]->Range.DataIndexMax                 = 263
+pp_data->cap[1]->Button.LogicalMin                   = 0
+pp_data->cap[1]->Button.LogicalMax                   = 255
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[2]->UsagePage                    = 0x0008
+pp_data->cap[2]->ReportID                     = 0x04
+pp_data->cap[2]->BitPosition                  = 0
+pp_data->cap[2]->BitSize                      = 1
+pp_data->cap[2]->ReportCount                  = 5
+pp_data->cap[2]->BytePosition                 = 0x0001
+pp_data->cap[2]->BitCount                     = 5
+pp_data->cap[2]->BitField                     = 0x02
+pp_data->cap[2]->NextBytePosition             = 0x0002
+pp_data->cap[2]->LinkCollection               = 0x0000
+pp_data->cap[2]->LinkUsagePage                = 0x0001
+pp_data->cap[2]->LinkUsage                    = 0x0006
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 1
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 1
+pp_data->cap[2]->IsRange                      = 1
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->Range.UsageMin                     = 0x0001
+pp_data->cap[2]->Range.UsageMax                     = 0x0005
+pp_data->cap[2]->Range.StringMin                    = 0
+pp_data->cap[2]->Range.StringMax                    = 0
+pp_data->cap[2]->Range.DesignatorMin                = 0
+pp_data->cap[2]->Range.DesignatorMax                = 0
+pp_data->cap[2]->Range.DataIndexMin                 = 0
+pp_data->cap[2]->Range.DataIndexMax                 = 4
+pp_data->cap[2]->Button.LogicalMin                   = 0
+pp_data->cap[2]->Button.LogicalMax                   = 0
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0006
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_B010_0006_0001_expected.rpt_desc b/src/hidapi/windows/test/data/046D_B010_0006_0001_expected.rpt_desc
new file mode 100644
index 0000000..1ec0b16
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0006_0001_expected.rpt_desc
@@ -0,0 +1,7 @@
+0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x85, 0x04, 0x05, 0x07, 
+0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 
+0x95, 0x08, 0x81, 0x02, 0x75, 0x08, 0x95, 0x01, 0x81, 0x03, 
+0x19, 0x00, 0x29, 0xFF, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x06, 0x81, 0x00, 0x05, 0x08, 0x19, 0x01, 0x29, 
+0x05, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x05, 0x91, 
+0x02, 0x75, 0x03, 0x95, 0x01, 0x91, 0x03, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_B010_0006_0001_real.rpt_desc b/src/hidapi/windows/test/data/046D_B010_0006_0001_real.rpt_desc
new file mode 100644
index 0000000..59ab03d
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_B010_0006_0001_real.rpt_desc
@@ -0,0 +1,58 @@
+
+mac-hid-dump on  main ❯ ./mac-hid-dump 
+mac-hid-dump:
+...
+046D B010: Unknown - Bluetooth Mouse M557
+DESCRIPTOR:
+  05  01  09  02  a1  01  85  02  09  01  a1  00  05  09  19  01 
+  29  08  15  00  25  01  75  01  95  08  81  02  05  01  09  30 
+  09  31  16  01  f8  26  ff  07  75  0c  95  02  81  06  09  38 
+  15  81  25  7f  75  08  95  01  81  06  05  0c  0a  38  02  75 
+  08  95  01  81  06  c0  c0  05  0c  09  01  a1  01  85  03  05 
+  06  09  20  15  00  26  64  00  75  08  95  01  81  02  c0  06 
+  00  ff  09  01  a1  01  85  10  75  08  95  06  15  00  26  ff 
+  00  09  01  81  00  09  01  91  00  c0  06  00  ff  09  02  a1 
+  01  85  11  75  08  95  13  15  00  26  ff  00  09  02  81  00 
+  09  02  91  00  c0  05  01  09  06  a1  01  85  04  75  01  95 
+  08  05  07  19  e0  29  e7  15  00  25  01  81  02  95  01  75 
+  08  81  03  95  05  75  01  05  08  19  01  29  05  91  02  95 
+  01  75  03  91  03  95  06  75  08  15  00  26  ff  00  05  07 
+  19  00  29  ff  81  00  c0  05  0c  09  01  a1  01  85  05  15 
+  00  25  01  75  01  95  02  0a  25  02  0a  24  02  81  02  95 
+  01  75  06  81  03  c0  
+  (246 bytes)
+
+Parser output:
+0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
+0x09, 0x06,        // Usage (Keyboard)
+0xA1, 0x01,        // Collection (Application)
+0x85, 0x04,        //   Report ID (4)
+0x75, 0x01,        //   Report Size (1)
+0x95, 0x08,        //   Report Count (8)
+0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
+0x19, 0xE0,        //   Usage Minimum (0xE0)
+0x29, 0xE7,        //   Usage Maximum (0xE7)
+0x15, 0x00,        //   Logical Minimum (0)
+0x25, 0x01,        //   Logical Maximum (1)
+0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x95, 0x01,        //   Report Count (1)
+0x75, 0x08,        //   Report Size (8)
+0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x95, 0x05,        //   Report Count (5)
+0x75, 0x01,        //   Report Size (1)
+0x05, 0x08,        //   Usage Page (LEDs)
+0x19, 0x01,        //   Usage Minimum (Num Lock)
+0x29, 0x05,        //   Usage Maximum (Kana)
+0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x95, 0x01,        //   Report Count (1)
+0x75, 0x03,        //   Report Size (3)
+0x91, 0x03,        //   Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x95, 0x06,        //   Report Count (6)
+0x75, 0x08,        //   Report Size (8)
+0x15, 0x00,        //   Logical Minimum (0)
+0x26, 0xFF, 0x00,  //   Logical Maximum (255)
+0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
+0x19, 0x00,        //   Usage Minimum (0x00)
+0x29, 0xFF,        //   Usage Maximum (0xFF)
+0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0xC0,              // End Collection
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C077_0002_0001.pp_data b/src/hidapi/windows/test/data/046D_C077_0002_0001.pp_data
new file mode 100644
index 0000000..3e9fcea
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C077_0002_0001.pp_data
@@ -0,0 +1,252 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xC077
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "USB Optical Mouse"
+dev->release_number      = 0x7200
+dev->interface_number    = -1
+dev->usage               = 0x0002
+dev->usage_page          = 0x0001
+dev->path                = "\\?\hid#vid_046d&pid_c077#7&1875dbae&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0002
+pp_data->UsagePage                            = 0x0001
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 4
+pp_data->caps_info[0]->NumberOfCaps       = 4
+pp_data->caps_info[0]->ReportByteLength   = 5
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 4
+pp_data->caps_info[1]->LastCap            = 4
+pp_data->caps_info[1]->NumberOfCaps       = 0
+pp_data->caps_info[1]->ReportByteLength   = 0
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 4
+pp_data->caps_info[2]->LastCap            = 4
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x01A0
+pp_data->NumberLinkCollectionNodes            = 2
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x0009
+pp_data->cap[0]->ReportID                     = 0x00
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 1
+pp_data->cap[0]->ReportCount                  = 8
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 8
+pp_data->cap[0]->BitField                     = 0x02
+pp_data->cap[0]->NextBytePosition             = 0x0002
+pp_data->cap[0]->LinkCollection               = 0x0001
+pp_data->cap[0]->LinkUsagePage                = 0x0001
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 1
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->Range.UsageMin                     = 0x0001
+pp_data->cap[0]->Range.UsageMax                     = 0x0003
+pp_data->cap[0]->Range.StringMin                    = 0
+pp_data->cap[0]->Range.StringMax                    = 0
+pp_data->cap[0]->Range.DesignatorMin                = 0
+pp_data->cap[0]->Range.DesignatorMax                = 0
+pp_data->cap[0]->Range.DataIndexMin                 = 0
+pp_data->cap[0]->Range.DataIndexMax                 = 2
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 0
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0x0001
+pp_data->cap[1]->ReportID                     = 0x00
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 8
+pp_data->cap[1]->ReportCount                  = 1
+pp_data->cap[1]->BytePosition                 = 0x0004
+pp_data->cap[1]->BitCount                     = 8
+pp_data->cap[1]->BitField                     = 0x06
+pp_data->cap[1]->NextBytePosition             = 0x0005
+pp_data->cap[1]->LinkCollection               = 0x0001
+pp_data->cap[1]->LinkUsagePage                = 0x0001
+pp_data->cap[1]->LinkUsage                    = 0x0001
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 0
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 0
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0038
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0038
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 3
+pp_data->cap[1]->NotRange.Reserved4                    = 3
+pp_data->cap[1]->NotButton.HasNull                   = 0
+pp_data->cap[1]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[1]->NotButton.LogicalMin                = -127
+pp_data->cap[1]->NotButton.LogicalMax                = 127
+pp_data->cap[1]->NotButton.PhysicalMin               = 0
+pp_data->cap[1]->NotButton.PhysicalMax               = 0
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+pp_data->cap[2]->UsagePage                    = 0x0001
+pp_data->cap[2]->ReportID                     = 0x00
+pp_data->cap[2]->BitPosition                  = 0
+pp_data->cap[2]->BitSize                      = 8
+pp_data->cap[2]->ReportCount                  = 1
+pp_data->cap[2]->BytePosition                 = 0x0003
+pp_data->cap[2]->BitCount                     = 8
+pp_data->cap[2]->BitField                     = 0x06
+pp_data->cap[2]->NextBytePosition             = 0x0004
+pp_data->cap[2]->LinkCollection               = 0x0001
+pp_data->cap[2]->LinkUsagePage                = 0x0001
+pp_data->cap[2]->LinkUsage                    = 0x0001
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 0
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 0
+pp_data->cap[2]->IsRange                      = 0
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->NotRange.Usage                        = 0x0031
+pp_data->cap[2]->NotRange.Reserved1                    = 0x0031
+pp_data->cap[2]->NotRange.StringIndex                  = 0
+pp_data->cap[2]->NotRange.Reserved2                    = 0
+pp_data->cap[2]->NotRange.DesignatorIndex              = 0
+pp_data->cap[2]->NotRange.Reserved3                    = 0
+pp_data->cap[2]->NotRange.DataIndex                    = 4
+pp_data->cap[2]->NotRange.Reserved4                    = 4
+pp_data->cap[2]->NotButton.HasNull                   = 0
+pp_data->cap[2]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[2]->NotButton.LogicalMin                = -127
+pp_data->cap[2]->NotButton.LogicalMax                = 127
+pp_data->cap[2]->NotButton.PhysicalMin               = 0
+pp_data->cap[2]->NotButton.PhysicalMax               = 0
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+pp_data->cap[3]->UsagePage                    = 0x0001
+pp_data->cap[3]->ReportID                     = 0x00
+pp_data->cap[3]->BitPosition                  = 0
+pp_data->cap[3]->BitSize                      = 8
+pp_data->cap[3]->ReportCount                  = 1
+pp_data->cap[3]->BytePosition                 = 0x0002
+pp_data->cap[3]->BitCount                     = 8
+pp_data->cap[3]->BitField                     = 0x06
+pp_data->cap[3]->NextBytePosition             = 0x0003
+pp_data->cap[3]->LinkCollection               = 0x0001
+pp_data->cap[3]->LinkUsagePage                = 0x0001
+pp_data->cap[3]->LinkUsage                    = 0x0001
+pp_data->cap[3]->IsMultipleItemsForArray      = 0
+pp_data->cap[3]->IsButtonCap                  = 0
+pp_data->cap[3]->IsPadding                    = 0
+pp_data->cap[3]->IsAbsolute                   = 0
+pp_data->cap[3]->IsRange                      = 0
+pp_data->cap[3]->IsAlias                      = 0
+pp_data->cap[3]->IsStringRange                = 0
+pp_data->cap[3]->IsDesignatorRange            = 0
+pp_data->cap[3]->Reserved1                    = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[3]->NotRange.Usage                        = 0x0030
+pp_data->cap[3]->NotRange.Reserved1                    = 0x0030
+pp_data->cap[3]->NotRange.StringIndex                  = 0
+pp_data->cap[3]->NotRange.Reserved2                    = 0
+pp_data->cap[3]->NotRange.DesignatorIndex              = 0
+pp_data->cap[3]->NotRange.Reserved3                    = 0
+pp_data->cap[3]->NotRange.DataIndex                    = 5
+pp_data->cap[3]->NotRange.Reserved4                    = 5
+pp_data->cap[3]->NotButton.HasNull                   = 0
+pp_data->cap[3]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[3]->NotButton.LogicalMin                = -127
+pp_data->cap[3]->NotButton.LogicalMax                = 127
+pp_data->cap[3]->NotButton.PhysicalMin               = 0
+pp_data->cap[3]->NotButton.PhysicalMax               = 0
+pp_data->cap[3]->Units                    = 0
+pp_data->cap[3]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0002
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 1
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 1
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[1]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[1]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[1]->Parent             = 0
+pp_data->LinkCollectionArray[1]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[1]->NextSibling        = 0
+pp_data->LinkCollectionArray[1]->FirstChild         = 0
+pp_data->LinkCollectionArray[1]->CollectionType     = 0
+pp_data->LinkCollectionArray[1]->IsAlias            = 0
+pp_data->LinkCollectionArray[1]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_C077_0002_0001_expected.rpt_desc b/src/hidapi/windows/test/data/046D_C077_0002_0001_expected.rpt_desc
new file mode 100644
index 0000000..7e144b4
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C077_0002_0001_expected.rpt_desc
@@ -0,0 +1,5 @@
+0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1, 0x00, 
+0x05, 0x09, 0x19, 0x01, 0x29, 0x03, 0x15, 0x00, 0x25, 0x01, 
+0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x05, 0x01, 0x09, 0x30, 
+0x09, 0x31, 0x09, 0x38, 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08, 
+0x95, 0x03, 0x81, 0x06, 0xC0, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C077_0002_0001_real.rpt_desc b/src/hidapi/windows/test/data/046D_C077_0002_0001_real.rpt_desc
new file mode 100644
index 0000000..7604c55
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C077_0002_0001_real.rpt_desc
@@ -0,0 +1,24 @@
+Usage Page (Generic Desktop) 05 01  
+Usage (Mouse) 09 02  
+Collection (Application) A1 01  
+    Usage (Pointer) 09 01  
+    Collection (Physical) A1 00  
+        Usage Page (Button) 05 09  
+        Usage Minimum (Button 1) 19 01  
+        Usage Maximum (Button 3) 29 03  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (1) 25 01  
+        Report Count (8) 95 08  
+        Report Size (1) 75 01  
+        Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02  
+        Usage Page (Generic Desktop) 05 01  
+        Usage (X) 09 30  
+        Usage (Y) 09 31  
+        Usage (Wheel) 09 38  
+        Logical Minimum (-127) 15 81  
+        Logical Maximum (127) 25 7F  
+        Report Size (8) 75 08  
+        Report Count (3) 95 03  
+        Input (Data,Var,Rel,NWrp,Lin,Pref,NNul,Bit) 81 06  
+    End Collection C0  
+End Collection C0 
diff --git a/src/hidapi/windows/test/data/046D_C283_0004_0001.pp_data b/src/hidapi/windows/test/data/046D_C283_0004_0001.pp_data
new file mode 100644
index 0000000..0f70d06
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C283_0004_0001.pp_data
@@ -0,0 +1,520 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xC283
+dev->manufacturer_string = "Logitech Inc."
+dev->product_string      = "WingMan Force 3D"
+dev->release_number      = 0x0106
+dev->interface_number    = -1
+dev->usage               = 0x0004
+dev->usage_page          = 0x0001
+dev->path                = "\\?\hid#vid_046d&pid_c283#7&d7fb4bf&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0004
+pp_data->UsagePage                            = 0x0001
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 8
+pp_data->caps_info[0]->NumberOfCaps       = 8
+pp_data->caps_info[0]->ReportByteLength   = 8
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 8
+pp_data->caps_info[1]->LastCap            = 9
+pp_data->caps_info[1]->NumberOfCaps       = 1
+pp_data->caps_info[1]->ReportByteLength   = 9
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 9
+pp_data->caps_info[2]->LastCap            = 9
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x03A8
+pp_data->NumberLinkCollectionNodes            = 4
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x0001
+pp_data->cap[0]->ReportID                     = 0x00
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 8
+pp_data->cap[0]->ReportCount                  = 1
+pp_data->cap[0]->BytePosition                 = 0x0002
+pp_data->cap[0]->BitCount                     = 8
+pp_data->cap[0]->BitField                     = 0x02
+pp_data->cap[0]->NextBytePosition             = 0x0003
+pp_data->cap[0]->LinkCollection               = 0x0002
+pp_data->cap[0]->LinkUsagePage                = 0x0001
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 0
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x0031
+pp_data->cap[0]->NotRange.Reserved1                    = 0x0031
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->NotButton.HasNull                   = 0
+pp_data->cap[0]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[0]->NotButton.LogicalMin                = 0
+pp_data->cap[0]->NotButton.LogicalMax                = 255
+pp_data->cap[0]->NotButton.PhysicalMin               = 0
+pp_data->cap[0]->NotButton.PhysicalMax               = 255
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0x0001
+pp_data->cap[1]->ReportID                     = 0x00
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 8
+pp_data->cap[1]->ReportCount                  = 1
+pp_data->cap[1]->BytePosition                 = 0x0001
+pp_data->cap[1]->BitCount                     = 8
+pp_data->cap[1]->BitField                     = 0x02
+pp_data->cap[1]->NextBytePosition             = 0x0002
+pp_data->cap[1]->LinkCollection               = 0x0002
+pp_data->cap[1]->LinkUsagePage                = 0x0001
+pp_data->cap[1]->LinkUsage                    = 0x0001
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 0
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0030
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0030
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 1
+pp_data->cap[1]->NotRange.Reserved4                    = 1
+pp_data->cap[1]->NotButton.HasNull                   = 0
+pp_data->cap[1]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[1]->NotButton.LogicalMin                = 0
+pp_data->cap[1]->NotButton.LogicalMax                = 255
+pp_data->cap[1]->NotButton.PhysicalMin               = 0
+pp_data->cap[1]->NotButton.PhysicalMax               = 255
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+pp_data->cap[2]->UsagePage                    = 0xFF00
+pp_data->cap[2]->ReportID                     = 0x00
+pp_data->cap[2]->BitPosition                  = 0
+pp_data->cap[2]->BitSize                      = 4
+pp_data->cap[2]->ReportCount                  = 1
+pp_data->cap[2]->BytePosition                 = 0x0003
+pp_data->cap[2]->BitCount                     = 4
+pp_data->cap[2]->BitField                     = 0x02
+pp_data->cap[2]->NextBytePosition             = 0x0004
+pp_data->cap[2]->LinkCollection               = 0x0002
+pp_data->cap[2]->LinkUsagePage                = 0x0001
+pp_data->cap[2]->LinkUsage                    = 0x0001
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 0
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 1
+pp_data->cap[2]->IsRange                      = 0
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->NotRange.Usage                        = 0x0001
+pp_data->cap[2]->NotRange.Reserved1                    = 0x0001
+pp_data->cap[2]->NotRange.StringIndex                  = 0
+pp_data->cap[2]->NotRange.Reserved2                    = 0
+pp_data->cap[2]->NotRange.DesignatorIndex              = 0
+pp_data->cap[2]->NotRange.Reserved3                    = 0
+pp_data->cap[2]->NotRange.DataIndex                    = 2
+pp_data->cap[2]->NotRange.Reserved4                    = 2
+pp_data->cap[2]->NotButton.HasNull                   = 0
+pp_data->cap[2]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[2]->NotButton.LogicalMin                = 0
+pp_data->cap[2]->NotButton.LogicalMax                = 15
+pp_data->cap[2]->NotButton.PhysicalMin               = 0
+pp_data->cap[2]->NotButton.PhysicalMax               = 255
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+pp_data->cap[3]->UsagePage                    = 0x0001
+pp_data->cap[3]->ReportID                     = 0x00
+pp_data->cap[3]->BitPosition                  = 4
+pp_data->cap[3]->BitSize                      = 4
+pp_data->cap[3]->ReportCount                  = 1
+pp_data->cap[3]->BytePosition                 = 0x0003
+pp_data->cap[3]->BitCount                     = 4
+pp_data->cap[3]->BitField                     = 0x42
+pp_data->cap[3]->NextBytePosition             = 0x0004
+pp_data->cap[3]->LinkCollection               = 0x0002
+pp_data->cap[3]->LinkUsagePage                = 0x0001
+pp_data->cap[3]->LinkUsage                    = 0x0001
+pp_data->cap[3]->IsMultipleItemsForArray      = 0
+pp_data->cap[3]->IsButtonCap                  = 0
+pp_data->cap[3]->IsPadding                    = 0
+pp_data->cap[3]->IsAbsolute                   = 1
+pp_data->cap[3]->IsRange                      = 0
+pp_data->cap[3]->IsAlias                      = 0
+pp_data->cap[3]->IsStringRange                = 0
+pp_data->cap[3]->IsDesignatorRange            = 0
+pp_data->cap[3]->Reserved1                    = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[3]->NotRange.Usage                        = 0x0039
+pp_data->cap[3]->NotRange.Reserved1                    = 0x0039
+pp_data->cap[3]->NotRange.StringIndex                  = 0
+pp_data->cap[3]->NotRange.Reserved2                    = 0
+pp_data->cap[3]->NotRange.DesignatorIndex              = 0
+pp_data->cap[3]->NotRange.Reserved3                    = 0
+pp_data->cap[3]->NotRange.DataIndex                    = 3
+pp_data->cap[3]->NotRange.Reserved4                    = 3
+pp_data->cap[3]->NotButton.HasNull                   = 1
+pp_data->cap[3]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[3]->NotButton.LogicalMin                = 0
+pp_data->cap[3]->NotButton.LogicalMax                = 7
+pp_data->cap[3]->NotButton.PhysicalMin               = 0
+pp_data->cap[3]->NotButton.PhysicalMax               = 315
+pp_data->cap[3]->Units                    = 20
+pp_data->cap[3]->UnitsExp                 = 0
+
+pp_data->cap[4]->UsagePage                    = 0x0001
+pp_data->cap[4]->ReportID                     = 0x00
+pp_data->cap[4]->BitPosition                  = 0
+pp_data->cap[4]->BitSize                      = 8
+pp_data->cap[4]->ReportCount                  = 1
+pp_data->cap[4]->BytePosition                 = 0x0004
+pp_data->cap[4]->BitCount                     = 8
+pp_data->cap[4]->BitField                     = 0x02
+pp_data->cap[4]->NextBytePosition             = 0x0005
+pp_data->cap[4]->LinkCollection               = 0x0002
+pp_data->cap[4]->LinkUsagePage                = 0x0001
+pp_data->cap[4]->LinkUsage                    = 0x0001
+pp_data->cap[4]->IsMultipleItemsForArray      = 0
+pp_data->cap[4]->IsButtonCap                  = 0
+pp_data->cap[4]->IsPadding                    = 0
+pp_data->cap[4]->IsAbsolute                   = 1
+pp_data->cap[4]->IsRange                      = 0
+pp_data->cap[4]->IsAlias                      = 0
+pp_data->cap[4]->IsStringRange                = 0
+pp_data->cap[4]->IsDesignatorRange            = 0
+pp_data->cap[4]->Reserved1                    = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[4]->NotRange.Usage                        = 0x0035
+pp_data->cap[4]->NotRange.Reserved1                    = 0x0035
+pp_data->cap[4]->NotRange.StringIndex                  = 0
+pp_data->cap[4]->NotRange.Reserved2                    = 0
+pp_data->cap[4]->NotRange.DesignatorIndex              = 0
+pp_data->cap[4]->NotRange.Reserved3                    = 0
+pp_data->cap[4]->NotRange.DataIndex                    = 4
+pp_data->cap[4]->NotRange.Reserved4                    = 4
+pp_data->cap[4]->NotButton.HasNull                   = 0
+pp_data->cap[4]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[4]->NotButton.LogicalMin                = 0
+pp_data->cap[4]->NotButton.LogicalMax                = 255
+pp_data->cap[4]->NotButton.PhysicalMin               = 0
+pp_data->cap[4]->NotButton.PhysicalMax               = 255
+pp_data->cap[4]->Units                    = 20
+pp_data->cap[4]->UnitsExp                 = 0
+
+pp_data->cap[5]->UsagePage                    = 0x0009
+pp_data->cap[5]->ReportID                     = 0x00
+pp_data->cap[5]->BitPosition                  = 0
+pp_data->cap[5]->BitSize                      = 1
+pp_data->cap[5]->ReportCount                  = 7
+pp_data->cap[5]->BytePosition                 = 0x0005
+pp_data->cap[5]->BitCount                     = 7
+pp_data->cap[5]->BitField                     = 0x02
+pp_data->cap[5]->NextBytePosition             = 0x0006
+pp_data->cap[5]->LinkCollection               = 0x0001
+pp_data->cap[5]->LinkUsagePage                = 0x0001
+pp_data->cap[5]->LinkUsage                    = 0x0000
+pp_data->cap[5]->IsMultipleItemsForArray      = 0
+pp_data->cap[5]->IsButtonCap                  = 1
+pp_data->cap[5]->IsPadding                    = 0
+pp_data->cap[5]->IsAbsolute                   = 1
+pp_data->cap[5]->IsRange                      = 1
+pp_data->cap[5]->IsAlias                      = 0
+pp_data->cap[5]->IsStringRange                = 0
+pp_data->cap[5]->IsDesignatorRange            = 0
+pp_data->cap[5]->Reserved1                    = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[5]->Range.UsageMin                     = 0x0001
+pp_data->cap[5]->Range.UsageMax                     = 0x0007
+pp_data->cap[5]->Range.StringMin                    = 0
+pp_data->cap[5]->Range.StringMax                    = 0
+pp_data->cap[5]->Range.DesignatorMin                = 0
+pp_data->cap[5]->Range.DesignatorMax                = 0
+pp_data->cap[5]->Range.DataIndexMin                 = 5
+pp_data->cap[5]->Range.DataIndexMax                 = 11
+pp_data->cap[5]->Button.LogicalMin                   = 0
+pp_data->cap[5]->Button.LogicalMax                   = 0
+pp_data->cap[5]->Units                    = 0
+pp_data->cap[5]->UnitsExp                 = 0
+
+pp_data->cap[6]->UsagePage                    = 0x0001
+pp_data->cap[6]->ReportID                     = 0x00
+pp_data->cap[6]->BitPosition                  = 0
+pp_data->cap[6]->BitSize                      = 8
+pp_data->cap[6]->ReportCount                  = 1
+pp_data->cap[6]->BytePosition                 = 0x0006
+pp_data->cap[6]->BitCount                     = 8
+pp_data->cap[6]->BitField                     = 0x02
+pp_data->cap[6]->NextBytePosition             = 0x0007
+pp_data->cap[6]->LinkCollection               = 0x0001
+pp_data->cap[6]->LinkUsagePage                = 0x0001
+pp_data->cap[6]->LinkUsage                    = 0x0000
+pp_data->cap[6]->IsMultipleItemsForArray      = 0
+pp_data->cap[6]->IsButtonCap                  = 0
+pp_data->cap[6]->IsPadding                    = 0
+pp_data->cap[6]->IsAbsolute                   = 1
+pp_data->cap[6]->IsRange                      = 0
+pp_data->cap[6]->IsAlias                      = 0
+pp_data->cap[6]->IsStringRange                = 0
+pp_data->cap[6]->IsDesignatorRange            = 0
+pp_data->cap[6]->Reserved1                    = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[6]->NotRange.Usage                        = 0x0036
+pp_data->cap[6]->NotRange.Reserved1                    = 0x0036
+pp_data->cap[6]->NotRange.StringIndex                  = 0
+pp_data->cap[6]->NotRange.Reserved2                    = 0
+pp_data->cap[6]->NotRange.DesignatorIndex              = 0
+pp_data->cap[6]->NotRange.Reserved3                    = 0
+pp_data->cap[6]->NotRange.DataIndex                    = 12
+pp_data->cap[6]->NotRange.Reserved4                    = 12
+pp_data->cap[6]->NotButton.HasNull                   = 0
+pp_data->cap[6]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[6]->NotButton.LogicalMin                = 0
+pp_data->cap[6]->NotButton.LogicalMax                = 255
+pp_data->cap[6]->NotButton.PhysicalMin               = 0
+pp_data->cap[6]->NotButton.PhysicalMax               = 255
+pp_data->cap[6]->Units                    = 0
+pp_data->cap[6]->UnitsExp                 = 0
+
+pp_data->cap[7]->UsagePage                    = 0xFF00
+pp_data->cap[7]->ReportID                     = 0x00
+pp_data->cap[7]->BitPosition                  = 0
+pp_data->cap[7]->BitSize                      = 8
+pp_data->cap[7]->ReportCount                  = 1
+pp_data->cap[7]->BytePosition                 = 0x0007
+pp_data->cap[7]->BitCount                     = 8
+pp_data->cap[7]->BitField                     = 0x02
+pp_data->cap[7]->NextBytePosition             = 0x0008
+pp_data->cap[7]->LinkCollection               = 0x0001
+pp_data->cap[7]->LinkUsagePage                = 0x0001
+pp_data->cap[7]->LinkUsage                    = 0x0000
+pp_data->cap[7]->IsMultipleItemsForArray      = 0
+pp_data->cap[7]->IsButtonCap                  = 0
+pp_data->cap[7]->IsPadding                    = 0
+pp_data->cap[7]->IsAbsolute                   = 1
+pp_data->cap[7]->IsRange                      = 0
+pp_data->cap[7]->IsAlias                      = 0
+pp_data->cap[7]->IsStringRange                = 0
+pp_data->cap[7]->IsDesignatorRange            = 0
+pp_data->cap[7]->Reserved1                    = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[7]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[7]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[7]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[7]->NotRange.Usage                        = 0x0001
+pp_data->cap[7]->NotRange.Reserved1                    = 0x0001
+pp_data->cap[7]->NotRange.StringIndex                  = 0
+pp_data->cap[7]->NotRange.Reserved2                    = 0
+pp_data->cap[7]->NotRange.DesignatorIndex              = 0
+pp_data->cap[7]->NotRange.Reserved3                    = 0
+pp_data->cap[7]->NotRange.DataIndex                    = 13
+pp_data->cap[7]->NotRange.Reserved4                    = 13
+pp_data->cap[7]->NotButton.HasNull                   = 0
+pp_data->cap[7]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[7]->NotButton.LogicalMin                = 0
+pp_data->cap[7]->NotButton.LogicalMax                = 255
+pp_data->cap[7]->NotButton.PhysicalMin               = 0
+pp_data->cap[7]->NotButton.PhysicalMax               = 255
+pp_data->cap[7]->Units                    = 0
+pp_data->cap[7]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[8]->UsagePage                    = 0xFF00
+pp_data->cap[8]->ReportID                     = 0x00
+pp_data->cap[8]->BitPosition                  = 0
+pp_data->cap[8]->BitSize                      = 8
+pp_data->cap[8]->ReportCount                  = 8
+pp_data->cap[8]->BytePosition                 = 0x0001
+pp_data->cap[8]->BitCount                     = 64
+pp_data->cap[8]->BitField                     = 0x02
+pp_data->cap[8]->NextBytePosition             = 0x0009
+pp_data->cap[8]->LinkCollection               = 0x0003
+pp_data->cap[8]->LinkUsagePage                = 0xFF00
+pp_data->cap[8]->LinkUsage                    = 0x0000
+pp_data->cap[8]->IsMultipleItemsForArray      = 0
+pp_data->cap[8]->IsButtonCap                  = 0
+pp_data->cap[8]->IsPadding                    = 0
+pp_data->cap[8]->IsAbsolute                   = 1
+pp_data->cap[8]->IsRange                      = 0
+pp_data->cap[8]->IsAlias                      = 0
+pp_data->cap[8]->IsStringRange                = 0
+pp_data->cap[8]->IsDesignatorRange            = 0
+pp_data->cap[8]->Reserved1                    = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[8]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[8]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[8]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[8]->NotRange.Usage                        = 0x0002
+pp_data->cap[8]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[8]->NotRange.StringIndex                  = 0
+pp_data->cap[8]->NotRange.Reserved2                    = 0
+pp_data->cap[8]->NotRange.DesignatorIndex              = 0
+pp_data->cap[8]->NotRange.Reserved3                    = 0
+pp_data->cap[8]->NotRange.DataIndex                    = 0
+pp_data->cap[8]->NotRange.Reserved4                    = 0
+pp_data->cap[8]->NotButton.HasNull                   = 0
+pp_data->cap[8]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[8]->NotButton.LogicalMin                = 0
+pp_data->cap[8]->NotButton.LogicalMax                = 255
+pp_data->cap[8]->NotButton.PhysicalMin               = 0
+pp_data->cap[8]->NotButton.PhysicalMax               = 255
+pp_data->cap[8]->Units                    = 0
+pp_data->cap[8]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0004
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 2
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 3
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[1]->LinkUsage          = 0x0000
+pp_data->LinkCollectionArray[1]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[1]->Parent             = 0
+pp_data->LinkCollectionArray[1]->NumberOfChildren   = 1
+pp_data->LinkCollectionArray[1]->NextSibling        = 0
+pp_data->LinkCollectionArray[1]->FirstChild         = 2
+pp_data->LinkCollectionArray[1]->CollectionType     = 2
+pp_data->LinkCollectionArray[1]->IsAlias            = 0
+pp_data->LinkCollectionArray[1]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[2]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[2]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[2]->Parent             = 1
+pp_data->LinkCollectionArray[2]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[2]->NextSibling        = 0
+pp_data->LinkCollectionArray[2]->FirstChild         = 0
+pp_data->LinkCollectionArray[2]->CollectionType     = 0
+pp_data->LinkCollectionArray[2]->IsAlias            = 0
+pp_data->LinkCollectionArray[2]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[3]->LinkUsage          = 0x0000
+pp_data->LinkCollectionArray[3]->LinkUsagePage      = 0xFF00
+pp_data->LinkCollectionArray[3]->Parent             = 0
+pp_data->LinkCollectionArray[3]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[3]->NextSibling        = 1
+pp_data->LinkCollectionArray[3]->FirstChild         = 0
+pp_data->LinkCollectionArray[3]->CollectionType     = 2
+pp_data->LinkCollectionArray[3]->IsAlias            = 0
+pp_data->LinkCollectionArray[3]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_C283_0004_0001_expected.rpt_desc b/src/hidapi/windows/test/data/046D_C283_0004_0001_expected.rpt_desc
new file mode 100644
index 0000000..fca719a
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C283_0004_0001_expected.rpt_desc
@@ -0,0 +1,18 @@
+0x05, 0x01, 0x09, 0x04, 0xA1, 0x01, 0x09, 0x00, 0xA1, 0x02, 
+0x09, 0x01, 0xA1, 0x00, 0x09, 0x30, 0x09, 0x31, 0x15, 0x00, 
+0x26, 0xFF, 0x00, 0x35, 0x00, 0x46, 0xFF, 0x00, 0x75, 0x08, 
+0x95, 0x02, 0x81, 0x02, 0x06, 0x00, 0xFF, 0x09, 0x01, 0x15, 
+0x00, 0x25, 0x0F, 0x75, 0x04, 0x95, 0x01, 0x81, 0x02, 0x05, 
+0x01, 0x09, 0x39, 0x15, 0x00, 0x25, 0x07, 0x35, 0x00, 0x46, 
+0x3B, 0x01, 0x65, 0x14, 0x75, 0x04, 0x95, 0x01, 0x81, 0x42, 
+0x09, 0x35, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x35, 0x00, 0x46, 
+0xFF, 0x00, 0x75, 0x08, 0x95, 0x01, 0x81, 0x02, 0xC0, 0x05, 
+0x09, 0x19, 0x01, 0x29, 0x07, 0x15, 0x00, 0x25, 0x01, 0x75, 
+0x01, 0x95, 0x07, 0x45, 0x00, 0x65, 0x00, 0x81, 0x02, 0x75, 
+0x01, 0x95, 0x01, 0x81, 0x03, 0x05, 0x01, 0x09, 0x36, 0x15, 
+0x00, 0x26, 0xFF, 0x00, 0x35, 0x00, 0x46, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x01, 0x81, 0x02, 0x06, 0x00, 0xFF, 0x09, 0x01, 
+0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x01, 0x81, 
+0x02, 0xC0, 0x09, 0x00, 0xA1, 0x02, 0x09, 0x02, 0x15, 0x00, 
+0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x08, 0x91, 0x02, 0xC0, 
+0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C283_0004_0001_real.rpt_desc b/src/hidapi/windows/test/data/046D_C283_0004_0001_real.rpt_desc
new file mode 100644
index 0000000..fca719a
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C283_0004_0001_real.rpt_desc
@@ -0,0 +1,18 @@
+0x05, 0x01, 0x09, 0x04, 0xA1, 0x01, 0x09, 0x00, 0xA1, 0x02, 
+0x09, 0x01, 0xA1, 0x00, 0x09, 0x30, 0x09, 0x31, 0x15, 0x00, 
+0x26, 0xFF, 0x00, 0x35, 0x00, 0x46, 0xFF, 0x00, 0x75, 0x08, 
+0x95, 0x02, 0x81, 0x02, 0x06, 0x00, 0xFF, 0x09, 0x01, 0x15, 
+0x00, 0x25, 0x0F, 0x75, 0x04, 0x95, 0x01, 0x81, 0x02, 0x05, 
+0x01, 0x09, 0x39, 0x15, 0x00, 0x25, 0x07, 0x35, 0x00, 0x46, 
+0x3B, 0x01, 0x65, 0x14, 0x75, 0x04, 0x95, 0x01, 0x81, 0x42, 
+0x09, 0x35, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x35, 0x00, 0x46, 
+0xFF, 0x00, 0x75, 0x08, 0x95, 0x01, 0x81, 0x02, 0xC0, 0x05, 
+0x09, 0x19, 0x01, 0x29, 0x07, 0x15, 0x00, 0x25, 0x01, 0x75, 
+0x01, 0x95, 0x07, 0x45, 0x00, 0x65, 0x00, 0x81, 0x02, 0x75, 
+0x01, 0x95, 0x01, 0x81, 0x03, 0x05, 0x01, 0x09, 0x36, 0x15, 
+0x00, 0x26, 0xFF, 0x00, 0x35, 0x00, 0x46, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x01, 0x81, 0x02, 0x06, 0x00, 0xFF, 0x09, 0x01, 
+0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x01, 0x81, 
+0x02, 0xC0, 0x09, 0x00, 0xA1, 0x02, 0x09, 0x02, 0x15, 0x00, 
+0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x08, 0x91, 0x02, 0xC0, 
+0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C52F_0001_000C.pp_data b/src/hidapi/windows/test/data/046D_C52F_0001_000C.pp_data
new file mode 100644
index 0000000..7f6b369
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C52F_0001_000C.pp_data
@@ -0,0 +1,93 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xC52F
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "USB Receiver"
+dev->release_number      = 0x2200
+dev->interface_number    = 1
+dev->usage               = 0x0001
+dev->usage_page          = 0x000C
+dev->path                = "\\?\hid#vid_046d&pid_c52f&mi_01&col01#8&28ca146b&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0001
+pp_data->UsagePage                            = 0x000C
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 1
+pp_data->caps_info[0]->NumberOfCaps       = 1
+pp_data->caps_info[0]->ReportByteLength   = 5
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 1
+pp_data->caps_info[1]->LastCap            = 1
+pp_data->caps_info[1]->NumberOfCaps       = 0
+pp_data->caps_info[1]->ReportByteLength   = 0
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 1
+pp_data->caps_info[2]->LastCap            = 1
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x0068
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x000C
+pp_data->cap[0]->ReportID                     = 0x03
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 16
+pp_data->cap[0]->ReportCount                  = 2
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 32
+pp_data->cap[0]->BitField                     = 0x00
+pp_data->cap[0]->NextBytePosition             = 0x0005
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0x000C
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 1
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->Range.UsageMin                     = 0x0001
+pp_data->cap[0]->Range.UsageMax                     = 0x028C
+pp_data->cap[0]->Range.StringMin                    = 0
+pp_data->cap[0]->Range.StringMax                    = 0
+pp_data->cap[0]->Range.DesignatorMin                = 0
+pp_data->cap[0]->Range.DesignatorMax                = 0
+pp_data->cap[0]->Range.DataIndexMin                 = 0
+pp_data->cap[0]->Range.DataIndexMax                 = 651
+pp_data->cap[0]->Button.LogicalMin                   = 1
+pp_data->cap[0]->Button.LogicalMax                   = 652
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x000C
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_C52F_0001_000C_expected.rpt_desc b/src/hidapi/windows/test/data/046D_C52F_0001_000C_expected.rpt_desc
new file mode 100644
index 0000000..85953ae
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C52F_0001_000C_expected.rpt_desc
@@ -0,0 +1,3 @@
+0x05, 0x0C, 0x09, 0x01, 0xA1, 0x01, 0x85, 0x03, 0x19, 0x01, 
+0x2A, 0x8C, 0x02, 0x15, 0x01, 0x26, 0x8C, 0x02, 0x75, 0x10, 
+0x95, 0x02, 0x81, 0x00, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C52F_0001_000C_real.rpt_desc b/src/hidapi/windows/test/data/046D_C52F_0001_000C_real.rpt_desc
new file mode 100644
index 0000000..280e58f
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C52F_0001_000C_real.rpt_desc
@@ -0,0 +1,12 @@
+Usage Page (Consumer Devices) 05 0C  
+Usage (Consumer Control) 09 01  
+Collection (Application) A1 01  
+    Report ID (3) 85 03  
+    Report Size (16) 75 10  
+    Report Count (2) 95 02  
+    Logical Minimum (1) 15 01  
+    Logical Maximum (652) 26 8C 02  
+    Usage Minimum (Consumer Control) 19 01  
+    Usage Maximum (AC Send) 2A 8C 02  
+    Input (Data,Ary,Abs) 81 00  
+End Collection C0  
diff --git a/src/hidapi/windows/test/data/046D_C52F_0001_FF00.pp_data b/src/hidapi/windows/test/data/046D_C52F_0001_FF00.pp_data
new file mode 100644
index 0000000..5e8ece1
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C52F_0001_FF00.pp_data
@@ -0,0 +1,139 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xC52F
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "USB Receiver"
+dev->release_number      = 0x2200
+dev->interface_number    = 1
+dev->usage               = 0x0001
+dev->usage_page          = 0xFF00
+dev->path                = "\\?\hid#vid_046d&pid_c52f&mi_01&col02#8&28ca146b&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0001
+pp_data->UsagePage                            = 0xFF00
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 1
+pp_data->caps_info[0]->NumberOfCaps       = 1
+pp_data->caps_info[0]->ReportByteLength   = 7
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 1
+pp_data->caps_info[1]->LastCap            = 2
+pp_data->caps_info[1]->NumberOfCaps       = 1
+pp_data->caps_info[1]->ReportByteLength   = 7
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 2
+pp_data->caps_info[2]->LastCap            = 2
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x00D0
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0xFF00
+pp_data->cap[0]->ReportID                     = 0x10
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 8
+pp_data->cap[0]->ReportCount                  = 6
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 48
+pp_data->cap[0]->BitField                     = 0x00
+pp_data->cap[0]->NextBytePosition             = 0x0007
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0xFF00
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x0001
+pp_data->cap[0]->NotRange.Reserved1                    = 0x0001
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 255
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[1]->UsagePage                    = 0xFF00
+pp_data->cap[1]->ReportID                     = 0x10
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 8
+pp_data->cap[1]->ReportCount                  = 6
+pp_data->cap[1]->BytePosition                 = 0x0001
+pp_data->cap[1]->BitCount                     = 48
+pp_data->cap[1]->BitField                     = 0x00
+pp_data->cap[1]->NextBytePosition             = 0x0007
+pp_data->cap[1]->LinkCollection               = 0x0000
+pp_data->cap[1]->LinkUsagePage                = 0xFF00
+pp_data->cap[1]->LinkUsage                    = 0x0001
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 1
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0001
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0001
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 0
+pp_data->cap[1]->NotRange.Reserved4                    = 0
+pp_data->cap[1]->Button.LogicalMin                   = 0
+pp_data->cap[1]->Button.LogicalMax                   = 255
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0xFF00
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_C52F_0001_FF00_expected.rpt_desc b/src/hidapi/windows/test/data/046D_C52F_0001_FF00_expected.rpt_desc
new file mode 100644
index 0000000..812bd2a
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C52F_0001_FF00_expected.rpt_desc
@@ -0,0 +1,4 @@
+0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x85, 0x10, 0x09, 
+0x01, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x06, 
+0x81, 0x00, 0x09, 0x01, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x06, 0x91, 0x00, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C52F_0001_FF00_real.rpt_desc b/src/hidapi/windows/test/data/046D_C52F_0001_FF00_real.rpt_desc
new file mode 100644
index 0000000..0db6898
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C52F_0001_FF00_real.rpt_desc
@@ -0,0 +1,13 @@
+Usage Page (Vendor-Defined 1) 06 00 FF  
+Usage (Vendor-Defined 1) 09 01  
+Collection (Application) A1 01  
+    Report ID (16) 85 10  
+    Report Size (8) 75 08  
+    Report Count (6) 95 06  
+    Logical Minimum (0) 15 00  
+    Logical Maximum (255) 26 FF 00  
+    Usage (Vendor-Defined 1) 09 01  
+    Input (Data,Ary,Abs) 81 00  
+    Usage (Vendor-Defined 1) 09 01  
+    Output (Data,Ary,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 00  
+End Collection C0 
diff --git a/src/hidapi/windows/test/data/046D_C52F_0002_0001.pp_data b/src/hidapi/windows/test/data/046D_C52F_0002_0001.pp_data
new file mode 100644
index 0000000..d90e666
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C52F_0002_0001.pp_data
@@ -0,0 +1,302 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xC52F
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "USB Receiver"
+dev->release_number      = 0x2200
+dev->interface_number    = 0
+dev->usage               = 0x0002
+dev->usage_page          = 0x0001
+dev->path                = "\\?\hid#vid_046d&pid_c52f&mi_00#8&1599f82d&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0002
+pp_data->UsagePage                            = 0x0001
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 5
+pp_data->caps_info[0]->NumberOfCaps       = 5
+pp_data->caps_info[0]->ReportByteLength   = 9
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 5
+pp_data->caps_info[1]->LastCap            = 5
+pp_data->caps_info[1]->NumberOfCaps       = 0
+pp_data->caps_info[1]->ReportByteLength   = 0
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 5
+pp_data->caps_info[2]->LastCap            = 5
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x0208
+pp_data->NumberLinkCollectionNodes            = 2
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x0009
+pp_data->cap[0]->ReportID                     = 0x00
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 1
+pp_data->cap[0]->ReportCount                  = 16
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 16
+pp_data->cap[0]->BitField                     = 0x02
+pp_data->cap[0]->NextBytePosition             = 0x0003
+pp_data->cap[0]->LinkCollection               = 0x0001
+pp_data->cap[0]->LinkUsagePage                = 0x0001
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 1
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->Range.UsageMin                     = 0x0001
+pp_data->cap[0]->Range.UsageMax                     = 0x0010
+pp_data->cap[0]->Range.StringMin                    = 0
+pp_data->cap[0]->Range.StringMax                    = 0
+pp_data->cap[0]->Range.DesignatorMin                = 0
+pp_data->cap[0]->Range.DesignatorMax                = 0
+pp_data->cap[0]->Range.DataIndexMin                 = 0
+pp_data->cap[0]->Range.DataIndexMax                 = 15
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 0
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0x0001
+pp_data->cap[1]->ReportID                     = 0x00
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 16
+pp_data->cap[1]->ReportCount                  = 1
+pp_data->cap[1]->BytePosition                 = 0x0005
+pp_data->cap[1]->BitCount                     = 16
+pp_data->cap[1]->BitField                     = 0x06
+pp_data->cap[1]->NextBytePosition             = 0x0007
+pp_data->cap[1]->LinkCollection               = 0x0001
+pp_data->cap[1]->LinkUsagePage                = 0x0001
+pp_data->cap[1]->LinkUsage                    = 0x0001
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 0
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 0
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0031
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0031
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 16
+pp_data->cap[1]->NotRange.Reserved4                    = 16
+pp_data->cap[1]->NotButton.HasNull                   = 0
+pp_data->cap[1]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[1]->NotButton.LogicalMin                = -32767
+pp_data->cap[1]->NotButton.LogicalMax                = 32767
+pp_data->cap[1]->NotButton.PhysicalMin               = 0
+pp_data->cap[1]->NotButton.PhysicalMax               = 0
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+pp_data->cap[2]->UsagePage                    = 0x0001
+pp_data->cap[2]->ReportID                     = 0x00
+pp_data->cap[2]->BitPosition                  = 0
+pp_data->cap[2]->BitSize                      = 16
+pp_data->cap[2]->ReportCount                  = 1
+pp_data->cap[2]->BytePosition                 = 0x0003
+pp_data->cap[2]->BitCount                     = 16
+pp_data->cap[2]->BitField                     = 0x06
+pp_data->cap[2]->NextBytePosition             = 0x0005
+pp_data->cap[2]->LinkCollection               = 0x0001
+pp_data->cap[2]->LinkUsagePage                = 0x0001
+pp_data->cap[2]->LinkUsage                    = 0x0001
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 0
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 0
+pp_data->cap[2]->IsRange                      = 0
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->NotRange.Usage                        = 0x0030
+pp_data->cap[2]->NotRange.Reserved1                    = 0x0030
+pp_data->cap[2]->NotRange.StringIndex                  = 0
+pp_data->cap[2]->NotRange.Reserved2                    = 0
+pp_data->cap[2]->NotRange.DesignatorIndex              = 0
+pp_data->cap[2]->NotRange.Reserved3                    = 0
+pp_data->cap[2]->NotRange.DataIndex                    = 17
+pp_data->cap[2]->NotRange.Reserved4                    = 17
+pp_data->cap[2]->NotButton.HasNull                   = 0
+pp_data->cap[2]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[2]->NotButton.LogicalMin                = -32767
+pp_data->cap[2]->NotButton.LogicalMax                = 32767
+pp_data->cap[2]->NotButton.PhysicalMin               = 0
+pp_data->cap[2]->NotButton.PhysicalMax               = 0
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+pp_data->cap[3]->UsagePage                    = 0x0001
+pp_data->cap[3]->ReportID                     = 0x00
+pp_data->cap[3]->BitPosition                  = 0
+pp_data->cap[3]->BitSize                      = 8
+pp_data->cap[3]->ReportCount                  = 1
+pp_data->cap[3]->BytePosition                 = 0x0007
+pp_data->cap[3]->BitCount                     = 8
+pp_data->cap[3]->BitField                     = 0x06
+pp_data->cap[3]->NextBytePosition             = 0x0008
+pp_data->cap[3]->LinkCollection               = 0x0001
+pp_data->cap[3]->LinkUsagePage                = 0x0001
+pp_data->cap[3]->LinkUsage                    = 0x0001
+pp_data->cap[3]->IsMultipleItemsForArray      = 0
+pp_data->cap[3]->IsButtonCap                  = 0
+pp_data->cap[3]->IsPadding                    = 0
+pp_data->cap[3]->IsAbsolute                   = 0
+pp_data->cap[3]->IsRange                      = 0
+pp_data->cap[3]->IsAlias                      = 0
+pp_data->cap[3]->IsStringRange                = 0
+pp_data->cap[3]->IsDesignatorRange            = 0
+pp_data->cap[3]->Reserved1                    = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[3]->NotRange.Usage                        = 0x0038
+pp_data->cap[3]->NotRange.Reserved1                    = 0x0038
+pp_data->cap[3]->NotRange.StringIndex                  = 0
+pp_data->cap[3]->NotRange.Reserved2                    = 0
+pp_data->cap[3]->NotRange.DesignatorIndex              = 0
+pp_data->cap[3]->NotRange.Reserved3                    = 0
+pp_data->cap[3]->NotRange.DataIndex                    = 18
+pp_data->cap[3]->NotRange.Reserved4                    = 18
+pp_data->cap[3]->NotButton.HasNull                   = 0
+pp_data->cap[3]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[3]->NotButton.LogicalMin                = -127
+pp_data->cap[3]->NotButton.LogicalMax                = 127
+pp_data->cap[3]->NotButton.PhysicalMin               = 0
+pp_data->cap[3]->NotButton.PhysicalMax               = 0
+pp_data->cap[3]->Units                    = 0
+pp_data->cap[3]->UnitsExp                 = 0
+
+pp_data->cap[4]->UsagePage                    = 0x000C
+pp_data->cap[4]->ReportID                     = 0x00
+pp_data->cap[4]->BitPosition                  = 0
+pp_data->cap[4]->BitSize                      = 8
+pp_data->cap[4]->ReportCount                  = 1
+pp_data->cap[4]->BytePosition                 = 0x0008
+pp_data->cap[4]->BitCount                     = 8
+pp_data->cap[4]->BitField                     = 0x06
+pp_data->cap[4]->NextBytePosition             = 0x0009
+pp_data->cap[4]->LinkCollection               = 0x0001
+pp_data->cap[4]->LinkUsagePage                = 0x0001
+pp_data->cap[4]->LinkUsage                    = 0x0001
+pp_data->cap[4]->IsMultipleItemsForArray      = 0
+pp_data->cap[4]->IsButtonCap                  = 0
+pp_data->cap[4]->IsPadding                    = 0
+pp_data->cap[4]->IsAbsolute                   = 0
+pp_data->cap[4]->IsRange                      = 0
+pp_data->cap[4]->IsAlias                      = 0
+pp_data->cap[4]->IsStringRange                = 0
+pp_data->cap[4]->IsDesignatorRange            = 0
+pp_data->cap[4]->Reserved1                    = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[4]->NotRange.Usage                        = 0x0238
+pp_data->cap[4]->NotRange.Reserved1                    = 0x0238
+pp_data->cap[4]->NotRange.StringIndex                  = 0
+pp_data->cap[4]->NotRange.Reserved2                    = 0
+pp_data->cap[4]->NotRange.DesignatorIndex              = 0
+pp_data->cap[4]->NotRange.Reserved3                    = 0
+pp_data->cap[4]->NotRange.DataIndex                    = 19
+pp_data->cap[4]->NotRange.Reserved4                    = 19
+pp_data->cap[4]->NotButton.HasNull                   = 0
+pp_data->cap[4]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[4]->NotButton.LogicalMin                = -127
+pp_data->cap[4]->NotButton.LogicalMax                = 127
+pp_data->cap[4]->NotButton.PhysicalMin               = 0
+pp_data->cap[4]->NotButton.PhysicalMax               = 0
+pp_data->cap[4]->Units                    = 0
+pp_data->cap[4]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0002
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 1
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 1
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[1]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[1]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[1]->Parent             = 0
+pp_data->LinkCollectionArray[1]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[1]->NextSibling        = 0
+pp_data->LinkCollectionArray[1]->FirstChild         = 0
+pp_data->LinkCollectionArray[1]->CollectionType     = 0
+pp_data->LinkCollectionArray[1]->IsAlias            = 0
+pp_data->LinkCollectionArray[1]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_C52F_0002_0001_expected.rpt_desc b/src/hidapi/windows/test/data/046D_C52F_0002_0001_expected.rpt_desc
new file mode 100644
index 0000000..128c411
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C52F_0002_0001_expected.rpt_desc
@@ -0,0 +1,8 @@
+0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1, 0x00, 
+0x05, 0x09, 0x19, 0x01, 0x29, 0x10, 0x15, 0x00, 0x25, 0x01, 
+0x75, 0x01, 0x95, 0x10, 0x81, 0x02, 0x05, 0x01, 0x09, 0x30, 
+0x09, 0x31, 0x16, 0x01, 0x80, 0x26, 0xFF, 0x7F, 0x75, 0x10, 
+0x95, 0x02, 0x81, 0x06, 0x09, 0x38, 0x15, 0x81, 0x25, 0x7F, 
+0x75, 0x08, 0x95, 0x01, 0x81, 0x06, 0x05, 0x0C, 0x0A, 0x38, 
+0x02, 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08, 0x95, 0x01, 0x81, 
+0x06, 0xC0, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C52F_0002_0001_real.rpt_desc b/src/hidapi/windows/test/data/046D_C52F_0002_0001_real.rpt_desc
new file mode 100644
index 0000000..9c0521d
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C52F_0002_0001_real.rpt_desc
@@ -0,0 +1,33 @@
+Usage Page (Generic Desktop) 05 01  
+Usage (Mouse) 09 02  
+Collection (Application) A1 01  
+    Usage (Pointer) 09 01  
+    Collection (Physical) A1 00  
+        Usage Page (Button) 05 09  
+        Usage Minimum (Button 1) 19 01  
+        Usage Maximum (Button 16) 29 10  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (1) 25 01  
+        Report Count (16) 95 10  
+        Report Size (1) 75 01  
+        Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02  
+        Usage Page (Generic Desktop) 05 01  
+        Logical Minimum (-32767) 16 01 80  
+        Logical Maximum (32767) 26 FF 7F  
+        Report Size (16) 75 10  
+        Report Count (2) 95 02  
+        Usage (X) 09 30  
+        Usage (Y) 09 31  
+        Input (Data,Var,Rel,NWrp,Lin,Pref,NNul,Bit) 81 06  
+        Logical Minimum (-127) 15 81  
+        Logical Maximum (127) 25 7F  
+        Report Size (8) 75 08  
+        Report Count (1) 95 01  
+        Usage (Wheel) 09 38  
+        Input (Data,Var,Rel,NWrp,Lin,Pref,NNul,Bit) 81 06  
+        Usage Page (Consumer Devices) 05 0C  
+        Usage (AC Pan) 0A 38 02  
+        Report Count (1) 95 01  
+        Input (Data,Var,Rel,NWrp,Lin,Pref,NNul,Bit) 81 06  
+    End Collection C0  
+End Collection C0  
diff --git a/src/hidapi/windows/test/data/046D_C52F_0002_FF00.pp_data b/src/hidapi/windows/test/data/046D_C52F_0002_FF00.pp_data
new file mode 100644
index 0000000..09a3689
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C52F_0002_FF00.pp_data
@@ -0,0 +1,139 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xC52F
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "USB Receiver"
+dev->release_number      = 0x2200
+dev->interface_number    = 1
+dev->usage               = 0x0002
+dev->usage_page          = 0xFF00
+dev->path                = "\\?\hid#vid_046d&pid_c52f&mi_01&col03#8&28ca146b&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0002
+pp_data->UsagePage                            = 0xFF00
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 1
+pp_data->caps_info[0]->NumberOfCaps       = 1
+pp_data->caps_info[0]->ReportByteLength   = 20
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 1
+pp_data->caps_info[1]->LastCap            = 2
+pp_data->caps_info[1]->NumberOfCaps       = 1
+pp_data->caps_info[1]->ReportByteLength   = 20
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 2
+pp_data->caps_info[2]->LastCap            = 2
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x00D0
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0xFF00
+pp_data->cap[0]->ReportID                     = 0x11
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 8
+pp_data->cap[0]->ReportCount                  = 19
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 152
+pp_data->cap[0]->BitField                     = 0x00
+pp_data->cap[0]->NextBytePosition             = 0x0014
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0xFF00
+pp_data->cap[0]->LinkUsage                    = 0x0002
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x0002
+pp_data->cap[0]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 255
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[1]->UsagePage                    = 0xFF00
+pp_data->cap[1]->ReportID                     = 0x11
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 8
+pp_data->cap[1]->ReportCount                  = 19
+pp_data->cap[1]->BytePosition                 = 0x0001
+pp_data->cap[1]->BitCount                     = 152
+pp_data->cap[1]->BitField                     = 0x00
+pp_data->cap[1]->NextBytePosition             = 0x0014
+pp_data->cap[1]->LinkCollection               = 0x0000
+pp_data->cap[1]->LinkUsagePage                = 0xFF00
+pp_data->cap[1]->LinkUsage                    = 0x0002
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 1
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0002
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 0
+pp_data->cap[1]->NotRange.Reserved4                    = 0
+pp_data->cap[1]->Button.LogicalMin                   = 0
+pp_data->cap[1]->Button.LogicalMax                   = 255
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0002
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0xFF00
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_C52F_0002_FF00_expected.rpt_desc b/src/hidapi/windows/test/data/046D_C52F_0002_FF00_expected.rpt_desc
new file mode 100644
index 0000000..b1654e7
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C52F_0002_FF00_expected.rpt_desc
@@ -0,0 +1,4 @@
+0x06, 0x00, 0xFF, 0x09, 0x02, 0xA1, 0x01, 0x85, 0x11, 0x09, 
+0x02, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x13, 
+0x81, 0x00, 0x09, 0x02, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x13, 0x91, 0x00, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C52F_0002_FF00_real.rpt_desc b/src/hidapi/windows/test/data/046D_C52F_0002_FF00_real.rpt_desc
new file mode 100644
index 0000000..68043e1
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C52F_0002_FF00_real.rpt_desc
@@ -0,0 +1,13 @@
+Usage Page (Vendor-Defined 1) 06 00 FF  
+Usage (Vendor-Defined 2) 09 02  
+Collection (Application) A1 01  
+    Report ID (17) 85 11  
+    Report Size (8) 75 08  
+    Report Count (19) 95 13  
+    Logical Minimum (0) 15 00  
+    Logical Maximum (255) 26 FF 00  
+    Usage (Vendor-Defined 2) 09 02  
+    Input (Data,Ary,Abs) 81 00  
+    Usage (Vendor-Defined 2) 09 02  
+    Output (Data,Ary,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 00  
+End Collection C0  
diff --git a/src/hidapi/windows/test/data/046D_C534_0001_000C.pp_data b/src/hidapi/windows/test/data/046D_C534_0001_000C.pp_data
new file mode 100644
index 0000000..5e44a31
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0001_000C.pp_data
@@ -0,0 +1,93 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xC534
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "USB Receiver"
+dev->release_number      = 0x2901
+dev->interface_number    = 1
+dev->usage               = 0x0001
+dev->usage_page          = 0x000C
+dev->path                = "\\?\hid#vid_046d&pid_c534&mi_01&col02#7&1ebb799e&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0001
+pp_data->UsagePage                            = 0x000C
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 1
+pp_data->caps_info[0]->NumberOfCaps       = 1
+pp_data->caps_info[0]->ReportByteLength   = 5
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 1
+pp_data->caps_info[1]->LastCap            = 1
+pp_data->caps_info[1]->NumberOfCaps       = 0
+pp_data->caps_info[1]->ReportByteLength   = 0
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 1
+pp_data->caps_info[2]->LastCap            = 1
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x0068
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x000C
+pp_data->cap[0]->ReportID                     = 0x03
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 16
+pp_data->cap[0]->ReportCount                  = 2
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 32
+pp_data->cap[0]->BitField                     = 0x00
+pp_data->cap[0]->NextBytePosition             = 0x0005
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0x000C
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 1
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->Range.UsageMin                     = 0x0001
+pp_data->cap[0]->Range.UsageMax                     = 0x028C
+pp_data->cap[0]->Range.StringMin                    = 0
+pp_data->cap[0]->Range.StringMax                    = 0
+pp_data->cap[0]->Range.DesignatorMin                = 0
+pp_data->cap[0]->Range.DesignatorMax                = 0
+pp_data->cap[0]->Range.DataIndexMin                 = 0
+pp_data->cap[0]->Range.DataIndexMax                 = 651
+pp_data->cap[0]->Button.LogicalMin                   = 1
+pp_data->cap[0]->Button.LogicalMax                   = 652
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x000C
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_C534_0001_000C_expected.rpt_desc b/src/hidapi/windows/test/data/046D_C534_0001_000C_expected.rpt_desc
new file mode 100644
index 0000000..85953ae
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0001_000C_expected.rpt_desc
@@ -0,0 +1,3 @@
+0x05, 0x0C, 0x09, 0x01, 0xA1, 0x01, 0x85, 0x03, 0x19, 0x01, 
+0x2A, 0x8C, 0x02, 0x15, 0x01, 0x26, 0x8C, 0x02, 0x75, 0x10, 
+0x95, 0x02, 0x81, 0x00, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C534_0001_000C_real.rpt_desc b/src/hidapi/windows/test/data/046D_C534_0001_000C_real.rpt_desc
new file mode 100644
index 0000000..e08f1f3
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0001_000C_real.rpt_desc
@@ -0,0 +1,18 @@
+macOS USB prober output for Logitech USB Receiver
+ 05 0C  09 01  A1 01
+ 85 03  75 10  95 02  15 01  26 8C 02  19 01  2A 8C 02  81 00
+ C0
+ 
+ Parser output:
+0x05, 0x0C,        // Usage Page (Consumer)
+0x09, 0x01,        // Usage (Consumer Control)
+0xA1, 0x01,        // Collection (Application)
+0x85, 0x03,        //   Report ID (3)
+0x75, 0x10,        //   Report Size (16)
+0x95, 0x02,        //   Report Count (2)
+0x15, 0x01,        //   Logical Minimum (1)
+0x26, 0x8C, 0x02,  //   Logical Maximum (652)
+0x19, 0x01,        //   Usage Minimum (Consumer Control)
+0x2A, 0x8C, 0x02,  //   Usage Maximum (AC Send)
+0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0xC0,              // End Collection
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C534_0001_FF00.pp_data b/src/hidapi/windows/test/data/046D_C534_0001_FF00.pp_data
new file mode 100644
index 0000000..6d42a15
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0001_FF00.pp_data
@@ -0,0 +1,139 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xC534
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "USB Receiver"
+dev->release_number      = 0x2901
+dev->interface_number    = 1
+dev->usage               = 0x0001
+dev->usage_page          = 0xFF00
+dev->path                = "\\?\hid#vid_046d&pid_c534&mi_01&col04#7&1ebb799e&0&0003#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0001
+pp_data->UsagePage                            = 0xFF00
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 1
+pp_data->caps_info[0]->NumberOfCaps       = 1
+pp_data->caps_info[0]->ReportByteLength   = 7
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 1
+pp_data->caps_info[1]->LastCap            = 2
+pp_data->caps_info[1]->NumberOfCaps       = 1
+pp_data->caps_info[1]->ReportByteLength   = 7
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 2
+pp_data->caps_info[2]->LastCap            = 2
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x00D0
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0xFF00
+pp_data->cap[0]->ReportID                     = 0x10
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 8
+pp_data->cap[0]->ReportCount                  = 6
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 48
+pp_data->cap[0]->BitField                     = 0x00
+pp_data->cap[0]->NextBytePosition             = 0x0007
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0xFF00
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x0001
+pp_data->cap[0]->NotRange.Reserved1                    = 0x0001
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 255
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[1]->UsagePage                    = 0xFF00
+pp_data->cap[1]->ReportID                     = 0x10
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 8
+pp_data->cap[1]->ReportCount                  = 6
+pp_data->cap[1]->BytePosition                 = 0x0001
+pp_data->cap[1]->BitCount                     = 48
+pp_data->cap[1]->BitField                     = 0x00
+pp_data->cap[1]->NextBytePosition             = 0x0007
+pp_data->cap[1]->LinkCollection               = 0x0000
+pp_data->cap[1]->LinkUsagePage                = 0xFF00
+pp_data->cap[1]->LinkUsage                    = 0x0001
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 1
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0001
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0001
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 0
+pp_data->cap[1]->NotRange.Reserved4                    = 0
+pp_data->cap[1]->Button.LogicalMin                   = 0
+pp_data->cap[1]->Button.LogicalMax                   = 255
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0xFF00
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_C534_0001_FF00_expected.rpt_desc b/src/hidapi/windows/test/data/046D_C534_0001_FF00_expected.rpt_desc
new file mode 100644
index 0000000..812bd2a
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0001_FF00_expected.rpt_desc
@@ -0,0 +1,4 @@
+0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x85, 0x10, 0x09, 
+0x01, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x06, 
+0x81, 0x00, 0x09, 0x01, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x06, 0x91, 0x00, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C534_0001_FF00_real.rpt_desc b/src/hidapi/windows/test/data/046D_C534_0001_FF00_real.rpt_desc
new file mode 100644
index 0000000..953193c
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0001_FF00_real.rpt_desc
@@ -0,0 +1,20 @@
+macOS USB prober output for Logitech USB Receiver
+
+06 00 FF 09 01 A1 01 85 10 75 08 95 06
+15 00 26 FF 00 09 01 81  
+00 09 01 91 00 C0 
+                         
+Parser Output:
+0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
+0x09, 0x01,        // Usage (0x01)
+0xA1, 0x01,        // Collection (Application)
+0x85, 0x10,        //   Report ID (16)
+0x75, 0x08,        //   Report Size (8)
+0x95, 0x06,        //   Report Count (6)
+0x15, 0x00,        //   Logical Minimum (0)
+0x26, 0xFF, 0x00,  //   Logical Maximum (255)
+0x09, 0x01,        //   Usage (0x01)
+0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x09, 0x01,        //   Usage (0x01)
+0x91, 0x00,        //   Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0xC0,              // End Collection
diff --git a/src/hidapi/windows/test/data/046D_C534_0002_0001.pp_data b/src/hidapi/windows/test/data/046D_C534_0002_0001.pp_data
new file mode 100644
index 0000000..f50d8a2
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0002_0001.pp_data
@@ -0,0 +1,302 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xC534
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "USB Receiver"
+dev->release_number      = 0x2901
+dev->interface_number    = 1
+dev->usage               = 0x0002
+dev->usage_page          = 0x0001
+dev->path                = "\\?\hid#vid_046d&pid_c534&mi_01&col01#7&1ebb799e&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0002
+pp_data->UsagePage                            = 0x0001
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 5
+pp_data->caps_info[0]->NumberOfCaps       = 5
+pp_data->caps_info[0]->ReportByteLength   = 8
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 5
+pp_data->caps_info[1]->LastCap            = 5
+pp_data->caps_info[1]->NumberOfCaps       = 0
+pp_data->caps_info[1]->ReportByteLength   = 0
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 5
+pp_data->caps_info[2]->LastCap            = 5
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x0208
+pp_data->NumberLinkCollectionNodes            = 2
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x0009
+pp_data->cap[0]->ReportID                     = 0x02
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 1
+pp_data->cap[0]->ReportCount                  = 16
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 16
+pp_data->cap[0]->BitField                     = 0x02
+pp_data->cap[0]->NextBytePosition             = 0x0003
+pp_data->cap[0]->LinkCollection               = 0x0001
+pp_data->cap[0]->LinkUsagePage                = 0x0001
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 1
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->Range.UsageMin                     = 0x0001
+pp_data->cap[0]->Range.UsageMax                     = 0x0010
+pp_data->cap[0]->Range.StringMin                    = 0
+pp_data->cap[0]->Range.StringMax                    = 0
+pp_data->cap[0]->Range.DesignatorMin                = 0
+pp_data->cap[0]->Range.DesignatorMax                = 0
+pp_data->cap[0]->Range.DataIndexMin                 = 0
+pp_data->cap[0]->Range.DataIndexMax                 = 15
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 0
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0x0001
+pp_data->cap[1]->ReportID                     = 0x02
+pp_data->cap[1]->BitPosition                  = 4
+pp_data->cap[1]->BitSize                      = 12
+pp_data->cap[1]->ReportCount                  = 1
+pp_data->cap[1]->BytePosition                 = 0x0004
+pp_data->cap[1]->BitCount                     = 12
+pp_data->cap[1]->BitField                     = 0x06
+pp_data->cap[1]->NextBytePosition             = 0x0006
+pp_data->cap[1]->LinkCollection               = 0x0001
+pp_data->cap[1]->LinkUsagePage                = 0x0001
+pp_data->cap[1]->LinkUsage                    = 0x0001
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 0
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 0
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0031
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0031
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 16
+pp_data->cap[1]->NotRange.Reserved4                    = 16
+pp_data->cap[1]->NotButton.HasNull                   = 0
+pp_data->cap[1]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[1]->NotButton.LogicalMin                = -2047
+pp_data->cap[1]->NotButton.LogicalMax                = 2047
+pp_data->cap[1]->NotButton.PhysicalMin               = 0
+pp_data->cap[1]->NotButton.PhysicalMax               = 0
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+pp_data->cap[2]->UsagePage                    = 0x0001
+pp_data->cap[2]->ReportID                     = 0x02
+pp_data->cap[2]->BitPosition                  = 0
+pp_data->cap[2]->BitSize                      = 12
+pp_data->cap[2]->ReportCount                  = 1
+pp_data->cap[2]->BytePosition                 = 0x0003
+pp_data->cap[2]->BitCount                     = 12
+pp_data->cap[2]->BitField                     = 0x06
+pp_data->cap[2]->NextBytePosition             = 0x0005
+pp_data->cap[2]->LinkCollection               = 0x0001
+pp_data->cap[2]->LinkUsagePage                = 0x0001
+pp_data->cap[2]->LinkUsage                    = 0x0001
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 0
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 0
+pp_data->cap[2]->IsRange                      = 0
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->NotRange.Usage                        = 0x0030
+pp_data->cap[2]->NotRange.Reserved1                    = 0x0030
+pp_data->cap[2]->NotRange.StringIndex                  = 0
+pp_data->cap[2]->NotRange.Reserved2                    = 0
+pp_data->cap[2]->NotRange.DesignatorIndex              = 0
+pp_data->cap[2]->NotRange.Reserved3                    = 0
+pp_data->cap[2]->NotRange.DataIndex                    = 17
+pp_data->cap[2]->NotRange.Reserved4                    = 17
+pp_data->cap[2]->NotButton.HasNull                   = 0
+pp_data->cap[2]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[2]->NotButton.LogicalMin                = -2047
+pp_data->cap[2]->NotButton.LogicalMax                = 2047
+pp_data->cap[2]->NotButton.PhysicalMin               = 0
+pp_data->cap[2]->NotButton.PhysicalMax               = 0
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+pp_data->cap[3]->UsagePage                    = 0x0001
+pp_data->cap[3]->ReportID                     = 0x02
+pp_data->cap[3]->BitPosition                  = 0
+pp_data->cap[3]->BitSize                      = 8
+pp_data->cap[3]->ReportCount                  = 1
+pp_data->cap[3]->BytePosition                 = 0x0006
+pp_data->cap[3]->BitCount                     = 8
+pp_data->cap[3]->BitField                     = 0x06
+pp_data->cap[3]->NextBytePosition             = 0x0007
+pp_data->cap[3]->LinkCollection               = 0x0001
+pp_data->cap[3]->LinkUsagePage                = 0x0001
+pp_data->cap[3]->LinkUsage                    = 0x0001
+pp_data->cap[3]->IsMultipleItemsForArray      = 0
+pp_data->cap[3]->IsButtonCap                  = 0
+pp_data->cap[3]->IsPadding                    = 0
+pp_data->cap[3]->IsAbsolute                   = 0
+pp_data->cap[3]->IsRange                      = 0
+pp_data->cap[3]->IsAlias                      = 0
+pp_data->cap[3]->IsStringRange                = 0
+pp_data->cap[3]->IsDesignatorRange            = 0
+pp_data->cap[3]->Reserved1                    = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[3]->NotRange.Usage                        = 0x0038
+pp_data->cap[3]->NotRange.Reserved1                    = 0x0038
+pp_data->cap[3]->NotRange.StringIndex                  = 0
+pp_data->cap[3]->NotRange.Reserved2                    = 0
+pp_data->cap[3]->NotRange.DesignatorIndex              = 0
+pp_data->cap[3]->NotRange.Reserved3                    = 0
+pp_data->cap[3]->NotRange.DataIndex                    = 18
+pp_data->cap[3]->NotRange.Reserved4                    = 18
+pp_data->cap[3]->NotButton.HasNull                   = 0
+pp_data->cap[3]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[3]->NotButton.LogicalMin                = -127
+pp_data->cap[3]->NotButton.LogicalMax                = 127
+pp_data->cap[3]->NotButton.PhysicalMin               = 0
+pp_data->cap[3]->NotButton.PhysicalMax               = 0
+pp_data->cap[3]->Units                    = 0
+pp_data->cap[3]->UnitsExp                 = 0
+
+pp_data->cap[4]->UsagePage                    = 0x000C
+pp_data->cap[4]->ReportID                     = 0x02
+pp_data->cap[4]->BitPosition                  = 0
+pp_data->cap[4]->BitSize                      = 8
+pp_data->cap[4]->ReportCount                  = 1
+pp_data->cap[4]->BytePosition                 = 0x0007
+pp_data->cap[4]->BitCount                     = 8
+pp_data->cap[4]->BitField                     = 0x06
+pp_data->cap[4]->NextBytePosition             = 0x0008
+pp_data->cap[4]->LinkCollection               = 0x0001
+pp_data->cap[4]->LinkUsagePage                = 0x0001
+pp_data->cap[4]->LinkUsage                    = 0x0001
+pp_data->cap[4]->IsMultipleItemsForArray      = 0
+pp_data->cap[4]->IsButtonCap                  = 0
+pp_data->cap[4]->IsPadding                    = 0
+pp_data->cap[4]->IsAbsolute                   = 0
+pp_data->cap[4]->IsRange                      = 0
+pp_data->cap[4]->IsAlias                      = 0
+pp_data->cap[4]->IsStringRange                = 0
+pp_data->cap[4]->IsDesignatorRange            = 0
+pp_data->cap[4]->Reserved1                    = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[4]->NotRange.Usage                        = 0x0238
+pp_data->cap[4]->NotRange.Reserved1                    = 0x0238
+pp_data->cap[4]->NotRange.StringIndex                  = 0
+pp_data->cap[4]->NotRange.Reserved2                    = 0
+pp_data->cap[4]->NotRange.DesignatorIndex              = 0
+pp_data->cap[4]->NotRange.Reserved3                    = 0
+pp_data->cap[4]->NotRange.DataIndex                    = 19
+pp_data->cap[4]->NotRange.Reserved4                    = 19
+pp_data->cap[4]->NotButton.HasNull                   = 0
+pp_data->cap[4]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[4]->NotButton.LogicalMin                = -127
+pp_data->cap[4]->NotButton.LogicalMax                = 127
+pp_data->cap[4]->NotButton.PhysicalMin               = 0
+pp_data->cap[4]->NotButton.PhysicalMax               = 0
+pp_data->cap[4]->Units                    = 0
+pp_data->cap[4]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0002
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 1
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 1
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[1]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[1]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[1]->Parent             = 0
+pp_data->LinkCollectionArray[1]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[1]->NextSibling        = 0
+pp_data->LinkCollectionArray[1]->FirstChild         = 0
+pp_data->LinkCollectionArray[1]->CollectionType     = 0
+pp_data->LinkCollectionArray[1]->IsAlias            = 0
+pp_data->LinkCollectionArray[1]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_C534_0002_0001_expected.rpt_desc b/src/hidapi/windows/test/data/046D_C534_0002_0001_expected.rpt_desc
new file mode 100644
index 0000000..48701c6
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0002_0001_expected.rpt_desc
@@ -0,0 +1,8 @@
+0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 0xA1, 0x00, 
+0x85, 0x02, 0x05, 0x09, 0x19, 0x01, 0x29, 0x10, 0x15, 0x00, 
+0x25, 0x01, 0x75, 0x01, 0x95, 0x10, 0x81, 0x02, 0x05, 0x01, 
+0x09, 0x30, 0x09, 0x31, 0x16, 0x01, 0xF8, 0x26, 0xFF, 0x07, 
+0x75, 0x0C, 0x95, 0x02, 0x81, 0x06, 0x09, 0x38, 0x15, 0x81, 
+0x25, 0x7F, 0x75, 0x08, 0x95, 0x01, 0x81, 0x06, 0x05, 0x0C, 
+0x0A, 0x38, 0x02, 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08, 0x95, 
+0x01, 0x81, 0x06, 0xC0, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C534_0002_0001_real.rpt_desc b/src/hidapi/windows/test/data/046D_C534_0002_0001_real.rpt_desc
new file mode 100644
index 0000000..1c5dea9
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0002_0001_real.rpt_desc
@@ -0,0 +1,44 @@
+
+05 01 09 02 A1 01 85 02  09 01 A1 00 05 09 19 01  
+29 10 15 00 25 01 95 10  75 01 81 02 05 01 16 01  
+F8 26 FF 07 75 0C 95 02  09 30 09 31 81 06 15 81  
+25 7F 75 08 95 01 09 38  81 06 05 0C 0A 38 02 95  
+01 81 06 C0 C0
+
+Parser Output:
+0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
+0x09, 0x02,        // Usage (Mouse)
+0xA1, 0x01,        // Collection (Application)
+0x85, 0x02,        //   Report ID (2)
+0x09, 0x01,        //   Usage (Pointer)
+0xA1, 0x00,        //   Collection (Physical)
+0x05, 0x09,        //     Usage Page (Button)
+0x19, 0x01,        //     Usage Minimum (0x01)
+0x29, 0x10,        //     Usage Maximum (0x10)
+0x15, 0x00,        //     Logical Minimum (0)
+0x25, 0x01,        //     Logical Maximum (1)
+0x95, 0x10,        //     Report Count (16)
+0x75, 0x01,        //     Report Size (1)
+0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
+0x16, 0x01, 0xF8,  //     Logical Minimum (-2047)
+0x26, 0xFF, 0x07,  //     Logical Maximum (2047)
+0x75, 0x0C,        //     Report Size (12)
+0x95, 0x02,        //     Report Count (2)
+0x09, 0x30,        //     Usage (X)
+0x09, 0x31,        //     Usage (Y)
+0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+0x15, 0x81,        //     Logical Minimum (-127)
+0x25, 0x7F,        //     Logical Maximum (127)
+0x75, 0x08,        //     Report Size (8)
+0x95, 0x01,        //     Report Count (1)
+0x09, 0x38,        //     Usage (Wheel)
+0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+0x05, 0x0C,        //     Usage Page (Consumer)
+0x0A, 0x38, 0x02,  //     Usage (AC Pan)
+0x95, 0x01,        //     Report Count (1)
+0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+0xC0,              //   End Collection
+0xC0,              // End Collection
+
+// 69 bytes
diff --git a/src/hidapi/windows/test/data/046D_C534_0002_FF00.pp_data b/src/hidapi/windows/test/data/046D_C534_0002_FF00.pp_data
new file mode 100644
index 0000000..b5fae3a
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0002_FF00.pp_data
@@ -0,0 +1,139 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xC534
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "USB Receiver"
+dev->release_number      = 0x2901
+dev->interface_number    = 1
+dev->usage               = 0x0002
+dev->usage_page          = 0xFF00
+dev->path                = "\\?\hid#vid_046d&pid_c534&mi_01&col05#7&1ebb799e&0&0004#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0002
+pp_data->UsagePage                            = 0xFF00
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 1
+pp_data->caps_info[0]->NumberOfCaps       = 1
+pp_data->caps_info[0]->ReportByteLength   = 20
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 1
+pp_data->caps_info[1]->LastCap            = 2
+pp_data->caps_info[1]->NumberOfCaps       = 1
+pp_data->caps_info[1]->ReportByteLength   = 20
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 2
+pp_data->caps_info[2]->LastCap            = 2
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x00D0
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0xFF00
+pp_data->cap[0]->ReportID                     = 0x11
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 8
+pp_data->cap[0]->ReportCount                  = 19
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 152
+pp_data->cap[0]->BitField                     = 0x00
+pp_data->cap[0]->NextBytePosition             = 0x0014
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0xFF00
+pp_data->cap[0]->LinkUsage                    = 0x0002
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x0002
+pp_data->cap[0]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 255
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[1]->UsagePage                    = 0xFF00
+pp_data->cap[1]->ReportID                     = 0x11
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 8
+pp_data->cap[1]->ReportCount                  = 19
+pp_data->cap[1]->BytePosition                 = 0x0001
+pp_data->cap[1]->BitCount                     = 152
+pp_data->cap[1]->BitField                     = 0x00
+pp_data->cap[1]->NextBytePosition             = 0x0014
+pp_data->cap[1]->LinkCollection               = 0x0000
+pp_data->cap[1]->LinkUsagePage                = 0xFF00
+pp_data->cap[1]->LinkUsage                    = 0x0002
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 1
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0002
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 0
+pp_data->cap[1]->NotRange.Reserved4                    = 0
+pp_data->cap[1]->Button.LogicalMin                   = 0
+pp_data->cap[1]->Button.LogicalMax                   = 255
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0002
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0xFF00
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_C534_0002_FF00_expected.rpt_desc b/src/hidapi/windows/test/data/046D_C534_0002_FF00_expected.rpt_desc
new file mode 100644
index 0000000..b1654e7
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0002_FF00_expected.rpt_desc
@@ -0,0 +1,4 @@
+0x06, 0x00, 0xFF, 0x09, 0x02, 0xA1, 0x01, 0x85, 0x11, 0x09, 
+0x02, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 0x08, 0x95, 0x13, 
+0x81, 0x00, 0x09, 0x02, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x13, 0x91, 0x00, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C534_0002_FF00_real.rpt_desc b/src/hidapi/windows/test/data/046D_C534_0002_FF00_real.rpt_desc
new file mode 100644
index 0000000..42a0ad8
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0002_FF00_real.rpt_desc
@@ -0,0 +1,22 @@
+macOS USB prober output for Logitech USB Receiver
+
+06 00  FF 09 02 A1 01 85 11
+75 08 95 13 15 00 26 FF
+00 09 02 81 00 09 02 91 00 C0
+
+Parser output:
+0x06, 0x00, 0xFF,  // Usage Page (Vendor Defined 0xFF00)
+0x09, 0x02,        // Usage (0x02)
+0xA1, 0x01,        // Collection (Application)
+0x85, 0x11,        //   Report ID (17)
+0x75, 0x08,        //   Report Size (8)
+0x95, 0x13,        //   Report Count (19)
+0x15, 0x00,        //   Logical Minimum (0)
+0x26, 0xFF, 0x00,  //   Logical Maximum (255)
+0x09, 0x02,        //   Usage (0x02)
+0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x09, 0x02,        //   Usage (0x02)
+0x91, 0x00,        //   Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0xC0,              // End Collection
+
+// 27 bytes
diff --git a/src/hidapi/windows/test/data/046D_C534_0006_0001.pp_data b/src/hidapi/windows/test/data/046D_C534_0006_0001.pp_data
new file mode 100644
index 0000000..2b42d5f
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0006_0001.pp_data
@@ -0,0 +1,185 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xC534
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "USB Receiver"
+dev->release_number      = 0x2901
+dev->interface_number    = 0
+dev->usage               = 0x0006
+dev->usage_page          = 0x0001
+dev->path                = "\\?\hid#vid_046d&pid_c534&mi_00#7&51bc424&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}\kbd"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0006
+pp_data->UsagePage                            = 0x0001
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 2
+pp_data->caps_info[0]->NumberOfCaps       = 2
+pp_data->caps_info[0]->ReportByteLength   = 9
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 2
+pp_data->caps_info[1]->LastCap            = 3
+pp_data->caps_info[1]->NumberOfCaps       = 1
+pp_data->caps_info[1]->ReportByteLength   = 2
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 3
+pp_data->caps_info[2]->LastCap            = 3
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x0138
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x0007
+pp_data->cap[0]->ReportID                     = 0x00
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 1
+pp_data->cap[0]->ReportCount                  = 8
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 8
+pp_data->cap[0]->BitField                     = 0x02
+pp_data->cap[0]->NextBytePosition             = 0x0002
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0x0001
+pp_data->cap[0]->LinkUsage                    = 0x0006
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 1
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->Range.UsageMin                     = 0x00E0
+pp_data->cap[0]->Range.UsageMax                     = 0x00E7
+pp_data->cap[0]->Range.StringMin                    = 0
+pp_data->cap[0]->Range.StringMax                    = 0
+pp_data->cap[0]->Range.DesignatorMin                = 0
+pp_data->cap[0]->Range.DesignatorMax                = 0
+pp_data->cap[0]->Range.DataIndexMin                 = 0
+pp_data->cap[0]->Range.DataIndexMax                 = 7
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 0
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0x0007
+pp_data->cap[1]->ReportID                     = 0x00
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 8
+pp_data->cap[1]->ReportCount                  = 6
+pp_data->cap[1]->BytePosition                 = 0x0003
+pp_data->cap[1]->BitCount                     = 48
+pp_data->cap[1]->BitField                     = 0x00
+pp_data->cap[1]->NextBytePosition             = 0x0009
+pp_data->cap[1]->LinkCollection               = 0x0000
+pp_data->cap[1]->LinkUsagePage                = 0x0001
+pp_data->cap[1]->LinkUsage                    = 0x0006
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 1
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 1
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->Range.UsageMin                     = 0x0000
+pp_data->cap[1]->Range.UsageMax                     = 0x00A4
+pp_data->cap[1]->Range.StringMin                    = 0
+pp_data->cap[1]->Range.StringMax                    = 0
+pp_data->cap[1]->Range.DesignatorMin                = 0
+pp_data->cap[1]->Range.DesignatorMax                = 0
+pp_data->cap[1]->Range.DataIndexMin                 = 8
+pp_data->cap[1]->Range.DataIndexMax                 = 172
+pp_data->cap[1]->Button.LogicalMin                   = 0
+pp_data->cap[1]->Button.LogicalMax                   = 164
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[2]->UsagePage                    = 0x0008
+pp_data->cap[2]->ReportID                     = 0x00
+pp_data->cap[2]->BitPosition                  = 0
+pp_data->cap[2]->BitSize                      = 1
+pp_data->cap[2]->ReportCount                  = 5
+pp_data->cap[2]->BytePosition                 = 0x0001
+pp_data->cap[2]->BitCount                     = 5
+pp_data->cap[2]->BitField                     = 0x02
+pp_data->cap[2]->NextBytePosition             = 0x0002
+pp_data->cap[2]->LinkCollection               = 0x0000
+pp_data->cap[2]->LinkUsagePage                = 0x0001
+pp_data->cap[2]->LinkUsage                    = 0x0006
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 1
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 1
+pp_data->cap[2]->IsRange                      = 1
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->Range.UsageMin                     = 0x0001
+pp_data->cap[2]->Range.UsageMax                     = 0x0005
+pp_data->cap[2]->Range.StringMin                    = 0
+pp_data->cap[2]->Range.StringMax                    = 0
+pp_data->cap[2]->Range.DesignatorMin                = 0
+pp_data->cap[2]->Range.DesignatorMax                = 0
+pp_data->cap[2]->Range.DataIndexMin                 = 0
+pp_data->cap[2]->Range.DataIndexMax                 = 4
+pp_data->cap[2]->Button.LogicalMin                   = 0
+pp_data->cap[2]->Button.LogicalMax                   = 0
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0006
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_C534_0006_0001_expected.rpt_desc b/src/hidapi/windows/test/data/046D_C534_0006_0001_expected.rpt_desc
new file mode 100644
index 0000000..d41d471
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0006_0001_expected.rpt_desc
@@ -0,0 +1,7 @@
+0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xE0, 
+0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 
+0x81, 0x02, 0x75, 0x08, 0x95, 0x01, 0x81, 0x03, 0x19, 0x00, 
+0x29, 0xA4, 0x15, 0x00, 0x26, 0xA4, 0x00, 0x75, 0x08, 0x95, 
+0x06, 0x81, 0x00, 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, 0x15, 
+0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x05, 0x91, 0x02, 0x75, 
+0x03, 0x95, 0x01, 0x91, 0x03, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C534_0006_0001_real.rpt_desc b/src/hidapi/windows/test/data/046D_C534_0006_0001_real.rpt_desc
new file mode 100644
index 0000000..d65aa57
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0006_0001_real.rpt_desc
@@ -0,0 +1,42 @@
+macOS USB prober output for Logitech USB Receiver
+
+
+Type:   0x22  (Report Descriptor)
+Length (and contents):   59
+    Raw Descriptor (hex)    0000: 05 01 09 06 A1 01 05 07  19 E0 29 E7 15 00 25 01  
+    Raw Descriptor (hex)    0010: 75 01 95 08 81 02 81 03  95 05 05 08 19 01 29 05  
+    Raw Descriptor (hex)    0020: 91 02 95 01 75 03 91 01  95 06 75 08 15 00 26 A4  
+    Raw Descriptor (hex)    0030: 00 05 07 19 00 2A A4 00  81 00 C0 
+
+Parser output:
+0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
+0x09, 0x06,        // Usage (Keyboard)
+0xA1, 0x01,        // Collection (Application)
+0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
+0x19, 0xE0,        //   Usage Minimum (0xE0)
+0x29, 0xE7,        //   Usage Maximum (0xE7)
+0x15, 0x00,        //   Logical Minimum (0)
+0x25, 0x01,        //   Logical Maximum (1)
+0x75, 0x01,        //   Report Size (1)
+0x95, 0x08,        //   Report Count (8)
+0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x95, 0x05,        //   Report Count (5)
+0x05, 0x08,        //   Usage Page (LEDs)
+0x19, 0x01,        //   Usage Minimum (Num Lock)
+0x29, 0x05,        //   Usage Maximum (Kana)
+0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x95, 0x01,        //   Report Count (1)
+0x75, 0x03,        //   Report Size (3)
+0x91, 0x01,        //   Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x95, 0x06,        //   Report Count (6)
+0x75, 0x08,        //   Report Size (8)
+0x15, 0x00,        //   Logical Minimum (0)
+0x26, 0xA4, 0x00,  //   Logical Maximum (164)
+0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
+0x19, 0x00,        //   Usage Minimum (0x00)
+0x2A, 0xA4, 0x00,  //   Usage Maximum (0xA4)
+0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0xC0,              // End Collection
+
+// 59 bytes
diff --git a/src/hidapi/windows/test/data/046D_C534_0080_0001.pp_data b/src/hidapi/windows/test/data/046D_C534_0080_0001.pp_data
new file mode 100644
index 0000000..a829f70
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0080_0001.pp_data
@@ -0,0 +1,185 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x046D
+dev->product_id          = 0xC534
+dev->manufacturer_string = "Logitech"
+dev->product_string      = "USB Receiver"
+dev->release_number      = 0x2901
+dev->interface_number    = 1
+dev->usage               = 0x0080
+dev->usage_page          = 0x0001
+dev->path                = "\\?\hid#vid_046d&pid_c534&mi_01&col03#7&1ebb799e&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0080
+pp_data->UsagePage                            = 0x0001
+pp_data->Reserved                             = 0x00038000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 3
+pp_data->caps_info[0]->NumberOfCaps       = 3
+pp_data->caps_info[0]->ReportByteLength   = 2
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 3
+pp_data->caps_info[1]->LastCap            = 3
+pp_data->caps_info[1]->NumberOfCaps       = 0
+pp_data->caps_info[1]->ReportByteLength   = 0
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 3
+pp_data->caps_info[2]->LastCap            = 3
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x0138
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x0001
+pp_data->cap[0]->ReportID                     = 0x04
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 2
+pp_data->cap[0]->ReportCount                  = 1
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 2
+pp_data->cap[0]->BitField                     = 0x60
+pp_data->cap[0]->NextBytePosition             = 0x0002
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0x0001
+pp_data->cap[0]->LinkUsage                    = 0x0080
+pp_data->cap[0]->IsMultipleItemsForArray      = 1
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x0083
+pp_data->cap[0]->NotRange.Reserved1                    = 0x0083
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 2
+pp_data->cap[0]->NotRange.Reserved4                    = 2
+pp_data->cap[0]->Button.LogicalMin                   = 1
+pp_data->cap[0]->Button.LogicalMax                   = 3
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0x0001
+pp_data->cap[1]->ReportID                     = 0x04
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 2
+pp_data->cap[1]->ReportCount                  = 1
+pp_data->cap[1]->BytePosition                 = 0x0001
+pp_data->cap[1]->BitCount                     = 2
+pp_data->cap[1]->BitField                     = 0x60
+pp_data->cap[1]->NextBytePosition             = 0x0002
+pp_data->cap[1]->LinkCollection               = 0x0000
+pp_data->cap[1]->LinkUsagePage                = 0x0001
+pp_data->cap[1]->LinkUsage                    = 0x0080
+pp_data->cap[1]->IsMultipleItemsForArray      = 1
+pp_data->cap[1]->IsButtonCap                  = 1
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0081
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 1
+pp_data->cap[1]->NotRange.Reserved4                    = 1
+pp_data->cap[1]->Button.LogicalMin                   = 1
+pp_data->cap[1]->Button.LogicalMax                   = 3
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+pp_data->cap[2]->UsagePage                    = 0x0001
+pp_data->cap[2]->ReportID                     = 0x04
+pp_data->cap[2]->BitPosition                  = 0
+pp_data->cap[2]->BitSize                      = 2
+pp_data->cap[2]->ReportCount                  = 1
+pp_data->cap[2]->BytePosition                 = 0x0001
+pp_data->cap[2]->BitCount                     = 2
+pp_data->cap[2]->BitField                     = 0x60
+pp_data->cap[2]->NextBytePosition             = 0x0002
+pp_data->cap[2]->LinkCollection               = 0x0000
+pp_data->cap[2]->LinkUsagePage                = 0x0001
+pp_data->cap[2]->LinkUsage                    = 0x0080
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 1
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 1
+pp_data->cap[2]->IsRange                      = 0
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->NotRange.Usage                        = 0x0082
+pp_data->cap[2]->NotRange.Reserved1                    = 0x0082
+pp_data->cap[2]->NotRange.StringIndex                  = 0
+pp_data->cap[2]->NotRange.Reserved2                    = 0
+pp_data->cap[2]->NotRange.DesignatorIndex              = 0
+pp_data->cap[2]->NotRange.Reserved3                    = 0
+pp_data->cap[2]->NotRange.DataIndex                    = 0
+pp_data->cap[2]->NotRange.Reserved4                    = 0
+pp_data->cap[2]->Button.LogicalMin                   = 1
+pp_data->cap[2]->Button.LogicalMax                   = 3
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0080
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x0001
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/046D_C534_0080_0001_expected.rpt_desc b/src/hidapi/windows/test/data/046D_C534_0080_0001_expected.rpt_desc
new file mode 100644
index 0000000..e7a9677
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0080_0001_expected.rpt_desc
@@ -0,0 +1,4 @@
+0x05, 0x01, 0x09, 0x80, 0xA1, 0x01, 0x85, 0x04, 0x09, 0x82, 
+0x09, 0x81, 0x09, 0x83, 0x15, 0x01, 0x25, 0x03, 0x75, 0x02, 
+0x95, 0x01, 0x81, 0x60, 0x75, 0x06, 0x95, 0x01, 0x81, 0x03, 
+0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/046D_C534_0080_0001_real.rpt_desc b/src/hidapi/windows/test/data/046D_C534_0080_0001_real.rpt_desc
new file mode 100644
index 0000000..7ebe8c9
--- /dev/null
+++ b/src/hidapi/windows/test/data/046D_C534_0080_0001_real.rpt_desc
@@ -0,0 +1,22 @@
+
+05 01 09 80 A1 01 85 04 75 02  95 01 15 01 25 03
+09 82 09 81 09 83 81 60 75 06  81 03 C0
+
+Parser output:
+0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
+0x09, 0x80,        // Usage (Sys Control)
+0xA1, 0x01,        // Collection (Application)
+0x85, 0x04,        //   Report ID (4)
+0x75, 0x02,        //   Report Size (2)
+0x95, 0x01,        //   Report Count (1)
+0x15, 0x01,        //   Logical Minimum (1)
+0x25, 0x03,        //   Logical Maximum (3)
+0x09, 0x82,        //   Usage (Sys Sleep)
+0x09, 0x81,        //   Usage (Sys Power Down)
+0x09, 0x83,        //   Usage (Sys Wake Up)
+0x81, 0x60,        //   Input (Data,Array,Abs,No Wrap,Linear,No Preferred State,Null State)
+0x75, 0x06,        //   Report Size (6)
+0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0xC0,              // End Collection
+
+// 29 bytes
diff --git a/src/hidapi/windows/test/data/047F_C056_0001_000C.pp_data b/src/hidapi/windows/test/data/047F_C056_0001_000C.pp_data
new file mode 100644
index 0000000..87da2b2
--- /dev/null
+++ b/src/hidapi/windows/test/data/047F_C056_0001_000C.pp_data
@@ -0,0 +1,385 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x047F
+dev->product_id          = 0xC056
+dev->manufacturer_string = "Plantronics"
+dev->product_string      = "Plantronics Blackwire 3220 Series"
+dev->release_number      = 0x0210
+dev->interface_number    = 3
+dev->usage               = 0x0001
+dev->usage_page          = 0x000C
+dev->path                = "\\?\hid#vid_047f&pid_c056&mi_03&col01#f&39e6f119&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0001
+pp_data->UsagePage                            = 0x000C
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 5
+pp_data->caps_info[0]->NumberOfCaps       = 5
+pp_data->caps_info[0]->ReportByteLength   = 33
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 5
+pp_data->caps_info[1]->LastCap            = 7
+pp_data->caps_info[1]->NumberOfCaps       = 2
+pp_data->caps_info[1]->ReportByteLength   = 37
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 7
+pp_data->caps_info[2]->LastCap            = 7
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x02D8
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x000C
+pp_data->cap[0]->ReportID                     = 0x01
+pp_data->cap[0]->BitPosition                  = 1
+pp_data->cap[0]->BitSize                      = 1
+pp_data->cap[0]->ReportCount                  = 1
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 1
+pp_data->cap[0]->BitField                     = 0x06
+pp_data->cap[0]->NextBytePosition             = 0x0002
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0x000C
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 0
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x00EA
+pp_data->cap[0]->NotRange.Reserved1                    = 0x00EA
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 0
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0x000C
+pp_data->cap[1]->ReportID                     = 0x01
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 1
+pp_data->cap[1]->ReportCount                  = 1
+pp_data->cap[1]->BytePosition                 = 0x0001
+pp_data->cap[1]->BitCount                     = 1
+pp_data->cap[1]->BitField                     = 0x06
+pp_data->cap[1]->NextBytePosition             = 0x0002
+pp_data->cap[1]->LinkCollection               = 0x0000
+pp_data->cap[1]->LinkUsagePage                = 0x000C
+pp_data->cap[1]->LinkUsage                    = 0x0001
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 1
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 0
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x00E9
+pp_data->cap[1]->NotRange.Reserved1                    = 0x00E9
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 1
+pp_data->cap[1]->NotRange.Reserved4                    = 1
+pp_data->cap[1]->Button.LogicalMin                   = 0
+pp_data->cap[1]->Button.LogicalMax                   = 0
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+pp_data->cap[2]->UsagePage                    = 0x000C
+pp_data->cap[2]->ReportID                     = 0x02
+pp_data->cap[2]->BitPosition                  = 0
+pp_data->cap[2]->BitSize                      = 1
+pp_data->cap[2]->ReportCount                  = 16
+pp_data->cap[2]->BytePosition                 = 0x0001
+pp_data->cap[2]->BitCount                     = 16
+pp_data->cap[2]->BitField                     = 0x02
+pp_data->cap[2]->NextBytePosition             = 0x0003
+pp_data->cap[2]->LinkCollection               = 0x0000
+pp_data->cap[2]->LinkUsagePage                = 0x000C
+pp_data->cap[2]->LinkUsage                    = 0x0001
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 1
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 1
+pp_data->cap[2]->IsRange                      = 0
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->NotRange.Usage                        = 0x0000
+pp_data->cap[2]->NotRange.Reserved1                    = 0x0000
+pp_data->cap[2]->NotRange.StringIndex                  = 0
+pp_data->cap[2]->NotRange.Reserved2                    = 0
+pp_data->cap[2]->NotRange.DesignatorIndex              = 0
+pp_data->cap[2]->NotRange.Reserved3                    = 0
+pp_data->cap[2]->NotRange.DataIndex                    = 2
+pp_data->cap[2]->NotRange.Reserved4                    = 2
+pp_data->cap[2]->Button.LogicalMin                   = 0
+pp_data->cap[2]->Button.LogicalMax                   = 0
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+pp_data->cap[3]->UsagePage                    = 0x000C
+pp_data->cap[3]->ReportID                     = 0x05
+pp_data->cap[3]->BitPosition                  = 0
+pp_data->cap[3]->BitSize                      = 8
+pp_data->cap[3]->ReportCount                  = 32
+pp_data->cap[3]->BytePosition                 = 0x0001
+pp_data->cap[3]->BitCount                     = 256
+pp_data->cap[3]->BitField                     = 0x02
+pp_data->cap[3]->NextBytePosition             = 0x0021
+pp_data->cap[3]->LinkCollection               = 0x0000
+pp_data->cap[3]->LinkUsagePage                = 0x000C
+pp_data->cap[3]->LinkUsage                    = 0x0001
+pp_data->cap[3]->IsMultipleItemsForArray      = 0
+pp_data->cap[3]->IsButtonCap                  = 0
+pp_data->cap[3]->IsPadding                    = 0
+pp_data->cap[3]->IsAbsolute                   = 1
+pp_data->cap[3]->IsRange                      = 0
+pp_data->cap[3]->IsAlias                      = 0
+pp_data->cap[3]->IsStringRange                = 0
+pp_data->cap[3]->IsDesignatorRange            = 0
+pp_data->cap[3]->Reserved1                    = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[3]->NotRange.Usage                        = 0x0000
+pp_data->cap[3]->NotRange.Reserved1                    = 0x0000
+pp_data->cap[3]->NotRange.StringIndex                  = 0
+pp_data->cap[3]->NotRange.Reserved2                    = 0
+pp_data->cap[3]->NotRange.DesignatorIndex              = 0
+pp_data->cap[3]->NotRange.Reserved3                    = 0
+pp_data->cap[3]->NotRange.DataIndex                    = 3
+pp_data->cap[3]->NotRange.Reserved4                    = 3
+pp_data->cap[3]->NotButton.HasNull                   = 0
+pp_data->cap[3]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[3]->NotButton.LogicalMin                = 0
+pp_data->cap[3]->NotButton.LogicalMax                = 1
+pp_data->cap[3]->NotButton.PhysicalMin               = 0
+pp_data->cap[3]->NotButton.PhysicalMax               = 0
+pp_data->cap[3]->Units                    = 0
+pp_data->cap[3]->UnitsExp                 = 0
+
+pp_data->cap[4]->UsagePage                    = 0x000C
+pp_data->cap[4]->ReportID                     = 0x07
+pp_data->cap[4]->BitPosition                  = 0
+pp_data->cap[4]->BitSize                      = 8
+pp_data->cap[4]->ReportCount                  = 32
+pp_data->cap[4]->BytePosition                 = 0x0001
+pp_data->cap[4]->BitCount                     = 256
+pp_data->cap[4]->BitField                     = 0x02
+pp_data->cap[4]->NextBytePosition             = 0x0021
+pp_data->cap[4]->LinkCollection               = 0x0000
+pp_data->cap[4]->LinkUsagePage                = 0x000C
+pp_data->cap[4]->LinkUsage                    = 0x0001
+pp_data->cap[4]->IsMultipleItemsForArray      = 0
+pp_data->cap[4]->IsButtonCap                  = 0
+pp_data->cap[4]->IsPadding                    = 0
+pp_data->cap[4]->IsAbsolute                   = 1
+pp_data->cap[4]->IsRange                      = 0
+pp_data->cap[4]->IsAlias                      = 0
+pp_data->cap[4]->IsStringRange                = 0
+pp_data->cap[4]->IsDesignatorRange            = 0
+pp_data->cap[4]->Reserved1                    = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[4]->NotRange.Usage                        = 0x0000
+pp_data->cap[4]->NotRange.Reserved1                    = 0x0000
+pp_data->cap[4]->NotRange.StringIndex                  = 0
+pp_data->cap[4]->NotRange.Reserved2                    = 0
+pp_data->cap[4]->NotRange.DesignatorIndex              = 0
+pp_data->cap[4]->NotRange.Reserved3                    = 0
+pp_data->cap[4]->NotRange.DataIndex                    = 4
+pp_data->cap[4]->NotRange.Reserved4                    = 4
+pp_data->cap[4]->NotButton.HasNull                   = 0
+pp_data->cap[4]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[4]->NotButton.LogicalMin                = 0
+pp_data->cap[4]->NotButton.LogicalMax                = 1
+pp_data->cap[4]->NotButton.PhysicalMin               = 0
+pp_data->cap[4]->NotButton.PhysicalMax               = 0
+pp_data->cap[4]->Units                    = 0
+pp_data->cap[4]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[5]->UsagePage                    = 0x000C
+pp_data->cap[5]->ReportID                     = 0x04
+pp_data->cap[5]->BitPosition                  = 0
+pp_data->cap[5]->BitSize                      = 8
+pp_data->cap[5]->ReportCount                  = 36
+pp_data->cap[5]->BytePosition                 = 0x0001
+pp_data->cap[5]->BitCount                     = 288
+pp_data->cap[5]->BitField                     = 0x02
+pp_data->cap[5]->NextBytePosition             = 0x0025
+pp_data->cap[5]->LinkCollection               = 0x0000
+pp_data->cap[5]->LinkUsagePage                = 0x000C
+pp_data->cap[5]->LinkUsage                    = 0x0001
+pp_data->cap[5]->IsMultipleItemsForArray      = 0
+pp_data->cap[5]->IsButtonCap                  = 0
+pp_data->cap[5]->IsPadding                    = 0
+pp_data->cap[5]->IsAbsolute                   = 1
+pp_data->cap[5]->IsRange                      = 0
+pp_data->cap[5]->IsAlias                      = 0
+pp_data->cap[5]->IsStringRange                = 0
+pp_data->cap[5]->IsDesignatorRange            = 0
+pp_data->cap[5]->Reserved1                    = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[5]->NotRange.Usage                        = 0x0000
+pp_data->cap[5]->NotRange.Reserved1                    = 0x0000
+pp_data->cap[5]->NotRange.StringIndex                  = 0
+pp_data->cap[5]->NotRange.Reserved2                    = 0
+pp_data->cap[5]->NotRange.DesignatorIndex              = 0
+pp_data->cap[5]->NotRange.Reserved3                    = 0
+pp_data->cap[5]->NotRange.DataIndex                    = 0
+pp_data->cap[5]->NotRange.Reserved4                    = 0
+pp_data->cap[5]->NotButton.HasNull                   = 0
+pp_data->cap[5]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[5]->NotButton.LogicalMin                = 0
+pp_data->cap[5]->NotButton.LogicalMax                = 1
+pp_data->cap[5]->NotButton.PhysicalMin               = 0
+pp_data->cap[5]->NotButton.PhysicalMax               = 0
+pp_data->cap[5]->Units                    = 0
+pp_data->cap[5]->UnitsExp                 = 0
+
+pp_data->cap[6]->UsagePage                    = 0x000C
+pp_data->cap[6]->ReportID                     = 0x06
+pp_data->cap[6]->BitPosition                  = 0
+pp_data->cap[6]->BitSize                      = 8
+pp_data->cap[6]->ReportCount                  = 36
+pp_data->cap[6]->BytePosition                 = 0x0001
+pp_data->cap[6]->BitCount                     = 288
+pp_data->cap[6]->BitField                     = 0x02
+pp_data->cap[6]->NextBytePosition             = 0x0025
+pp_data->cap[6]->LinkCollection               = 0x0000
+pp_data->cap[6]->LinkUsagePage                = 0x000C
+pp_data->cap[6]->LinkUsage                    = 0x0001
+pp_data->cap[6]->IsMultipleItemsForArray      = 0
+pp_data->cap[6]->IsButtonCap                  = 0
+pp_data->cap[6]->IsPadding                    = 0
+pp_data->cap[6]->IsAbsolute                   = 1
+pp_data->cap[6]->IsRange                      = 0
+pp_data->cap[6]->IsAlias                      = 0
+pp_data->cap[6]->IsStringRange                = 0
+pp_data->cap[6]->IsDesignatorRange            = 0
+pp_data->cap[6]->Reserved1                    = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[6]->NotRange.Usage                        = 0x0000
+pp_data->cap[6]->NotRange.Reserved1                    = 0x0000
+pp_data->cap[6]->NotRange.StringIndex                  = 0
+pp_data->cap[6]->NotRange.Reserved2                    = 0
+pp_data->cap[6]->NotRange.DesignatorIndex              = 0
+pp_data->cap[6]->NotRange.Reserved3                    = 0
+pp_data->cap[6]->NotRange.DataIndex                    = 1
+pp_data->cap[6]->NotRange.Reserved4                    = 1
+pp_data->cap[6]->NotButton.HasNull                   = 0
+pp_data->cap[6]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[6]->NotButton.LogicalMin                = 0
+pp_data->cap[6]->NotButton.LogicalMax                = 1
+pp_data->cap[6]->NotButton.PhysicalMin               = 0
+pp_data->cap[6]->NotButton.PhysicalMax               = 0
+pp_data->cap[6]->Units                    = 0
+pp_data->cap[6]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x000C
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/047F_C056_0001_000C_expected.rpt_desc b/src/hidapi/windows/test/data/047F_C056_0001_000C_expected.rpt_desc
new file mode 100644
index 0000000..d7ca045
--- /dev/null
+++ b/src/hidapi/windows/test/data/047F_C056_0001_000C_expected.rpt_desc
@@ -0,0 +1,10 @@
+0x05, 0x0C, 0x09, 0x01, 0xA1, 0x01, 0x85, 0x01, 0x09, 0xE9, 
+0x09, 0xEA, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x02, 
+0x81, 0x06, 0x75, 0x06, 0x95, 0x01, 0x81, 0x03, 0x85, 0x02, 
+0x09, 0x00, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x10, 
+0x81, 0x02, 0x85, 0x05, 0x09, 0x00, 0x15, 0x00, 0x25, 0x01, 
+0x75, 0x08, 0x95, 0x20, 0x81, 0x02, 0x85, 0x07, 0x09, 0x00, 
+0x15, 0x00, 0x25, 0x01, 0x75, 0x08, 0x95, 0x20, 0x81, 0x02, 
+0x85, 0x04, 0x09, 0x00, 0x15, 0x00, 0x25, 0x01, 0x75, 0x08, 
+0x95, 0x24, 0x91, 0x02, 0x85, 0x06, 0x09, 0x00, 0x15, 0x00, 
+0x25, 0x01, 0x75, 0x08, 0x95, 0x24, 0x91, 0x02, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/047F_C056_0001_000C_real.rpt_desc b/src/hidapi/windows/test/data/047F_C056_0001_000C_real.rpt_desc
new file mode 100644
index 0000000..ba0fc3a
--- /dev/null
+++ b/src/hidapi/windows/test/data/047F_C056_0001_000C_real.rpt_desc
@@ -0,0 +1,47 @@
+macOS USB Prober about 0x047F/0xC056 "Plantronics Blackwire 3220 Series"
+05 0C 09 01 A1 01 85 01 15 00 25 01 09 E9 09 EA  
+75 01 95 02 81 06 95 06 81 01 85 02 05 0C 09 00  
+95 10 81 02 85 04 09 00 75 08 95 24 91 02 85 05  
+09 00 95 20 81 02 85 06 09 00 95 24 91 02 85 07  
+09 00 95 20 81 02 C0
+
+# Parser output:
+
+0x05, 0x0C,        // Usage Page (Consumer)
+0x09, 0x01,        // Usage (Consumer Control)
+0xA1, 0x01,        // Collection (Application)
+0x85, 0x01,        //   Report ID (1)
+0x15, 0x00,        //   Logical Minimum (0)
+0x25, 0x01,        //   Logical Maximum (1)
+0x09, 0xE9,        //   Usage (Volume Increment)
+0x09, 0xEA,        //   Usage (Volume Decrement)
+0x75, 0x01,        //   Report Size (1)
+0x95, 0x02,        //   Report Count (2)
+0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+0x95, 0x06,        //   Report Count (6)
+0x81, 0x01,        //   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x85, 0x02,        //   Report ID (2)
+0x05, 0x0C,        //   Usage Page (Consumer)
+0x09, 0x00,        //   Usage (Unassigned)
+0x95, 0x10,        //   Report Count (16)
+0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x85, 0x04,        //   Report ID (4)
+0x09, 0x00,        //   Usage (Unassigned)
+0x75, 0x08,        //   Report Size (8)
+0x95, 0x24,        //   Report Count (36)
+0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x85, 0x05,        //   Report ID (5)
+0x09, 0x00,        //   Usage (Unassigned)
+0x95, 0x20,        //   Report Count (32)
+0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x85, 0x06,        //   Report ID (6)
+0x09, 0x00,        //   Usage (Unassigned)
+0x95, 0x24,        //   Report Count (36)
+0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x85, 0x07,        //   Report ID (7)
+0x09, 0x00,        //   Usage (Unassigned)
+0x95, 0x20,        //   Report Count (32)
+0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0xC0,              // End Collection
+
+// 71 bytes
diff --git a/src/hidapi/windows/test/data/047F_C056_0003_FFA0.pp_data b/src/hidapi/windows/test/data/047F_C056_0003_FFA0.pp_data
new file mode 100644
index 0000000..6def736
--- /dev/null
+++ b/src/hidapi/windows/test/data/047F_C056_0003_FFA0.pp_data
@@ -0,0 +1,1255 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x047F
+dev->product_id          = 0xC056
+dev->manufacturer_string = "Plantronics"
+dev->product_string      = "Plantronics Blackwire 3220 Series"
+dev->release_number      = 0x0210
+dev->interface_number    = 3
+dev->usage               = 0x0003
+dev->usage_page          = 0xFFA0
+dev->path                = "\\?\hid#vid_047f&pid_c056&mi_03&col03#f&39e6f119&0&0002#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0003
+pp_data->UsagePage                            = 0xFFA0
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 8
+pp_data->caps_info[0]->NumberOfCaps       = 8
+pp_data->caps_info[0]->ReportByteLength   = 33
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 8
+pp_data->caps_info[1]->LastCap            = 16
+pp_data->caps_info[1]->NumberOfCaps       = 8
+pp_data->caps_info[1]->ReportByteLength   = 33
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 16
+pp_data->caps_info[2]->LastCap            = 26
+pp_data->caps_info[2]->NumberOfCaps       = 10
+pp_data->caps_info[2]->ReportByteLength   = 3
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x0A90
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0xFFA0
+pp_data->cap[0]->ReportID                     = 0x03
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 8
+pp_data->cap[0]->ReportCount                  = 32
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 256
+pp_data->cap[0]->BitField                     = 0x02
+pp_data->cap[0]->NextBytePosition             = 0x0021
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0xFFA0
+pp_data->cap[0]->LinkUsage                    = 0x0003
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 0
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x0030
+pp_data->cap[0]->NotRange.Reserved1                    = 0x0030
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->NotButton.HasNull                   = 0
+pp_data->cap[0]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[0]->NotButton.LogicalMin                = 0
+pp_data->cap[0]->NotButton.LogicalMax                = 1
+pp_data->cap[0]->NotButton.PhysicalMin               = 0
+pp_data->cap[0]->NotButton.PhysicalMax               = 0
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0xFFA0
+pp_data->cap[1]->ReportID                     = 0x14
+pp_data->cap[1]->BitPosition                  = 4
+pp_data->cap[1]->BitSize                      = 1
+pp_data->cap[1]->ReportCount                  = 1
+pp_data->cap[1]->BytePosition                 = 0x0001
+pp_data->cap[1]->BitCount                     = 1
+pp_data->cap[1]->BitField                     = 0x06
+pp_data->cap[1]->NextBytePosition             = 0x0002
+pp_data->cap[1]->LinkCollection               = 0x0000
+pp_data->cap[1]->LinkUsagePage                = 0xFFA0
+pp_data->cap[1]->LinkUsage                    = 0x0003
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 1
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 0
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x00B3
+pp_data->cap[1]->NotRange.Reserved1                    = 0x00B3
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 1
+pp_data->cap[1]->NotRange.Reserved4                    = 1
+pp_data->cap[1]->Button.LogicalMin                   = 0
+pp_data->cap[1]->Button.LogicalMax                   = 0
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+pp_data->cap[2]->UsagePage                    = 0xFFA0
+pp_data->cap[2]->ReportID                     = 0x14
+pp_data->cap[2]->BitPosition                  = 3
+pp_data->cap[2]->BitSize                      = 1
+pp_data->cap[2]->ReportCount                  = 1
+pp_data->cap[2]->BytePosition                 = 0x0001
+pp_data->cap[2]->BitCount                     = 1
+pp_data->cap[2]->BitField                     = 0x06
+pp_data->cap[2]->NextBytePosition             = 0x0002
+pp_data->cap[2]->LinkCollection               = 0x0000
+pp_data->cap[2]->LinkUsagePage                = 0xFFA0
+pp_data->cap[2]->LinkUsage                    = 0x0003
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 1
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 0
+pp_data->cap[2]->IsRange                      = 0
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->NotRange.Usage                        = 0x00B7
+pp_data->cap[2]->NotRange.Reserved1                    = 0x00B7
+pp_data->cap[2]->NotRange.StringIndex                  = 0
+pp_data->cap[2]->NotRange.Reserved2                    = 0
+pp_data->cap[2]->NotRange.DesignatorIndex              = 0
+pp_data->cap[2]->NotRange.Reserved3                    = 0
+pp_data->cap[2]->NotRange.DataIndex                    = 2
+pp_data->cap[2]->NotRange.Reserved4                    = 2
+pp_data->cap[2]->Button.LogicalMin                   = 0
+pp_data->cap[2]->Button.LogicalMax                   = 0
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+pp_data->cap[3]->UsagePage                    = 0xFFA0
+pp_data->cap[3]->ReportID                     = 0x14
+pp_data->cap[3]->BitPosition                  = 2
+pp_data->cap[3]->BitSize                      = 1
+pp_data->cap[3]->ReportCount                  = 1
+pp_data->cap[3]->BytePosition                 = 0x0001
+pp_data->cap[3]->BitCount                     = 1
+pp_data->cap[3]->BitField                     = 0x06
+pp_data->cap[3]->NextBytePosition             = 0x0002
+pp_data->cap[3]->LinkCollection               = 0x0000
+pp_data->cap[3]->LinkUsagePage                = 0xFFA0
+pp_data->cap[3]->LinkUsage                    = 0x0003
+pp_data->cap[3]->IsMultipleItemsForArray      = 0
+pp_data->cap[3]->IsButtonCap                  = 1
+pp_data->cap[3]->IsPadding                    = 0
+pp_data->cap[3]->IsAbsolute                   = 0
+pp_data->cap[3]->IsRange                      = 0
+pp_data->cap[3]->IsAlias                      = 0
+pp_data->cap[3]->IsStringRange                = 0
+pp_data->cap[3]->IsDesignatorRange            = 0
+pp_data->cap[3]->Reserved1                    = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[3]->NotRange.Usage                        = 0x00B5
+pp_data->cap[3]->NotRange.Reserved1                    = 0x00B5
+pp_data->cap[3]->NotRange.StringIndex                  = 0
+pp_data->cap[3]->NotRange.Reserved2                    = 0
+pp_data->cap[3]->NotRange.DesignatorIndex              = 0
+pp_data->cap[3]->NotRange.Reserved3                    = 0
+pp_data->cap[3]->NotRange.DataIndex                    = 3
+pp_data->cap[3]->NotRange.Reserved4                    = 3
+pp_data->cap[3]->Button.LogicalMin                   = 0
+pp_data->cap[3]->Button.LogicalMax                   = 0
+pp_data->cap[3]->Units                    = 0
+pp_data->cap[3]->UnitsExp                 = 0
+
+pp_data->cap[4]->UsagePage                    = 0xFFA0
+pp_data->cap[4]->ReportID                     = 0x14
+pp_data->cap[4]->BitPosition                  = 1
+pp_data->cap[4]->BitSize                      = 1
+pp_data->cap[4]->ReportCount                  = 1
+pp_data->cap[4]->BytePosition                 = 0x0001
+pp_data->cap[4]->BitCount                     = 1
+pp_data->cap[4]->BitField                     = 0x06
+pp_data->cap[4]->NextBytePosition             = 0x0002
+pp_data->cap[4]->LinkCollection               = 0x0000
+pp_data->cap[4]->LinkUsagePage                = 0xFFA0
+pp_data->cap[4]->LinkUsage                    = 0x0003
+pp_data->cap[4]->IsMultipleItemsForArray      = 0
+pp_data->cap[4]->IsButtonCap                  = 1
+pp_data->cap[4]->IsPadding                    = 0
+pp_data->cap[4]->IsAbsolute                   = 0
+pp_data->cap[4]->IsRange                      = 0
+pp_data->cap[4]->IsAlias                      = 0
+pp_data->cap[4]->IsStringRange                = 0
+pp_data->cap[4]->IsDesignatorRange            = 0
+pp_data->cap[4]->Reserved1                    = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[4]->NotRange.Usage                        = 0x00B2
+pp_data->cap[4]->NotRange.Reserved1                    = 0x00B2
+pp_data->cap[4]->NotRange.StringIndex                  = 0
+pp_data->cap[4]->NotRange.Reserved2                    = 0
+pp_data->cap[4]->NotRange.DesignatorIndex              = 0
+pp_data->cap[4]->NotRange.Reserved3                    = 0
+pp_data->cap[4]->NotRange.DataIndex                    = 4
+pp_data->cap[4]->NotRange.Reserved4                    = 4
+pp_data->cap[4]->Button.LogicalMin                   = 0
+pp_data->cap[4]->Button.LogicalMax                   = 0
+pp_data->cap[4]->Units                    = 0
+pp_data->cap[4]->UnitsExp                 = 0
+
+pp_data->cap[5]->UsagePage                    = 0xFFA0
+pp_data->cap[5]->ReportID                     = 0x14
+pp_data->cap[5]->BitPosition                  = 0
+pp_data->cap[5]->BitSize                      = 1
+pp_data->cap[5]->ReportCount                  = 1
+pp_data->cap[5]->BytePosition                 = 0x0001
+pp_data->cap[5]->BitCount                     = 1
+pp_data->cap[5]->BitField                     = 0x06
+pp_data->cap[5]->NextBytePosition             = 0x0002
+pp_data->cap[5]->LinkCollection               = 0x0000
+pp_data->cap[5]->LinkUsagePage                = 0xFFA0
+pp_data->cap[5]->LinkUsage                    = 0x0003
+pp_data->cap[5]->IsMultipleItemsForArray      = 0
+pp_data->cap[5]->IsButtonCap                  = 1
+pp_data->cap[5]->IsPadding                    = 0
+pp_data->cap[5]->IsAbsolute                   = 0
+pp_data->cap[5]->IsRange                      = 0
+pp_data->cap[5]->IsAlias                      = 0
+pp_data->cap[5]->IsStringRange                = 0
+pp_data->cap[5]->IsDesignatorRange            = 0
+pp_data->cap[5]->Reserved1                    = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[5]->NotRange.Usage                        = 0x00B1
+pp_data->cap[5]->NotRange.Reserved1                    = 0x00B1
+pp_data->cap[5]->NotRange.StringIndex                  = 0
+pp_data->cap[5]->NotRange.Reserved2                    = 0
+pp_data->cap[5]->NotRange.DesignatorIndex              = 0
+pp_data->cap[5]->NotRange.Reserved3                    = 0
+pp_data->cap[5]->NotRange.DataIndex                    = 5
+pp_data->cap[5]->NotRange.Reserved4                    = 5
+pp_data->cap[5]->Button.LogicalMin                   = 0
+pp_data->cap[5]->Button.LogicalMax                   = 0
+pp_data->cap[5]->Units                    = 0
+pp_data->cap[5]->UnitsExp                 = 0
+
+pp_data->cap[6]->UsagePage                    = 0xFFA0
+pp_data->cap[6]->ReportID                     = 0x15
+pp_data->cap[6]->BitPosition                  = 0
+pp_data->cap[6]->BitSize                      = 16
+pp_data->cap[6]->ReportCount                  = 1
+pp_data->cap[6]->BytePosition                 = 0x0001
+pp_data->cap[6]->BitCount                     = 16
+pp_data->cap[6]->BitField                     = 0x22
+pp_data->cap[6]->NextBytePosition             = 0x0003
+pp_data->cap[6]->LinkCollection               = 0x0000
+pp_data->cap[6]->LinkUsagePage                = 0xFFA0
+pp_data->cap[6]->LinkUsage                    = 0x0003
+pp_data->cap[6]->IsMultipleItemsForArray      = 0
+pp_data->cap[6]->IsButtonCap                  = 0
+pp_data->cap[6]->IsPadding                    = 0
+pp_data->cap[6]->IsAbsolute                   = 1
+pp_data->cap[6]->IsRange                      = 0
+pp_data->cap[6]->IsAlias                      = 0
+pp_data->cap[6]->IsStringRange                = 0
+pp_data->cap[6]->IsDesignatorRange            = 0
+pp_data->cap[6]->Reserved1                    = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[6]->NotRange.Usage                        = 0x008C
+pp_data->cap[6]->NotRange.Reserved1                    = 0x008C
+pp_data->cap[6]->NotRange.StringIndex                  = 0
+pp_data->cap[6]->NotRange.Reserved2                    = 0
+pp_data->cap[6]->NotRange.DesignatorIndex              = 0
+pp_data->cap[6]->NotRange.Reserved3                    = 0
+pp_data->cap[6]->NotRange.DataIndex                    = 6
+pp_data->cap[6]->NotRange.Reserved4                    = 6
+pp_data->cap[6]->NotButton.HasNull                   = 0
+pp_data->cap[6]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[6]->NotButton.LogicalMin                = 0
+pp_data->cap[6]->NotButton.LogicalMax                = 65535
+pp_data->cap[6]->NotButton.PhysicalMin               = 0
+pp_data->cap[6]->NotButton.PhysicalMax               = 0
+pp_data->cap[6]->Units                    = 0
+pp_data->cap[6]->UnitsExp                 = 0
+
+pp_data->cap[7]->UsagePage                    = 0xFFA0
+pp_data->cap[7]->ReportID                     = 0x1F
+pp_data->cap[7]->BitPosition                  = 0
+pp_data->cap[7]->BitSize                      = 1
+pp_data->cap[7]->ReportCount                  = 1
+pp_data->cap[7]->BytePosition                 = 0x0001
+pp_data->cap[7]->BitCount                     = 1
+pp_data->cap[7]->BitField                     = 0x06
+pp_data->cap[7]->NextBytePosition             = 0x0002
+pp_data->cap[7]->LinkCollection               = 0x0000
+pp_data->cap[7]->LinkUsagePage                = 0xFFA0
+pp_data->cap[7]->LinkUsage                    = 0x0003
+pp_data->cap[7]->IsMultipleItemsForArray      = 0
+pp_data->cap[7]->IsButtonCap                  = 1
+pp_data->cap[7]->IsPadding                    = 0
+pp_data->cap[7]->IsAbsolute                   = 0
+pp_data->cap[7]->IsRange                      = 0
+pp_data->cap[7]->IsAlias                      = 0
+pp_data->cap[7]->IsStringRange                = 0
+pp_data->cap[7]->IsDesignatorRange            = 0
+pp_data->cap[7]->Reserved1                    = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[7]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[7]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[7]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[7]->NotRange.Usage                        = 0x009C
+pp_data->cap[7]->NotRange.Reserved1                    = 0x009C
+pp_data->cap[7]->NotRange.StringIndex                  = 0
+pp_data->cap[7]->NotRange.Reserved2                    = 0
+pp_data->cap[7]->NotRange.DesignatorIndex              = 0
+pp_data->cap[7]->NotRange.Reserved3                    = 0
+pp_data->cap[7]->NotRange.DataIndex                    = 7
+pp_data->cap[7]->NotRange.Reserved4                    = 7
+pp_data->cap[7]->Button.LogicalMin                   = 0
+pp_data->cap[7]->Button.LogicalMax                   = 0
+pp_data->cap[7]->Units                    = 0
+pp_data->cap[7]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[8]->UsagePage                    = 0xFFA0
+pp_data->cap[8]->ReportID                     = 0x03
+pp_data->cap[8]->BitPosition                  = 0
+pp_data->cap[8]->BitSize                      = 8
+pp_data->cap[8]->ReportCount                  = 32
+pp_data->cap[8]->BytePosition                 = 0x0001
+pp_data->cap[8]->BitCount                     = 256
+pp_data->cap[8]->BitField                     = 0x02
+pp_data->cap[8]->NextBytePosition             = 0x0021
+pp_data->cap[8]->LinkCollection               = 0x0000
+pp_data->cap[8]->LinkUsagePage                = 0xFFA0
+pp_data->cap[8]->LinkUsage                    = 0x0003
+pp_data->cap[8]->IsMultipleItemsForArray      = 0
+pp_data->cap[8]->IsButtonCap                  = 0
+pp_data->cap[8]->IsPadding                    = 0
+pp_data->cap[8]->IsAbsolute                   = 1
+pp_data->cap[8]->IsRange                      = 0
+pp_data->cap[8]->IsAlias                      = 0
+pp_data->cap[8]->IsStringRange                = 0
+pp_data->cap[8]->IsDesignatorRange            = 0
+pp_data->cap[8]->Reserved1                    = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[8]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[8]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[8]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[8]->NotRange.Usage                        = 0x0030
+pp_data->cap[8]->NotRange.Reserved1                    = 0x0030
+pp_data->cap[8]->NotRange.StringIndex                  = 0
+pp_data->cap[8]->NotRange.Reserved2                    = 0
+pp_data->cap[8]->NotRange.DesignatorIndex              = 0
+pp_data->cap[8]->NotRange.Reserved3                    = 0
+pp_data->cap[8]->NotRange.DataIndex                    = 0
+pp_data->cap[8]->NotRange.Reserved4                    = 0
+pp_data->cap[8]->NotButton.HasNull                   = 0
+pp_data->cap[8]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[8]->NotButton.LogicalMin                = 0
+pp_data->cap[8]->NotButton.LogicalMax                = 1
+pp_data->cap[8]->NotButton.PhysicalMin               = 0
+pp_data->cap[8]->NotButton.PhysicalMax               = 0
+pp_data->cap[8]->Units                    = 0
+pp_data->cap[8]->UnitsExp                 = 0
+
+pp_data->cap[9]->UsagePage                    = 0xFFA0
+pp_data->cap[9]->ReportID                     = 0x19
+pp_data->cap[9]->BitPosition                  = 3
+pp_data->cap[9]->BitSize                      = 1
+pp_data->cap[9]->ReportCount                  = 1
+pp_data->cap[9]->BytePosition                 = 0x0001
+pp_data->cap[9]->BitCount                     = 1
+pp_data->cap[9]->BitField                     = 0x22
+pp_data->cap[9]->NextBytePosition             = 0x0002
+pp_data->cap[9]->LinkCollection               = 0x0000
+pp_data->cap[9]->LinkUsagePage                = 0xFFA0
+pp_data->cap[9]->LinkUsage                    = 0x0003
+pp_data->cap[9]->IsMultipleItemsForArray      = 0
+pp_data->cap[9]->IsButtonCap                  = 1
+pp_data->cap[9]->IsPadding                    = 0
+pp_data->cap[9]->IsAbsolute                   = 1
+pp_data->cap[9]->IsRange                      = 0
+pp_data->cap[9]->IsAlias                      = 0
+pp_data->cap[9]->IsStringRange                = 0
+pp_data->cap[9]->IsDesignatorRange            = 0
+pp_data->cap[9]->Reserved1                    = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[9]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[9]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[9]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[9]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[9]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[9]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[9]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[9]->NotRange.Usage                        = 0x00DC
+pp_data->cap[9]->NotRange.Reserved1                    = 0x00DC
+pp_data->cap[9]->NotRange.StringIndex                  = 0
+pp_data->cap[9]->NotRange.Reserved2                    = 0
+pp_data->cap[9]->NotRange.DesignatorIndex              = 0
+pp_data->cap[9]->NotRange.Reserved3                    = 0
+pp_data->cap[9]->NotRange.DataIndex                    = 1
+pp_data->cap[9]->NotRange.Reserved4                    = 1
+pp_data->cap[9]->Button.LogicalMin                   = 0
+pp_data->cap[9]->Button.LogicalMax                   = 0
+pp_data->cap[9]->Units                    = 0
+pp_data->cap[9]->UnitsExp                 = 0
+
+pp_data->cap[10]->UsagePage                    = 0xFFA0
+pp_data->cap[10]->ReportID                     = 0x19
+pp_data->cap[10]->BitPosition                  = 2
+pp_data->cap[10]->BitSize                      = 1
+pp_data->cap[10]->ReportCount                  = 1
+pp_data->cap[10]->BytePosition                 = 0x0001
+pp_data->cap[10]->BitCount                     = 1
+pp_data->cap[10]->BitField                     = 0x22
+pp_data->cap[10]->NextBytePosition             = 0x0002
+pp_data->cap[10]->LinkCollection               = 0x0000
+pp_data->cap[10]->LinkUsagePage                = 0xFFA0
+pp_data->cap[10]->LinkUsage                    = 0x0003
+pp_data->cap[10]->IsMultipleItemsForArray      = 0
+pp_data->cap[10]->IsButtonCap                  = 1
+pp_data->cap[10]->IsPadding                    = 0
+pp_data->cap[10]->IsAbsolute                   = 1
+pp_data->cap[10]->IsRange                      = 0
+pp_data->cap[10]->IsAlias                      = 0
+pp_data->cap[10]->IsStringRange                = 0
+pp_data->cap[10]->IsDesignatorRange            = 0
+pp_data->cap[10]->Reserved1                    = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[10]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[10]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[10]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[10]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[10]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[10]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[10]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[10]->NotRange.Usage                        = 0x009E
+pp_data->cap[10]->NotRange.Reserved1                    = 0x009E
+pp_data->cap[10]->NotRange.StringIndex                  = 0
+pp_data->cap[10]->NotRange.Reserved2                    = 0
+pp_data->cap[10]->NotRange.DesignatorIndex              = 0
+pp_data->cap[10]->NotRange.Reserved3                    = 0
+pp_data->cap[10]->NotRange.DataIndex                    = 2
+pp_data->cap[10]->NotRange.Reserved4                    = 2
+pp_data->cap[10]->Button.LogicalMin                   = 0
+pp_data->cap[10]->Button.LogicalMax                   = 0
+pp_data->cap[10]->Units                    = 0
+pp_data->cap[10]->UnitsExp                 = 0
+
+pp_data->cap[11]->UsagePage                    = 0xFFA0
+pp_data->cap[11]->ReportID                     = 0x19
+pp_data->cap[11]->BitPosition                  = 1
+pp_data->cap[11]->BitSize                      = 1
+pp_data->cap[11]->ReportCount                  = 1
+pp_data->cap[11]->BytePosition                 = 0x0001
+pp_data->cap[11]->BitCount                     = 1
+pp_data->cap[11]->BitField                     = 0x22
+pp_data->cap[11]->NextBytePosition             = 0x0002
+pp_data->cap[11]->LinkCollection               = 0x0000
+pp_data->cap[11]->LinkUsagePage                = 0xFFA0
+pp_data->cap[11]->LinkUsage                    = 0x0003
+pp_data->cap[11]->IsMultipleItemsForArray      = 0
+pp_data->cap[11]->IsButtonCap                  = 1
+pp_data->cap[11]->IsPadding                    = 0
+pp_data->cap[11]->IsAbsolute                   = 1
+pp_data->cap[11]->IsRange                      = 0
+pp_data->cap[11]->IsAlias                      = 0
+pp_data->cap[11]->IsStringRange                = 0
+pp_data->cap[11]->IsDesignatorRange            = 0
+pp_data->cap[11]->Reserved1                    = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[11]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[11]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[11]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[11]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[11]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[11]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[11]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[11]->NotRange.Usage                        = 0x008F
+pp_data->cap[11]->NotRange.Reserved1                    = 0x008F
+pp_data->cap[11]->NotRange.StringIndex                  = 0
+pp_data->cap[11]->NotRange.Reserved2                    = 0
+pp_data->cap[11]->NotRange.DesignatorIndex              = 0
+pp_data->cap[11]->NotRange.Reserved3                    = 0
+pp_data->cap[11]->NotRange.DataIndex                    = 3
+pp_data->cap[11]->NotRange.Reserved4                    = 3
+pp_data->cap[11]->Button.LogicalMin                   = 0
+pp_data->cap[11]->Button.LogicalMax                   = 0
+pp_data->cap[11]->Units                    = 0
+pp_data->cap[11]->UnitsExp                 = 0
+
+pp_data->cap[12]->UsagePage                    = 0xFFA0
+pp_data->cap[12]->ReportID                     = 0x19
+pp_data->cap[12]->BitPosition                  = 0
+pp_data->cap[12]->BitSize                      = 1
+pp_data->cap[12]->ReportCount                  = 1
+pp_data->cap[12]->BytePosition                 = 0x0001
+pp_data->cap[12]->BitCount                     = 1
+pp_data->cap[12]->BitField                     = 0x22
+pp_data->cap[12]->NextBytePosition             = 0x0002
+pp_data->cap[12]->LinkCollection               = 0x0000
+pp_data->cap[12]->LinkUsagePage                = 0xFFA0
+pp_data->cap[12]->LinkUsage                    = 0x0003
+pp_data->cap[12]->IsMultipleItemsForArray      = 0
+pp_data->cap[12]->IsButtonCap                  = 1
+pp_data->cap[12]->IsPadding                    = 0
+pp_data->cap[12]->IsAbsolute                   = 1
+pp_data->cap[12]->IsRange                      = 0
+pp_data->cap[12]->IsAlias                      = 0
+pp_data->cap[12]->IsStringRange                = 0
+pp_data->cap[12]->IsDesignatorRange            = 0
+pp_data->cap[12]->Reserved1                    = 0x000000
+pp_data->cap[12]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[12]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[12]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[12]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[12]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[12]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[12]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[12]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[12]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[12]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[12]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[12]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[12]->NotRange.Usage                        = 0x008D
+pp_data->cap[12]->NotRange.Reserved1                    = 0x008D
+pp_data->cap[12]->NotRange.StringIndex                  = 0
+pp_data->cap[12]->NotRange.Reserved2                    = 0
+pp_data->cap[12]->NotRange.DesignatorIndex              = 0
+pp_data->cap[12]->NotRange.Reserved3                    = 0
+pp_data->cap[12]->NotRange.DataIndex                    = 4
+pp_data->cap[12]->NotRange.Reserved4                    = 4
+pp_data->cap[12]->Button.LogicalMin                   = 0
+pp_data->cap[12]->Button.LogicalMax                   = 0
+pp_data->cap[12]->Units                    = 0
+pp_data->cap[12]->UnitsExp                 = 0
+
+pp_data->cap[13]->UsagePage                    = 0xFFA0
+pp_data->cap[13]->ReportID                     = 0x19
+pp_data->cap[13]->BitPosition                  = 5
+pp_data->cap[13]->BitSize                      = 1
+pp_data->cap[13]->ReportCount                  = 1
+pp_data->cap[13]->BytePosition                 = 0x0001
+pp_data->cap[13]->BitCount                     = 1
+pp_data->cap[13]->BitField                     = 0x06
+pp_data->cap[13]->NextBytePosition             = 0x0002
+pp_data->cap[13]->LinkCollection               = 0x0000
+pp_data->cap[13]->LinkUsagePage                = 0xFFA0
+pp_data->cap[13]->LinkUsage                    = 0x0003
+pp_data->cap[13]->IsMultipleItemsForArray      = 0
+pp_data->cap[13]->IsButtonCap                  = 1
+pp_data->cap[13]->IsPadding                    = 0
+pp_data->cap[13]->IsAbsolute                   = 0
+pp_data->cap[13]->IsRange                      = 0
+pp_data->cap[13]->IsAlias                      = 0
+pp_data->cap[13]->IsStringRange                = 0
+pp_data->cap[13]->IsDesignatorRange            = 0
+pp_data->cap[13]->Reserved1                    = 0x000000
+pp_data->cap[13]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[13]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[13]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[13]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[13]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[13]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[13]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[13]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[13]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[13]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[13]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[13]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[13]->NotRange.Usage                        = 0x00D9
+pp_data->cap[13]->NotRange.Reserved1                    = 0x00D9
+pp_data->cap[13]->NotRange.StringIndex                  = 0
+pp_data->cap[13]->NotRange.Reserved2                    = 0
+pp_data->cap[13]->NotRange.DesignatorIndex              = 0
+pp_data->cap[13]->NotRange.Reserved3                    = 0
+pp_data->cap[13]->NotRange.DataIndex                    = 5
+pp_data->cap[13]->NotRange.Reserved4                    = 5
+pp_data->cap[13]->Button.LogicalMin                   = 0
+pp_data->cap[13]->Button.LogicalMax                   = 0
+pp_data->cap[13]->Units                    = 0
+pp_data->cap[13]->UnitsExp                 = 0
+
+pp_data->cap[14]->UsagePage                    = 0xFFA0
+pp_data->cap[14]->ReportID                     = 0x19
+pp_data->cap[14]->BitPosition                  = 4
+pp_data->cap[14]->BitSize                      = 1
+pp_data->cap[14]->ReportCount                  = 1
+pp_data->cap[14]->BytePosition                 = 0x0001
+pp_data->cap[14]->BitCount                     = 1
+pp_data->cap[14]->BitField                     = 0x06
+pp_data->cap[14]->NextBytePosition             = 0x0002
+pp_data->cap[14]->LinkCollection               = 0x0000
+pp_data->cap[14]->LinkUsagePage                = 0xFFA0
+pp_data->cap[14]->LinkUsage                    = 0x0003
+pp_data->cap[14]->IsMultipleItemsForArray      = 0
+pp_data->cap[14]->IsButtonCap                  = 1
+pp_data->cap[14]->IsPadding                    = 0
+pp_data->cap[14]->IsAbsolute                   = 0
+pp_data->cap[14]->IsRange                      = 0
+pp_data->cap[14]->IsAlias                      = 0
+pp_data->cap[14]->IsStringRange                = 0
+pp_data->cap[14]->IsDesignatorRange            = 0
+pp_data->cap[14]->Reserved1                    = 0x000000
+pp_data->cap[14]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[14]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[14]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[14]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[14]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[14]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[14]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[14]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[14]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[14]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[14]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[14]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[14]->NotRange.Usage                        = 0x00D2
+pp_data->cap[14]->NotRange.Reserved1                    = 0x00D2
+pp_data->cap[14]->NotRange.StringIndex                  = 0
+pp_data->cap[14]->NotRange.Reserved2                    = 0
+pp_data->cap[14]->NotRange.DesignatorIndex              = 0
+pp_data->cap[14]->NotRange.Reserved3                    = 0
+pp_data->cap[14]->NotRange.DataIndex                    = 6
+pp_data->cap[14]->NotRange.Reserved4                    = 6
+pp_data->cap[14]->Button.LogicalMin                   = 0
+pp_data->cap[14]->Button.LogicalMax                   = 0
+pp_data->cap[14]->Units                    = 0
+pp_data->cap[14]->UnitsExp                 = 0
+
+pp_data->cap[15]->UsagePage                    = 0xFFA0
+pp_data->cap[15]->ReportID                     = 0x1A
+pp_data->cap[15]->BitPosition                  = 0
+pp_data->cap[15]->BitSize                      = 1
+pp_data->cap[15]->ReportCount                  = 1
+pp_data->cap[15]->BytePosition                 = 0x0001
+pp_data->cap[15]->BitCount                     = 1
+pp_data->cap[15]->BitField                     = 0x22
+pp_data->cap[15]->NextBytePosition             = 0x0002
+pp_data->cap[15]->LinkCollection               = 0x0000
+pp_data->cap[15]->LinkUsagePage                = 0xFFA0
+pp_data->cap[15]->LinkUsage                    = 0x0003
+pp_data->cap[15]->IsMultipleItemsForArray      = 0
+pp_data->cap[15]->IsButtonCap                  = 1
+pp_data->cap[15]->IsPadding                    = 0
+pp_data->cap[15]->IsAbsolute                   = 1
+pp_data->cap[15]->IsRange                      = 0
+pp_data->cap[15]->IsAlias                      = 0
+pp_data->cap[15]->IsStringRange                = 0
+pp_data->cap[15]->IsDesignatorRange            = 0
+pp_data->cap[15]->Reserved1                    = 0x000000
+pp_data->cap[15]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[15]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[15]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[15]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[15]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[15]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[15]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[15]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[15]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[15]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[15]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[15]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[15]->NotRange.Usage                        = 0x00B5
+pp_data->cap[15]->NotRange.Reserved1                    = 0x00B5
+pp_data->cap[15]->NotRange.StringIndex                  = 0
+pp_data->cap[15]->NotRange.Reserved2                    = 0
+pp_data->cap[15]->NotRange.DesignatorIndex              = 0
+pp_data->cap[15]->NotRange.Reserved3                    = 0
+pp_data->cap[15]->NotRange.DataIndex                    = 7
+pp_data->cap[15]->NotRange.Reserved4                    = 7
+pp_data->cap[15]->Button.LogicalMin                   = 0
+pp_data->cap[15]->Button.LogicalMax                   = 0
+pp_data->cap[15]->Units                    = 0
+pp_data->cap[15]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+pp_data->cap[16]->UsagePage                    = 0xFFA0
+pp_data->cap[16]->ReportID                     = 0x1B
+pp_data->cap[16]->BitPosition                  = 1
+pp_data->cap[16]->BitSize                      = 1
+pp_data->cap[16]->ReportCount                  = 1
+pp_data->cap[16]->BytePosition                 = 0x0001
+pp_data->cap[16]->BitCount                     = 1
+pp_data->cap[16]->BitField                     = 0x22
+pp_data->cap[16]->NextBytePosition             = 0x0002
+pp_data->cap[16]->LinkCollection               = 0x0000
+pp_data->cap[16]->LinkUsagePage                = 0xFFA0
+pp_data->cap[16]->LinkUsage                    = 0x0003
+pp_data->cap[16]->IsMultipleItemsForArray      = 0
+pp_data->cap[16]->IsButtonCap                  = 1
+pp_data->cap[16]->IsPadding                    = 0
+pp_data->cap[16]->IsAbsolute                   = 1
+pp_data->cap[16]->IsRange                      = 0
+pp_data->cap[16]->IsAlias                      = 0
+pp_data->cap[16]->IsStringRange                = 0
+pp_data->cap[16]->IsDesignatorRange            = 0
+pp_data->cap[16]->Reserved1                    = 0x000000
+pp_data->cap[16]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[16]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[16]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[16]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[16]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[16]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[16]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[16]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[16]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[16]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[16]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[16]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[16]->NotRange.Usage                        = 0x00B5
+pp_data->cap[16]->NotRange.Reserved1                    = 0x00B5
+pp_data->cap[16]->NotRange.StringIndex                  = 0
+pp_data->cap[16]->NotRange.Reserved2                    = 0
+pp_data->cap[16]->NotRange.DesignatorIndex              = 0
+pp_data->cap[16]->NotRange.Reserved3                    = 0
+pp_data->cap[16]->NotRange.DataIndex                    = 0
+pp_data->cap[16]->NotRange.Reserved4                    = 0
+pp_data->cap[16]->Button.LogicalMin                   = 0
+pp_data->cap[16]->Button.LogicalMax                   = 0
+pp_data->cap[16]->Units                    = 0
+pp_data->cap[16]->UnitsExp                 = 0
+
+pp_data->cap[17]->UsagePage                    = 0xFFA0
+pp_data->cap[17]->ReportID                     = 0x1B
+pp_data->cap[17]->BitPosition                  = 0
+pp_data->cap[17]->BitSize                      = 1
+pp_data->cap[17]->ReportCount                  = 1
+pp_data->cap[17]->BytePosition                 = 0x0001
+pp_data->cap[17]->BitCount                     = 1
+pp_data->cap[17]->BitField                     = 0x22
+pp_data->cap[17]->NextBytePosition             = 0x0002
+pp_data->cap[17]->LinkCollection               = 0x0000
+pp_data->cap[17]->LinkUsagePage                = 0xFFA0
+pp_data->cap[17]->LinkUsage                    = 0x0003
+pp_data->cap[17]->IsMultipleItemsForArray      = 0
+pp_data->cap[17]->IsButtonCap                  = 1
+pp_data->cap[17]->IsPadding                    = 0
+pp_data->cap[17]->IsAbsolute                   = 1
+pp_data->cap[17]->IsRange                      = 0
+pp_data->cap[17]->IsAlias                      = 0
+pp_data->cap[17]->IsStringRange                = 0
+pp_data->cap[17]->IsDesignatorRange            = 0
+pp_data->cap[17]->Reserved1                    = 0x000000
+pp_data->cap[17]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[17]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[17]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[17]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[17]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[17]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[17]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[17]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[17]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[17]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[17]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[17]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[17]->NotRange.Usage                        = 0x00CF
+pp_data->cap[17]->NotRange.Reserved1                    = 0x00CF
+pp_data->cap[17]->NotRange.StringIndex                  = 0
+pp_data->cap[17]->NotRange.Reserved2                    = 0
+pp_data->cap[17]->NotRange.DesignatorIndex              = 0
+pp_data->cap[17]->NotRange.Reserved3                    = 0
+pp_data->cap[17]->NotRange.DataIndex                    = 1
+pp_data->cap[17]->NotRange.Reserved4                    = 1
+pp_data->cap[17]->Button.LogicalMin                   = 0
+pp_data->cap[17]->Button.LogicalMax                   = 0
+pp_data->cap[17]->Units                    = 0
+pp_data->cap[17]->UnitsExp                 = 0
+
+pp_data->cap[18]->UsagePage                    = 0xFFA0
+pp_data->cap[18]->ReportID                     = 0x1B
+pp_data->cap[18]->BitPosition                  = 2
+pp_data->cap[18]->BitSize                      = 1
+pp_data->cap[18]->ReportCount                  = 1
+pp_data->cap[18]->BytePosition                 = 0x0001
+pp_data->cap[18]->BitCount                     = 1
+pp_data->cap[18]->BitField                     = 0x23
+pp_data->cap[18]->NextBytePosition             = 0x0002
+pp_data->cap[18]->LinkCollection               = 0x0000
+pp_data->cap[18]->LinkUsagePage                = 0xFFA0
+pp_data->cap[18]->LinkUsage                    = 0x0003
+pp_data->cap[18]->IsMultipleItemsForArray      = 0
+pp_data->cap[18]->IsButtonCap                  = 1
+pp_data->cap[18]->IsPadding                    = 1
+pp_data->cap[18]->IsAbsolute                   = 1
+pp_data->cap[18]->IsRange                      = 0
+pp_data->cap[18]->IsAlias                      = 0
+pp_data->cap[18]->IsStringRange                = 0
+pp_data->cap[18]->IsDesignatorRange            = 0
+pp_data->cap[18]->Reserved1                    = 0x000000
+pp_data->cap[18]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[18]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[18]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[18]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[18]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[18]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[18]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[18]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[18]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[18]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[18]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[18]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[18]->NotRange.Usage                        = 0x00DE
+pp_data->cap[18]->NotRange.Reserved1                    = 0x00DE
+pp_data->cap[18]->NotRange.StringIndex                  = 0
+pp_data->cap[18]->NotRange.Reserved2                    = 0
+pp_data->cap[18]->NotRange.DesignatorIndex              = 0
+pp_data->cap[18]->NotRange.Reserved3                    = 0
+pp_data->cap[18]->NotRange.DataIndex                    = 2
+pp_data->cap[18]->NotRange.Reserved4                    = 2
+pp_data->cap[18]->Button.LogicalMin                   = 0
+pp_data->cap[18]->Button.LogicalMax                   = 0
+pp_data->cap[18]->Units                    = 0
+pp_data->cap[18]->UnitsExp                 = 0
+
+pp_data->cap[19]->UsagePage                    = 0xFFA0
+pp_data->cap[19]->ReportID                     = 0x1B
+pp_data->cap[19]->BitPosition                  = 3
+pp_data->cap[19]->BitSize                      = 1
+pp_data->cap[19]->ReportCount                  = 1
+pp_data->cap[19]->BytePosition                 = 0x0001
+pp_data->cap[19]->BitCount                     = 1
+pp_data->cap[19]->BitField                     = 0x22
+pp_data->cap[19]->NextBytePosition             = 0x0002
+pp_data->cap[19]->LinkCollection               = 0x0000
+pp_data->cap[19]->LinkUsagePage                = 0xFFA0
+pp_data->cap[19]->LinkUsage                    = 0x0003
+pp_data->cap[19]->IsMultipleItemsForArray      = 0
+pp_data->cap[19]->IsButtonCap                  = 1
+pp_data->cap[19]->IsPadding                    = 0
+pp_data->cap[19]->IsAbsolute                   = 1
+pp_data->cap[19]->IsRange                      = 0
+pp_data->cap[19]->IsAlias                      = 0
+pp_data->cap[19]->IsStringRange                = 0
+pp_data->cap[19]->IsDesignatorRange            = 0
+pp_data->cap[19]->Reserved1                    = 0x000000
+pp_data->cap[19]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[19]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[19]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[19]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[19]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[19]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[19]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[19]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[19]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[19]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[19]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[19]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[19]->NotRange.Usage                        = 0x00D8
+pp_data->cap[19]->NotRange.Reserved1                    = 0x00D8
+pp_data->cap[19]->NotRange.StringIndex                  = 0
+pp_data->cap[19]->NotRange.Reserved2                    = 0
+pp_data->cap[19]->NotRange.DesignatorIndex              = 0
+pp_data->cap[19]->NotRange.Reserved3                    = 0
+pp_data->cap[19]->NotRange.DataIndex                    = 3
+pp_data->cap[19]->NotRange.Reserved4                    = 3
+pp_data->cap[19]->Button.LogicalMin                   = 0
+pp_data->cap[19]->Button.LogicalMax                   = 0
+pp_data->cap[19]->Units                    = 0
+pp_data->cap[19]->UnitsExp                 = 0
+
+pp_data->cap[20]->UsagePage                    = 0xFFA0
+pp_data->cap[20]->ReportID                     = 0x1B
+pp_data->cap[20]->BitPosition                  = 5
+pp_data->cap[20]->BitSize                      = 1
+pp_data->cap[20]->ReportCount                  = 1
+pp_data->cap[20]->BytePosition                 = 0x0002
+pp_data->cap[20]->BitCount                     = 1
+pp_data->cap[20]->BitField                     = 0x22
+pp_data->cap[20]->NextBytePosition             = 0x0003
+pp_data->cap[20]->LinkCollection               = 0x0000
+pp_data->cap[20]->LinkUsagePage                = 0xFFA0
+pp_data->cap[20]->LinkUsage                    = 0x0003
+pp_data->cap[20]->IsMultipleItemsForArray      = 0
+pp_data->cap[20]->IsButtonCap                  = 1
+pp_data->cap[20]->IsPadding                    = 0
+pp_data->cap[20]->IsAbsolute                   = 1
+pp_data->cap[20]->IsRange                      = 0
+pp_data->cap[20]->IsAlias                      = 0
+pp_data->cap[20]->IsStringRange                = 0
+pp_data->cap[20]->IsDesignatorRange            = 0
+pp_data->cap[20]->Reserved1                    = 0x000000
+pp_data->cap[20]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[20]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[20]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[20]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[20]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[20]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[20]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[20]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[20]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[20]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[20]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[20]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[20]->NotRange.Usage                        = 0x002A
+pp_data->cap[20]->NotRange.Reserved1                    = 0x002A
+pp_data->cap[20]->NotRange.StringIndex                  = 0
+pp_data->cap[20]->NotRange.Reserved2                    = 0
+pp_data->cap[20]->NotRange.DesignatorIndex              = 0
+pp_data->cap[20]->NotRange.Reserved3                    = 0
+pp_data->cap[20]->NotRange.DataIndex                    = 4
+pp_data->cap[20]->NotRange.Reserved4                    = 4
+pp_data->cap[20]->Button.LogicalMin                   = 0
+pp_data->cap[20]->Button.LogicalMax                   = 0
+pp_data->cap[20]->Units                    = 0
+pp_data->cap[20]->UnitsExp                 = 0
+
+pp_data->cap[21]->UsagePage                    = 0xFFA0
+pp_data->cap[21]->ReportID                     = 0x1B
+pp_data->cap[21]->BitPosition                  = 4
+pp_data->cap[21]->BitSize                      = 1
+pp_data->cap[21]->ReportCount                  = 1
+pp_data->cap[21]->BytePosition                 = 0x0002
+pp_data->cap[21]->BitCount                     = 1
+pp_data->cap[21]->BitField                     = 0x22
+pp_data->cap[21]->NextBytePosition             = 0x0003
+pp_data->cap[21]->LinkCollection               = 0x0000
+pp_data->cap[21]->LinkUsagePage                = 0xFFA0
+pp_data->cap[21]->LinkUsage                    = 0x0003
+pp_data->cap[21]->IsMultipleItemsForArray      = 0
+pp_data->cap[21]->IsButtonCap                  = 1
+pp_data->cap[21]->IsPadding                    = 0
+pp_data->cap[21]->IsAbsolute                   = 1
+pp_data->cap[21]->IsRange                      = 0
+pp_data->cap[21]->IsAlias                      = 0
+pp_data->cap[21]->IsStringRange                = 0
+pp_data->cap[21]->IsDesignatorRange            = 0
+pp_data->cap[21]->Reserved1                    = 0x000000
+pp_data->cap[21]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[21]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[21]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[21]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[21]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[21]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[21]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[21]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[21]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[21]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[21]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[21]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[21]->NotRange.Usage                        = 0x0020
+pp_data->cap[21]->NotRange.Reserved1                    = 0x0020
+pp_data->cap[21]->NotRange.StringIndex                  = 0
+pp_data->cap[21]->NotRange.Reserved2                    = 0
+pp_data->cap[21]->NotRange.DesignatorIndex              = 0
+pp_data->cap[21]->NotRange.Reserved3                    = 0
+pp_data->cap[21]->NotRange.DataIndex                    = 5
+pp_data->cap[21]->NotRange.Reserved4                    = 5
+pp_data->cap[21]->Button.LogicalMin                   = 0
+pp_data->cap[21]->Button.LogicalMax                   = 0
+pp_data->cap[21]->Units                    = 0
+pp_data->cap[21]->UnitsExp                 = 0
+
+pp_data->cap[22]->UsagePage                    = 0xFFA0
+pp_data->cap[22]->ReportID                     = 0x1B
+pp_data->cap[22]->BitPosition                  = 3
+pp_data->cap[22]->BitSize                      = 1
+pp_data->cap[22]->ReportCount                  = 1
+pp_data->cap[22]->BytePosition                 = 0x0002
+pp_data->cap[22]->BitCount                     = 1
+pp_data->cap[22]->BitField                     = 0x22
+pp_data->cap[22]->NextBytePosition             = 0x0003
+pp_data->cap[22]->LinkCollection               = 0x0000
+pp_data->cap[22]->LinkUsagePage                = 0xFFA0
+pp_data->cap[22]->LinkUsage                    = 0x0003
+pp_data->cap[22]->IsMultipleItemsForArray      = 0
+pp_data->cap[22]->IsButtonCap                  = 1
+pp_data->cap[22]->IsPadding                    = 0
+pp_data->cap[22]->IsAbsolute                   = 1
+pp_data->cap[22]->IsRange                      = 0
+pp_data->cap[22]->IsAlias                      = 0
+pp_data->cap[22]->IsStringRange                = 0
+pp_data->cap[22]->IsDesignatorRange            = 0
+pp_data->cap[22]->Reserved1                    = 0x000000
+pp_data->cap[22]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[22]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[22]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[22]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[22]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[22]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[22]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[22]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[22]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[22]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[22]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[22]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[22]->NotRange.Usage                        = 0x001E
+pp_data->cap[22]->NotRange.Reserved1                    = 0x001E
+pp_data->cap[22]->NotRange.StringIndex                  = 0
+pp_data->cap[22]->NotRange.Reserved2                    = 0
+pp_data->cap[22]->NotRange.DesignatorIndex              = 0
+pp_data->cap[22]->NotRange.Reserved3                    = 0
+pp_data->cap[22]->NotRange.DataIndex                    = 6
+pp_data->cap[22]->NotRange.Reserved4                    = 6
+pp_data->cap[22]->Button.LogicalMin                   = 0
+pp_data->cap[22]->Button.LogicalMax                   = 0
+pp_data->cap[22]->Units                    = 0
+pp_data->cap[22]->UnitsExp                 = 0
+
+pp_data->cap[23]->UsagePage                    = 0xFFA0
+pp_data->cap[23]->ReportID                     = 0x1B
+pp_data->cap[23]->BitPosition                  = 2
+pp_data->cap[23]->BitSize                      = 1
+pp_data->cap[23]->ReportCount                  = 1
+pp_data->cap[23]->BytePosition                 = 0x0002
+pp_data->cap[23]->BitCount                     = 1
+pp_data->cap[23]->BitField                     = 0x22
+pp_data->cap[23]->NextBytePosition             = 0x0003
+pp_data->cap[23]->LinkCollection               = 0x0000
+pp_data->cap[23]->LinkUsagePage                = 0xFFA0
+pp_data->cap[23]->LinkUsage                    = 0x0003
+pp_data->cap[23]->IsMultipleItemsForArray      = 0
+pp_data->cap[23]->IsButtonCap                  = 1
+pp_data->cap[23]->IsPadding                    = 0
+pp_data->cap[23]->IsAbsolute                   = 1
+pp_data->cap[23]->IsRange                      = 0
+pp_data->cap[23]->IsAlias                      = 0
+pp_data->cap[23]->IsStringRange                = 0
+pp_data->cap[23]->IsDesignatorRange            = 0
+pp_data->cap[23]->Reserved1                    = 0x000000
+pp_data->cap[23]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[23]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[23]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[23]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[23]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[23]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[23]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[23]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[23]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[23]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[23]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[23]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[23]->NotRange.Usage                        = 0x0018
+pp_data->cap[23]->NotRange.Reserved1                    = 0x0018
+pp_data->cap[23]->NotRange.StringIndex                  = 0
+pp_data->cap[23]->NotRange.Reserved2                    = 0
+pp_data->cap[23]->NotRange.DesignatorIndex              = 0
+pp_data->cap[23]->NotRange.Reserved3                    = 0
+pp_data->cap[23]->NotRange.DataIndex                    = 7
+pp_data->cap[23]->NotRange.Reserved4                    = 7
+pp_data->cap[23]->Button.LogicalMin                   = 0
+pp_data->cap[23]->Button.LogicalMax                   = 0
+pp_data->cap[23]->Units                    = 0
+pp_data->cap[23]->UnitsExp                 = 0
+
+pp_data->cap[24]->UsagePage                    = 0xFFA0
+pp_data->cap[24]->ReportID                     = 0x1B
+pp_data->cap[24]->BitPosition                  = 1
+pp_data->cap[24]->BitSize                      = 1
+pp_data->cap[24]->ReportCount                  = 1
+pp_data->cap[24]->BytePosition                 = 0x0002
+pp_data->cap[24]->BitCount                     = 1
+pp_data->cap[24]->BitField                     = 0x22
+pp_data->cap[24]->NextBytePosition             = 0x0003
+pp_data->cap[24]->LinkCollection               = 0x0000
+pp_data->cap[24]->LinkUsagePage                = 0xFFA0
+pp_data->cap[24]->LinkUsage                    = 0x0003
+pp_data->cap[24]->IsMultipleItemsForArray      = 0
+pp_data->cap[24]->IsButtonCap                  = 1
+pp_data->cap[24]->IsPadding                    = 0
+pp_data->cap[24]->IsAbsolute                   = 1
+pp_data->cap[24]->IsRange                      = 0
+pp_data->cap[24]->IsAlias                      = 0
+pp_data->cap[24]->IsStringRange                = 0
+pp_data->cap[24]->IsDesignatorRange            = 0
+pp_data->cap[24]->Reserved1                    = 0x000000
+pp_data->cap[24]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[24]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[24]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[24]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[24]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[24]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[24]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[24]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[24]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[24]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[24]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[24]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[24]->NotRange.Usage                        = 0x0017
+pp_data->cap[24]->NotRange.Reserved1                    = 0x0017
+pp_data->cap[24]->NotRange.StringIndex                  = 0
+pp_data->cap[24]->NotRange.Reserved2                    = 0
+pp_data->cap[24]->NotRange.DesignatorIndex              = 0
+pp_data->cap[24]->NotRange.Reserved3                    = 0
+pp_data->cap[24]->NotRange.DataIndex                    = 8
+pp_data->cap[24]->NotRange.Reserved4                    = 8
+pp_data->cap[24]->Button.LogicalMin                   = 0
+pp_data->cap[24]->Button.LogicalMax                   = 0
+pp_data->cap[24]->Units                    = 0
+pp_data->cap[24]->UnitsExp                 = 0
+
+pp_data->cap[25]->UsagePage                    = 0xFFA0
+pp_data->cap[25]->ReportID                     = 0x1B
+pp_data->cap[25]->BitPosition                  = 0
+pp_data->cap[25]->BitSize                      = 1
+pp_data->cap[25]->ReportCount                  = 1
+pp_data->cap[25]->BytePosition                 = 0x0002
+pp_data->cap[25]->BitCount                     = 1
+pp_data->cap[25]->BitField                     = 0x22
+pp_data->cap[25]->NextBytePosition             = 0x0003
+pp_data->cap[25]->LinkCollection               = 0x0000
+pp_data->cap[25]->LinkUsagePage                = 0xFFA0
+pp_data->cap[25]->LinkUsage                    = 0x0003
+pp_data->cap[25]->IsMultipleItemsForArray      = 0
+pp_data->cap[25]->IsButtonCap                  = 1
+pp_data->cap[25]->IsPadding                    = 0
+pp_data->cap[25]->IsAbsolute                   = 1
+pp_data->cap[25]->IsRange                      = 0
+pp_data->cap[25]->IsAlias                      = 0
+pp_data->cap[25]->IsStringRange                = 0
+pp_data->cap[25]->IsDesignatorRange            = 0
+pp_data->cap[25]->Reserved1                    = 0x000000
+pp_data->cap[25]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[25]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[25]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[25]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[25]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[25]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[25]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[25]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[25]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[25]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[25]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[25]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[25]->NotRange.Usage                        = 0x0009
+pp_data->cap[25]->NotRange.Reserved1                    = 0x0009
+pp_data->cap[25]->NotRange.StringIndex                  = 0
+pp_data->cap[25]->NotRange.Reserved2                    = 0
+pp_data->cap[25]->NotRange.DesignatorIndex              = 0
+pp_data->cap[25]->NotRange.Reserved3                    = 0
+pp_data->cap[25]->NotRange.DataIndex                    = 9
+pp_data->cap[25]->NotRange.Reserved4                    = 9
+pp_data->cap[25]->Button.LogicalMin                   = 0
+pp_data->cap[25]->Button.LogicalMax                   = 0
+pp_data->cap[25]->Units                    = 0
+pp_data->cap[25]->UnitsExp                 = 0
+
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0003
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0xFFA0
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/047F_C056_0003_FFA0_expected.rpt_desc b/src/hidapi/windows/test/data/047F_C056_0003_FFA0_expected.rpt_desc
new file mode 100644
index 0000000..ef059c4
--- /dev/null
+++ b/src/hidapi/windows/test/data/047F_C056_0003_FFA0_expected.rpt_desc
@@ -0,0 +1,24 @@
+0x06, 0xA0, 0xFF, 0x09, 0x03, 0xA1, 0x01, 0x85, 0x03, 0x09, 
+0x30, 0x15, 0x00, 0x25, 0x01, 0x75, 0x08, 0x95, 0x20, 0x81, 
+0x02, 0x85, 0x14, 0x09, 0xB1, 0x09, 0xB2, 0x09, 0xB5, 0x09, 
+0xB7, 0x09, 0xB3, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 
+0x05, 0x81, 0x06, 0x75, 0x03, 0x95, 0x01, 0x81, 0x03, 0x85, 
+0x15, 0x09, 0x8C, 0x15, 0x00, 0x27, 0xFF, 0xFF, 0x00, 0x00, 
+0x75, 0x10, 0x95, 0x01, 0x81, 0x22, 0x85, 0x1F, 0x09, 0x9C, 
+0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x01, 0x81, 0x06, 
+0x75, 0x07, 0x95, 0x01, 0x81, 0x03, 0x85, 0x03, 0x09, 0x30, 
+0x15, 0x00, 0x25, 0x01, 0x75, 0x08, 0x95, 0x20, 0x91, 0x02, 
+0x85, 0x19, 0x09, 0x8D, 0x09, 0x8F, 0x09, 0x9E, 0x09, 0xDC, 
+0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x04, 0x91, 0x22, 
+0x09, 0xD2, 0x09, 0xD9, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 
+0x95, 0x02, 0x91, 0x06, 0x75, 0x02, 0x95, 0x01, 0x91, 0x03, 
+0x85, 0x1A, 0x09, 0xB5, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 
+0x95, 0x01, 0x91, 0x22, 0x75, 0x07, 0x95, 0x01, 0x91, 0x03, 
+0x85, 0x1B, 0x09, 0xCF, 0x09, 0xB5, 0x15, 0x00, 0x25, 0x01, 
+0x75, 0x01, 0x95, 0x02, 0xB1, 0x22, 0x09, 0xDE, 0x15, 0x00, 
+0x25, 0x01, 0x75, 0x01, 0x95, 0x01, 0xB1, 0x23, 0x09, 0xD8, 
+0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x01, 0xB1, 0x22, 
+0x75, 0x04, 0x95, 0x01, 0xB1, 0x03, 0x09, 0x09, 0x09, 0x17, 
+0x09, 0x18, 0x09, 0x1E, 0x09, 0x20, 0x09, 0x2A, 0x15, 0x00, 
+0x25, 0x01, 0x75, 0x01, 0x95, 0x06, 0xB1, 0x22, 0x75, 0x02, 
+0x95, 0x01, 0xB1, 0x03, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/047F_C056_0003_FFA0_real.rpt_desc b/src/hidapi/windows/test/data/047F_C056_0003_FFA0_real.rpt_desc
new file mode 100644
index 0000000..7532fd1
--- /dev/null
+++ b/src/hidapi/windows/test/data/047F_C056_0003_FFA0_real.rpt_desc
@@ -0,0 +1,113 @@
+macOS USB Prober about 0x047F/0xC056 "Plantronics Blackwire 3220 Series"
+06 A0 FF 09 03 A1 01 85 03 09 30 75  
+08 95 20 91 02 85 03 09 30 75 08 95 20 81 02 85  
+14 09 B1 09 B2 09 B5 09 B7 09 B3 15 00 25 01 75  
+01 95 05 81 06 95 03 81 01 85 15 09 8C 15 00 27  
+FF FF 00 00 75 10 95 01 81 22 85 19 09 8D 09 8F  
+09 9E 09 DC 15 00 25 01 75 01 95 04 91 22 09 D2  
+09 D9 15 00 25 01 75 01 95 02 91 06 95 02 91 01  
+85 1A 09 B5 15 00 25 01 75 01 95 01 91 22 95 07  
+91 01 85 1B 09 CF 09 B5 75 01 95 02 B1 22 09 DE  
+75 01 95 01 B1 23 09 D8 95 01 B1 22 95 04 B1 01  
+09 09 09 17 09 18 09 1E 09 20 09 2A 75 01 95 06  
+B1 22 95 02 B1 01 85 1F 09 9C 75 01 95 01 81 06  
+95 07 81 01 C0 
+
+Parser output:
+0x06, 0xA0, 0xFF,  // Usage Page (Vendor Defined 0xFFA0)
+0x09, 0x03,        // Usage (0x03)
+0xA1, 0x01,        // Collection (Application)
+0x85, 0x03,        //   Report ID (3)
+0x09, 0x30,        //   Usage (0x30)
+0x75, 0x08,        //   Report Size (8)
+0x95, 0x20,        //   Report Count (32)
+0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x85, 0x03,        //   Report ID (3)
+0x09, 0x30,        //   Usage (0x30)
+0x75, 0x08,        //   Report Size (8)
+0x95, 0x20,        //   Report Count (32)
+0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x85, 0x14,        //   Report ID (20)
+0x09, 0xB1,        //   Usage (0xB1)
+0x09, 0xB2,        //   Usage (0xB2)
+0x09, 0xB5,        //   Usage (0xB5)
+0x09, 0xB7,        //   Usage (0xB7)
+0x09, 0xB3,        //   Usage (0xB3)
+0x15, 0x00,        //   Logical Minimum (0)
+0x25, 0x01,        //   Logical Maximum (1)
+0x75, 0x01,        //   Report Size (1)
+0x95, 0x05,        //   Report Count (5)
+0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+0x95, 0x03,        //   Report Count (3)
+0x81, 0x01,        //   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x85, 0x15,        //   Report ID (21)
+0x09, 0x8C,        //   Usage (0x8C)
+0x15, 0x00,        //   Logical Minimum (0)
+0x27, 0xFF, 0xFF, 0x00, 0x00,  //   Logical Maximum (65534)
+0x75, 0x10,        //   Report Size (16)
+0x95, 0x01,        //   Report Count (1)
+0x81, 0x22,        //   Input (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position)
+0x85, 0x19,        //   Report ID (25)
+0x09, 0x8D,        //   Usage (0x8D)
+0x09, 0x8F,        //   Usage (0x8F)
+0x09, 0x9E,        //   Usage (0x9E)
+0x09, 0xDC,        //   Usage (0xDC)
+0x15, 0x00,        //   Logical Minimum (0)
+0x25, 0x01,        //   Logical Maximum (1)
+0x75, 0x01,        //   Report Size (1)
+0x95, 0x04,        //   Report Count (4)
+0x91, 0x22,        //   Output (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)
+0x09, 0xD2,        //   Usage (0xD2)
+0x09, 0xD9,        //   Usage (0xD9)
+0x15, 0x00,        //   Logical Minimum (0)
+0x25, 0x01,        //   Logical Maximum (1)
+0x75, 0x01,        //   Report Size (1)
+0x95, 0x02,        //   Report Count (2)
+0x91, 0x06,        //   Output (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x95, 0x02,        //   Report Count (2)
+0x91, 0x01,        //   Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x85, 0x1A,        //   Report ID (26)
+0x09, 0xB5,        //   Usage (0xB5)
+0x15, 0x00,        //   Logical Minimum (0)
+0x25, 0x01,        //   Logical Maximum (1)
+0x75, 0x01,        //   Report Size (1)
+0x95, 0x01,        //   Report Count (1)
+0x91, 0x22,        //   Output (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)
+0x95, 0x07,        //   Report Count (7)
+0x91, 0x01,        //   Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x85, 0x1B,        //   Report ID (27)
+0x09, 0xCF,        //   Usage (0xCF)
+0x09, 0xB5,        //   Usage (0xB5)
+0x75, 0x01,        //   Report Size (1)
+0x95, 0x02,        //   Report Count (2)
+0xB1, 0x22,        //   Feature (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)
+0x09, 0xDE,        //   Usage (0xDE)
+0x75, 0x01,        //   Report Size (1)
+0x95, 0x01,        //   Report Count (1)
+0xB1, 0x23,        //   Feature (Const,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)
+0x09, 0xD8,        //   Usage (0xD8)
+0x95, 0x01,        //   Report Count (1)
+0xB1, 0x22,        //   Feature (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)
+0x95, 0x04,        //   Report Count (4)
+0xB1, 0x01,        //   Feature (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x09, 0x09,        //   Usage (0x09)
+0x09, 0x17,        //   Usage (0x17)
+0x09, 0x18,        //   Usage (0x18)
+0x09, 0x1E,        //   Usage (0x1E)
+0x09, 0x20,        //   Usage (0x20)
+0x09, 0x2A,        //   Usage (0x2A)
+0x75, 0x01,        //   Report Size (1)
+0x95, 0x06,        //   Report Count (6)
+0xB1, 0x22,        //   Feature (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)
+0x95, 0x02,        //   Report Count (2)
+0xB1, 0x01,        //   Feature (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x85, 0x1F,        //   Report ID (31)
+0x09, 0x9C,        //   Usage (0x9C)
+0x75, 0x01,        //   Report Size (1)
+0x95, 0x01,        //   Report Count (1)
+0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+0x95, 0x07,        //   Report Count (7)
+0x81, 0x01,        //   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0xC0,              // End Collection
+
+// 193 bytes
diff --git a/src/hidapi/windows/test/data/047F_C056_0005_000B.pp_data b/src/hidapi/windows/test/data/047F_C056_0005_000B.pp_data
new file mode 100644
index 0000000..583c317
--- /dev/null
+++ b/src/hidapi/windows/test/data/047F_C056_0005_000B.pp_data
@@ -0,0 +1,461 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x047F
+dev->product_id          = 0xC056
+dev->manufacturer_string = "Plantronics"
+dev->product_string      = "Plantronics Blackwire 3220 Series"
+dev->release_number      = 0x0210
+dev->interface_number    = 3
+dev->usage               = 0x0005
+dev->usage_page          = 0x000B
+dev->path                = "\\?\hid#vid_047f&pid_c056&mi_03&col02#f&39e6f119&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0005
+pp_data->UsagePage                            = 0x000B
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 3
+pp_data->caps_info[0]->NumberOfCaps       = 3
+pp_data->caps_info[0]->ReportByteLength   = 2
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 3
+pp_data->caps_info[1]->LastCap            = 9
+pp_data->caps_info[1]->NumberOfCaps       = 6
+pp_data->caps_info[1]->ReportByteLength   = 2
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 9
+pp_data->caps_info[2]->LastCap            = 9
+pp_data->caps_info[2]->NumberOfCaps       = 0
+pp_data->caps_info[2]->ReportByteLength   = 0
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x03A8
+pp_data->NumberLinkCollectionNodes            = 1
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0x000B
+pp_data->cap[0]->ReportID                     = 0x08
+pp_data->cap[0]->BitPosition                  = 0
+pp_data->cap[0]->BitSize                      = 1
+pp_data->cap[0]->ReportCount                  = 1
+pp_data->cap[0]->BytePosition                 = 0x0001
+pp_data->cap[0]->BitCount                     = 1
+pp_data->cap[0]->BitField                     = 0x06
+pp_data->cap[0]->NextBytePosition             = 0x0002
+pp_data->cap[0]->LinkCollection               = 0x0000
+pp_data->cap[0]->LinkUsagePage                = 0x000B
+pp_data->cap[0]->LinkUsage                    = 0x0005
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 1
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 0
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x002F
+pp_data->cap[0]->NotRange.Reserved1                    = 0x002F
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->Button.LogicalMin                   = 0
+pp_data->cap[0]->Button.LogicalMax                   = 0
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0x000B
+pp_data->cap[1]->ReportID                     = 0x08
+pp_data->cap[1]->BitPosition                  = 2
+pp_data->cap[1]->BitSize                      = 1
+pp_data->cap[1]->ReportCount                  = 1
+pp_data->cap[1]->BytePosition                 = 0x0001
+pp_data->cap[1]->BitCount                     = 1
+pp_data->cap[1]->BitField                     = 0x22
+pp_data->cap[1]->NextBytePosition             = 0x0002
+pp_data->cap[1]->LinkCollection               = 0x0000
+pp_data->cap[1]->LinkUsagePage                = 0x000B
+pp_data->cap[1]->LinkUsage                    = 0x0005
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 1
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0021
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0021
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 1
+pp_data->cap[1]->NotRange.Reserved4                    = 1
+pp_data->cap[1]->Button.LogicalMin                   = 0
+pp_data->cap[1]->Button.LogicalMax                   = 0
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+pp_data->cap[2]->UsagePage                    = 0x000B
+pp_data->cap[2]->ReportID                     = 0x08
+pp_data->cap[2]->BitPosition                  = 1
+pp_data->cap[2]->BitSize                      = 1
+pp_data->cap[2]->ReportCount                  = 1
+pp_data->cap[2]->BytePosition                 = 0x0001
+pp_data->cap[2]->BitCount                     = 1
+pp_data->cap[2]->BitField                     = 0x22
+pp_data->cap[2]->NextBytePosition             = 0x0002
+pp_data->cap[2]->LinkCollection               = 0x0000
+pp_data->cap[2]->LinkUsagePage                = 0x000B
+pp_data->cap[2]->LinkUsage                    = 0x0005
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 1
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 1
+pp_data->cap[2]->IsRange                      = 0
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->NotRange.Usage                        = 0x0020
+pp_data->cap[2]->NotRange.Reserved1                    = 0x0020
+pp_data->cap[2]->NotRange.StringIndex                  = 0
+pp_data->cap[2]->NotRange.Reserved2                    = 0
+pp_data->cap[2]->NotRange.DesignatorIndex              = 0
+pp_data->cap[2]->NotRange.Reserved3                    = 0
+pp_data->cap[2]->NotRange.DataIndex                    = 2
+pp_data->cap[2]->NotRange.Reserved4                    = 2
+pp_data->cap[2]->Button.LogicalMin                   = 0
+pp_data->cap[2]->Button.LogicalMax                   = 0
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[3]->UsagePage                    = 0x0008
+pp_data->cap[3]->ReportID                     = 0x09
+pp_data->cap[3]->BitPosition                  = 0
+pp_data->cap[3]->BitSize                      = 1
+pp_data->cap[3]->ReportCount                  = 1
+pp_data->cap[3]->BytePosition                 = 0x0001
+pp_data->cap[3]->BitCount                     = 1
+pp_data->cap[3]->BitField                     = 0x22
+pp_data->cap[3]->NextBytePosition             = 0x0002
+pp_data->cap[3]->LinkCollection               = 0x0000
+pp_data->cap[3]->LinkUsagePage                = 0x000B
+pp_data->cap[3]->LinkUsage                    = 0x0005
+pp_data->cap[3]->IsMultipleItemsForArray      = 0
+pp_data->cap[3]->IsButtonCap                  = 1
+pp_data->cap[3]->IsPadding                    = 0
+pp_data->cap[3]->IsAbsolute                   = 1
+pp_data->cap[3]->IsRange                      = 0
+pp_data->cap[3]->IsAlias                      = 0
+pp_data->cap[3]->IsStringRange                = 0
+pp_data->cap[3]->IsDesignatorRange            = 0
+pp_data->cap[3]->Reserved1                    = 0x000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[3]->NotRange.Usage                        = 0x0009
+pp_data->cap[3]->NotRange.Reserved1                    = 0x0009
+pp_data->cap[3]->NotRange.StringIndex                  = 0
+pp_data->cap[3]->NotRange.Reserved2                    = 0
+pp_data->cap[3]->NotRange.DesignatorIndex              = 0
+pp_data->cap[3]->NotRange.Reserved3                    = 0
+pp_data->cap[3]->NotRange.DataIndex                    = 0
+pp_data->cap[3]->NotRange.Reserved4                    = 0
+pp_data->cap[3]->Button.LogicalMin                   = 0
+pp_data->cap[3]->Button.LogicalMax                   = 0
+pp_data->cap[3]->Units                    = 0
+pp_data->cap[3]->UnitsExp                 = 0
+
+pp_data->cap[4]->UsagePage                    = 0x0008
+pp_data->cap[4]->ReportID                     = 0x17
+pp_data->cap[4]->BitPosition                  = 0
+pp_data->cap[4]->BitSize                      = 1
+pp_data->cap[4]->ReportCount                  = 1
+pp_data->cap[4]->BytePosition                 = 0x0001
+pp_data->cap[4]->BitCount                     = 1
+pp_data->cap[4]->BitField                     = 0x22
+pp_data->cap[4]->NextBytePosition             = 0x0002
+pp_data->cap[4]->LinkCollection               = 0x0000
+pp_data->cap[4]->LinkUsagePage                = 0x000B
+pp_data->cap[4]->LinkUsage                    = 0x0005
+pp_data->cap[4]->IsMultipleItemsForArray      = 0
+pp_data->cap[4]->IsButtonCap                  = 1
+pp_data->cap[4]->IsPadding                    = 0
+pp_data->cap[4]->IsAbsolute                   = 1
+pp_data->cap[4]->IsRange                      = 0
+pp_data->cap[4]->IsAlias                      = 0
+pp_data->cap[4]->IsStringRange                = 0
+pp_data->cap[4]->IsDesignatorRange            = 0
+pp_data->cap[4]->Reserved1                    = 0x000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[4]->NotRange.Usage                        = 0x0017
+pp_data->cap[4]->NotRange.Reserved1                    = 0x0017
+pp_data->cap[4]->NotRange.StringIndex                  = 0
+pp_data->cap[4]->NotRange.Reserved2                    = 0
+pp_data->cap[4]->NotRange.DesignatorIndex              = 0
+pp_data->cap[4]->NotRange.Reserved3                    = 0
+pp_data->cap[4]->NotRange.DataIndex                    = 1
+pp_data->cap[4]->NotRange.Reserved4                    = 1
+pp_data->cap[4]->Button.LogicalMin                   = 0
+pp_data->cap[4]->Button.LogicalMax                   = 0
+pp_data->cap[4]->Units                    = 0
+pp_data->cap[4]->UnitsExp                 = 0
+
+pp_data->cap[5]->UsagePage                    = 0x0008
+pp_data->cap[5]->ReportID                     = 0x18
+pp_data->cap[5]->BitPosition                  = 0
+pp_data->cap[5]->BitSize                      = 1
+pp_data->cap[5]->ReportCount                  = 1
+pp_data->cap[5]->BytePosition                 = 0x0001
+pp_data->cap[5]->BitCount                     = 1
+pp_data->cap[5]->BitField                     = 0x22
+pp_data->cap[5]->NextBytePosition             = 0x0002
+pp_data->cap[5]->LinkCollection               = 0x0000
+pp_data->cap[5]->LinkUsagePage                = 0x000B
+pp_data->cap[5]->LinkUsage                    = 0x0005
+pp_data->cap[5]->IsMultipleItemsForArray      = 0
+pp_data->cap[5]->IsButtonCap                  = 1
+pp_data->cap[5]->IsPadding                    = 0
+pp_data->cap[5]->IsAbsolute                   = 1
+pp_data->cap[5]->IsRange                      = 0
+pp_data->cap[5]->IsAlias                      = 0
+pp_data->cap[5]->IsStringRange                = 0
+pp_data->cap[5]->IsDesignatorRange            = 0
+pp_data->cap[5]->Reserved1                    = 0x000
+pp_data->cap[5]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[5]->NotRange.Usage                        = 0x0018
+pp_data->cap[5]->NotRange.Reserved1                    = 0x0018
+pp_data->cap[5]->NotRange.StringIndex                  = 0
+pp_data->cap[5]->NotRange.Reserved2                    = 0
+pp_data->cap[5]->NotRange.DesignatorIndex              = 0
+pp_data->cap[5]->NotRange.Reserved3                    = 0
+pp_data->cap[5]->NotRange.DataIndex                    = 2
+pp_data->cap[5]->NotRange.Reserved4                    = 2
+pp_data->cap[5]->Button.LogicalMin                   = 0
+pp_data->cap[5]->Button.LogicalMax                   = 0
+pp_data->cap[5]->Units                    = 0
+pp_data->cap[5]->UnitsExp                 = 0
+
+pp_data->cap[6]->UsagePage                    = 0x0008
+pp_data->cap[6]->ReportID                     = 0x1E
+pp_data->cap[6]->BitPosition                  = 0
+pp_data->cap[6]->BitSize                      = 1
+pp_data->cap[6]->ReportCount                  = 1
+pp_data->cap[6]->BytePosition                 = 0x0001
+pp_data->cap[6]->BitCount                     = 1
+pp_data->cap[6]->BitField                     = 0x22
+pp_data->cap[6]->NextBytePosition             = 0x0002
+pp_data->cap[6]->LinkCollection               = 0x0000
+pp_data->cap[6]->LinkUsagePage                = 0x000B
+pp_data->cap[6]->LinkUsage                    = 0x0005
+pp_data->cap[6]->IsMultipleItemsForArray      = 0
+pp_data->cap[6]->IsButtonCap                  = 1
+pp_data->cap[6]->IsPadding                    = 0
+pp_data->cap[6]->IsAbsolute                   = 1
+pp_data->cap[6]->IsRange                      = 0
+pp_data->cap[6]->IsAlias                      = 0
+pp_data->cap[6]->IsStringRange                = 0
+pp_data->cap[6]->IsDesignatorRange            = 0
+pp_data->cap[6]->Reserved1                    = 0x000
+pp_data->cap[6]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[6]->NotRange.Usage                        = 0x001E
+pp_data->cap[6]->NotRange.Reserved1                    = 0x001E
+pp_data->cap[6]->NotRange.StringIndex                  = 0
+pp_data->cap[6]->NotRange.Reserved2                    = 0
+pp_data->cap[6]->NotRange.DesignatorIndex              = 0
+pp_data->cap[6]->NotRange.Reserved3                    = 0
+pp_data->cap[6]->NotRange.DataIndex                    = 3
+pp_data->cap[6]->NotRange.Reserved4                    = 3
+pp_data->cap[6]->Button.LogicalMin                   = 0
+pp_data->cap[6]->Button.LogicalMax                   = 0
+pp_data->cap[6]->Units                    = 0
+pp_data->cap[6]->UnitsExp                 = 0
+
+pp_data->cap[7]->UsagePage                    = 0x0008
+pp_data->cap[7]->ReportID                     = 0x20
+pp_data->cap[7]->BitPosition                  = 0
+pp_data->cap[7]->BitSize                      = 1
+pp_data->cap[7]->ReportCount                  = 1
+pp_data->cap[7]->BytePosition                 = 0x0001
+pp_data->cap[7]->BitCount                     = 1
+pp_data->cap[7]->BitField                     = 0x22
+pp_data->cap[7]->NextBytePosition             = 0x0002
+pp_data->cap[7]->LinkCollection               = 0x0000
+pp_data->cap[7]->LinkUsagePage                = 0x000B
+pp_data->cap[7]->LinkUsage                    = 0x0005
+pp_data->cap[7]->IsMultipleItemsForArray      = 0
+pp_data->cap[7]->IsButtonCap                  = 1
+pp_data->cap[7]->IsPadding                    = 0
+pp_data->cap[7]->IsAbsolute                   = 1
+pp_data->cap[7]->IsRange                      = 0
+pp_data->cap[7]->IsAlias                      = 0
+pp_data->cap[7]->IsStringRange                = 0
+pp_data->cap[7]->IsDesignatorRange            = 0
+pp_data->cap[7]->Reserved1                    = 0x000
+pp_data->cap[7]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[7]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[7]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[7]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[7]->NotRange.Usage                        = 0x0020
+pp_data->cap[7]->NotRange.Reserved1                    = 0x0020
+pp_data->cap[7]->NotRange.StringIndex                  = 0
+pp_data->cap[7]->NotRange.Reserved2                    = 0
+pp_data->cap[7]->NotRange.DesignatorIndex              = 0
+pp_data->cap[7]->NotRange.Reserved3                    = 0
+pp_data->cap[7]->NotRange.DataIndex                    = 4
+pp_data->cap[7]->NotRange.Reserved4                    = 4
+pp_data->cap[7]->Button.LogicalMin                   = 0
+pp_data->cap[7]->Button.LogicalMax                   = 0
+pp_data->cap[7]->Units                    = 0
+pp_data->cap[7]->UnitsExp                 = 0
+
+pp_data->cap[8]->UsagePage                    = 0x0008
+pp_data->cap[8]->ReportID                     = 0x2A
+pp_data->cap[8]->BitPosition                  = 0
+pp_data->cap[8]->BitSize                      = 1
+pp_data->cap[8]->ReportCount                  = 1
+pp_data->cap[8]->BytePosition                 = 0x0001
+pp_data->cap[8]->BitCount                     = 1
+pp_data->cap[8]->BitField                     = 0x22
+pp_data->cap[8]->NextBytePosition             = 0x0002
+pp_data->cap[8]->LinkCollection               = 0x0000
+pp_data->cap[8]->LinkUsagePage                = 0x000B
+pp_data->cap[8]->LinkUsage                    = 0x0005
+pp_data->cap[8]->IsMultipleItemsForArray      = 0
+pp_data->cap[8]->IsButtonCap                  = 1
+pp_data->cap[8]->IsPadding                    = 0
+pp_data->cap[8]->IsAbsolute                   = 1
+pp_data->cap[8]->IsRange                      = 0
+pp_data->cap[8]->IsAlias                      = 0
+pp_data->cap[8]->IsStringRange                = 0
+pp_data->cap[8]->IsDesignatorRange            = 0
+pp_data->cap[8]->Reserved1                    = 0x000
+pp_data->cap[8]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[8]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[8]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[8]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[8]->NotRange.Usage                        = 0x002A
+pp_data->cap[8]->NotRange.Reserved1                    = 0x002A
+pp_data->cap[8]->NotRange.StringIndex                  = 0
+pp_data->cap[8]->NotRange.Reserved2                    = 0
+pp_data->cap[8]->NotRange.DesignatorIndex              = 0
+pp_data->cap[8]->NotRange.Reserved3                    = 0
+pp_data->cap[8]->NotRange.DataIndex                    = 5
+pp_data->cap[8]->NotRange.Reserved4                    = 5
+pp_data->cap[8]->Button.LogicalMin                   = 0
+pp_data->cap[8]->Button.LogicalMax                   = 0
+pp_data->cap[8]->Units                    = 0
+pp_data->cap[8]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0005
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0x000B
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 0
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/047F_C056_0005_000B_expected.rpt_desc b/src/hidapi/windows/test/data/047F_C056_0005_000B_expected.rpt_desc
new file mode 100644
index 0000000..40962ac
--- /dev/null
+++ b/src/hidapi/windows/test/data/047F_C056_0005_000B_expected.rpt_desc
@@ -0,0 +1,17 @@
+0x05, 0x0B, 0x09, 0x05, 0xA1, 0x01, 0x85, 0x08, 0x09, 0x2F, 
+0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x01, 0x81, 0x06, 
+0x09, 0x20, 0x09, 0x21, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 
+0x95, 0x02, 0x81, 0x22, 0x75, 0x05, 0x95, 0x01, 0x81, 0x03, 
+0x85, 0x09, 0x05, 0x08, 0x09, 0x09, 0x15, 0x00, 0x25, 0x01, 
+0x75, 0x01, 0x95, 0x01, 0x91, 0x22, 0x75, 0x07, 0x95, 0x01, 
+0x91, 0x03, 0x85, 0x17, 0x09, 0x17, 0x15, 0x00, 0x25, 0x01, 
+0x75, 0x01, 0x95, 0x01, 0x91, 0x22, 0x75, 0x07, 0x95, 0x01, 
+0x91, 0x03, 0x85, 0x18, 0x09, 0x18, 0x15, 0x00, 0x25, 0x01, 
+0x75, 0x01, 0x95, 0x01, 0x91, 0x22, 0x75, 0x07, 0x95, 0x01, 
+0x91, 0x03, 0x85, 0x1E, 0x09, 0x1E, 0x15, 0x00, 0x25, 0x01, 
+0x75, 0x01, 0x95, 0x01, 0x91, 0x22, 0x75, 0x07, 0x95, 0x01, 
+0x91, 0x03, 0x85, 0x20, 0x09, 0x20, 0x15, 0x00, 0x25, 0x01, 
+0x75, 0x01, 0x95, 0x01, 0x91, 0x22, 0x75, 0x07, 0x95, 0x01, 
+0x91, 0x03, 0x85, 0x2A, 0x09, 0x2A, 0x15, 0x00, 0x25, 0x01, 
+0x75, 0x01, 0x95, 0x01, 0x91, 0x22, 0x75, 0x07, 0x95, 0x01, 
+0x91, 0x03, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/047F_C056_0005_000B_real.rpt_desc b/src/hidapi/windows/test/data/047F_C056_0005_000B_real.rpt_desc
new file mode 100644
index 0000000..2fe387e
--- /dev/null
+++ b/src/hidapi/windows/test/data/047F_C056_0005_000B_real.rpt_desc
@@ -0,0 +1,68 @@
+macOS USB Prober about 0x047F/0xC056 "Plantronics Blackwire 3220 Series"
+05 0B 09 05 A1 01 85 08 15  
+00 25 01 09 2F 75 01 95 01 81 06 09 20 09 21 75  
+01 95 02 81 22 95 05 81 01 05 08 85 09 09 09 95  
+01 91 22 95 07 91 01 85 17 09 17 95 01 91 22 95  
+07 91 01 85 18 09 18 95 01 91 22 95 07 91 01 85  
+1E 09 1E 95 01 91 22 95 07 91 01 85 20 09 20 95  
+01 91 22 95 07 91 01 85 2A 09 2A 95 01 91 22 95  
+07 91 01 C0
+
+Parser output:
+0x05, 0x0B,        // Usage Page (Telephony)
+0x09, 0x05,        // Usage (Headset)
+0xA1, 0x01,        // Collection (Application)
+0x85, 0x08,        //   Report ID (8)
+0x15, 0x00,        //   Logical Minimum (0)
+0x25, 0x01,        //   Logical Maximum (1)
+0x09, 0x2F,        //   Usage (Phone Mute)
+0x75, 0x01,        //   Report Size (1)
+0x95, 0x01,        //   Report Count (1)
+0x81, 0x06,        //   Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
+0x09, 0x20,        //   Usage (Hook Switch)
+0x09, 0x21,        //   Usage (Flash)
+0x75, 0x01,        //   Report Size (1)
+0x95, 0x02,        //   Report Count (2)
+0x81, 0x22,        //   Input (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position)
+0x95, 0x05,        //   Report Count (5)
+0x81, 0x01,        //   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
+0x05, 0x08,        //   Usage Page (LEDs)
+0x85, 0x09,        //   Report ID (9)
+0x09, 0x09,        //   Usage (Mute)
+0x95, 0x01,        //   Report Count (1)
+0x91, 0x22,        //   Output (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)
+0x95, 0x07,        //   Report Count (7)
+0x91, 0x01,        //   Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x85, 0x17,        //   Report ID (23)
+0x09, 0x17,        //   Usage (Off-Hook)
+0x95, 0x01,        //   Report Count (1)
+0x91, 0x22,        //   Output (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)
+0x95, 0x07,        //   Report Count (7)
+0x91, 0x01,        //   Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x85, 0x18,        //   Report ID (24)
+0x09, 0x18,        //   Usage (Ring)
+0x95, 0x01,        //   Report Count (1)
+0x91, 0x22,        //   Output (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)
+0x95, 0x07,        //   Report Count (7)
+0x91, 0x01,        //   Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x85, 0x1E,        //   Report ID (30)
+0x09, 0x1E,        //   Usage (Speaker)
+0x95, 0x01,        //   Report Count (1)
+0x91, 0x22,        //   Output (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)
+0x95, 0x07,        //   Report Count (7)
+0x91, 0x01,        //   Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x85, 0x20,        //   Report ID (32)
+0x09, 0x20,        //   Usage (Hold)
+0x95, 0x01,        //   Report Count (1)
+0x91, 0x22,        //   Output (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)
+0x95, 0x07,        //   Report Count (7)
+0x91, 0x01,        //   Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0x85, 0x2A,        //   Report ID (42)
+0x09, 0x2A,        //   Usage (On-Line)
+0x95, 0x01,        //   Report Count (1)
+0x91, 0x22,        //   Output (Data,Var,Abs,No Wrap,Linear,No Preferred State,No Null Position,Non-volatile)
+0x95, 0x07,        //   Report Count (7)
+0x91, 0x01,        //   Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+0xC0,              // End Collection
+
+// 109 bytes
diff --git a/src/hidapi/windows/test/data/17CC_1130_0000_FF01.pp_data b/src/hidapi/windows/test/data/17CC_1130_0000_FF01.pp_data
new file mode 100644
index 0000000..acab8a6
--- /dev/null
+++ b/src/hidapi/windows/test/data/17CC_1130_0000_FF01.pp_data
@@ -0,0 +1,11508 @@
+# HIDAPI device info struct:
+dev->vendor_id           = 0x17CC
+dev->product_id          = 0x1130
+dev->manufacturer_string = "Native Instruments"
+dev->product_string      = "Traktor Kontrol Z2"
+dev->release_number      = 0x0033
+dev->interface_number    = 4
+dev->usage               = 0x0000
+dev->usage_page          = 0xFF01
+dev->path                = "\\?\hid#vid_17cc&pid_1130&mi_04#9&11d406cd&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
+
+# Preparsed Data struct:
+pp_data->MagicKey                             = 0x48696450204B4452
+pp_data->Usage                                = 0x0000
+pp_data->UsagePage                            = 0xFF01
+pp_data->Reserved                             = 0x00000000
+# Input caps_info struct:
+pp_data->caps_info[0]->FirstCap           = 0
+pp_data->caps_info[0]->LastCap            = 86
+pp_data->caps_info[0]->NumberOfCaps       = 87
+pp_data->caps_info[0]->ReportByteLength   = 53
+# Output caps_info struct:
+pp_data->caps_info[1]->FirstCap           = 87
+pp_data->caps_info[1]->LastCap            = 221
+pp_data->caps_info[1]->NumberOfCaps       = 134
+pp_data->caps_info[1]->ReportByteLength   = 95
+# Feature caps_info struct:
+pp_data->caps_info[2]->FirstCap           = 221
+pp_data->caps_info[2]->LastCap            = 232
+pp_data->caps_info[2]->NumberOfCaps       = 11
+pp_data->caps_info[2]->ReportByteLength   = 33
+# LinkCollectionArray Offset & Size:
+pp_data->FirstByteOfLinkCollectionArray       = 0x5E40
+pp_data->NumberLinkCollectionNodes            = 16
+# Input hid_pp_cap struct:
+pp_data->cap[0]->UsagePage                    = 0xFF01
+pp_data->cap[0]->ReportID                     = 0x01
+pp_data->cap[0]->BitPosition                  = 4
+pp_data->cap[0]->BitSize                      = 4
+pp_data->cap[0]->ReportCount                  = 1
+pp_data->cap[0]->BytePosition                 = 0x0002
+pp_data->cap[0]->BitCount                     = 4
+pp_data->cap[0]->BitField                     = 0x02
+pp_data->cap[0]->NextBytePosition             = 0x0003
+pp_data->cap[0]->LinkCollection               = 0x0001
+pp_data->cap[0]->LinkUsagePage                = 0xFF01
+pp_data->cap[0]->LinkUsage                    = 0x0001
+pp_data->cap[0]->IsMultipleItemsForArray      = 0
+pp_data->cap[0]->IsButtonCap                  = 0
+pp_data->cap[0]->IsPadding                    = 0
+pp_data->cap[0]->IsAbsolute                   = 1
+pp_data->cap[0]->IsRange                      = 0
+pp_data->cap[0]->IsAlias                      = 0
+pp_data->cap[0]->IsStringRange                = 0
+pp_data->cap[0]->IsDesignatorRange            = 0
+pp_data->cap[0]->Reserved1                    = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[0]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[0]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[0]->NotRange.Usage                        = 0x0003
+pp_data->cap[0]->NotRange.Reserved1                    = 0x0003
+pp_data->cap[0]->NotRange.StringIndex                  = 0
+pp_data->cap[0]->NotRange.Reserved2                    = 0
+pp_data->cap[0]->NotRange.DesignatorIndex              = 0
+pp_data->cap[0]->NotRange.Reserved3                    = 0
+pp_data->cap[0]->NotRange.DataIndex                    = 0
+pp_data->cap[0]->NotRange.Reserved4                    = 0
+pp_data->cap[0]->NotButton.HasNull                   = 0
+pp_data->cap[0]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[0]->NotButton.LogicalMin                = 0
+pp_data->cap[0]->NotButton.LogicalMax                = 15
+pp_data->cap[0]->NotButton.PhysicalMin               = 0
+pp_data->cap[0]->NotButton.PhysicalMax               = 0
+pp_data->cap[0]->Units                    = 0
+pp_data->cap[0]->UnitsExp                 = 0
+
+pp_data->cap[1]->UsagePage                    = 0xFF01
+pp_data->cap[1]->ReportID                     = 0x01
+pp_data->cap[1]->BitPosition                  = 0
+pp_data->cap[1]->BitSize                      = 4
+pp_data->cap[1]->ReportCount                  = 1
+pp_data->cap[1]->BytePosition                 = 0x0002
+pp_data->cap[1]->BitCount                     = 4
+pp_data->cap[1]->BitField                     = 0x02
+pp_data->cap[1]->NextBytePosition             = 0x0003
+pp_data->cap[1]->LinkCollection               = 0x0001
+pp_data->cap[1]->LinkUsagePage                = 0xFF01
+pp_data->cap[1]->LinkUsage                    = 0x0001
+pp_data->cap[1]->IsMultipleItemsForArray      = 0
+pp_data->cap[1]->IsButtonCap                  = 0
+pp_data->cap[1]->IsPadding                    = 0
+pp_data->cap[1]->IsAbsolute                   = 1
+pp_data->cap[1]->IsRange                      = 0
+pp_data->cap[1]->IsAlias                      = 0
+pp_data->cap[1]->IsStringRange                = 0
+pp_data->cap[1]->IsDesignatorRange            = 0
+pp_data->cap[1]->Reserved1                    = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[1]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[1]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[1]->NotRange.Usage                        = 0x0003
+pp_data->cap[1]->NotRange.Reserved1                    = 0x0003
+pp_data->cap[1]->NotRange.StringIndex                  = 0
+pp_data->cap[1]->NotRange.Reserved2                    = 0
+pp_data->cap[1]->NotRange.DesignatorIndex              = 0
+pp_data->cap[1]->NotRange.Reserved3                    = 0
+pp_data->cap[1]->NotRange.DataIndex                    = 1
+pp_data->cap[1]->NotRange.Reserved4                    = 1
+pp_data->cap[1]->NotButton.HasNull                   = 0
+pp_data->cap[1]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[1]->NotButton.LogicalMin                = 0
+pp_data->cap[1]->NotButton.LogicalMax                = 15
+pp_data->cap[1]->NotButton.PhysicalMin               = 0
+pp_data->cap[1]->NotButton.PhysicalMax               = 0
+pp_data->cap[1]->Units                    = 0
+pp_data->cap[1]->UnitsExp                 = 0
+
+pp_data->cap[2]->UsagePage                    = 0xFF01
+pp_data->cap[2]->ReportID                     = 0x01
+pp_data->cap[2]->BitPosition                  = 4
+pp_data->cap[2]->BitSize                      = 4
+pp_data->cap[2]->ReportCount                  = 1
+pp_data->cap[2]->BytePosition                 = 0x0001
+pp_data->cap[2]->BitCount                     = 4
+pp_data->cap[2]->BitField                     = 0x02
+pp_data->cap[2]->NextBytePosition             = 0x0002
+pp_data->cap[2]->LinkCollection               = 0x0001
+pp_data->cap[2]->LinkUsagePage                = 0xFF01
+pp_data->cap[2]->LinkUsage                    = 0x0001
+pp_data->cap[2]->IsMultipleItemsForArray      = 0
+pp_data->cap[2]->IsButtonCap                  = 0
+pp_data->cap[2]->IsPadding                    = 0
+pp_data->cap[2]->IsAbsolute                   = 1
+pp_data->cap[2]->IsRange                      = 0
+pp_data->cap[2]->IsAlias                      = 0
+pp_data->cap[2]->IsStringRange                = 0
+pp_data->cap[2]->IsDesignatorRange            = 0
+pp_data->cap[2]->Reserved1                    = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[2]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[2]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[2]->NotRange.Usage                        = 0x0003
+pp_data->cap[2]->NotRange.Reserved1                    = 0x0003
+pp_data->cap[2]->NotRange.StringIndex                  = 0
+pp_data->cap[2]->NotRange.Reserved2                    = 0
+pp_data->cap[2]->NotRange.DesignatorIndex              = 0
+pp_data->cap[2]->NotRange.Reserved3                    = 0
+pp_data->cap[2]->NotRange.DataIndex                    = 2
+pp_data->cap[2]->NotRange.Reserved4                    = 2
+pp_data->cap[2]->NotButton.HasNull                   = 0
+pp_data->cap[2]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[2]->NotButton.LogicalMin                = 0
+pp_data->cap[2]->NotButton.LogicalMax                = 15
+pp_data->cap[2]->NotButton.PhysicalMin               = 0
+pp_data->cap[2]->NotButton.PhysicalMax               = 0
+pp_data->cap[2]->Units                    = 0
+pp_data->cap[2]->UnitsExp                 = 0
+
+pp_data->cap[3]->UsagePage                    = 0xFF01
+pp_data->cap[3]->ReportID                     = 0x01
+pp_data->cap[3]->BitPosition                  = 0
+pp_data->cap[3]->BitSize                      = 4
+pp_data->cap[3]->ReportCount                  = 1
+pp_data->cap[3]->BytePosition                 = 0x0001
+pp_data->cap[3]->BitCount                     = 4
+pp_data->cap[3]->BitField                     = 0x02
+pp_data->cap[3]->NextBytePosition             = 0x0002
+pp_data->cap[3]->LinkCollection               = 0x0001
+pp_data->cap[3]->LinkUsagePage                = 0xFF01
+pp_data->cap[3]->LinkUsage                    = 0x0001
+pp_data->cap[3]->IsMultipleItemsForArray      = 0
+pp_data->cap[3]->IsButtonCap                  = 0
+pp_data->cap[3]->IsPadding                    = 0
+pp_data->cap[3]->IsAbsolute                   = 1
+pp_data->cap[3]->IsRange                      = 0
+pp_data->cap[3]->IsAlias                      = 0
+pp_data->cap[3]->IsStringRange                = 0
+pp_data->cap[3]->IsDesignatorRange            = 0
+pp_data->cap[3]->Reserved1                    = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[3]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[3]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[3]->NotRange.Usage                        = 0x0003
+pp_data->cap[3]->NotRange.Reserved1                    = 0x0003
+pp_data->cap[3]->NotRange.StringIndex                  = 0
+pp_data->cap[3]->NotRange.Reserved2                    = 0
+pp_data->cap[3]->NotRange.DesignatorIndex              = 0
+pp_data->cap[3]->NotRange.Reserved3                    = 0
+pp_data->cap[3]->NotRange.DataIndex                    = 3
+pp_data->cap[3]->NotRange.Reserved4                    = 3
+pp_data->cap[3]->NotButton.HasNull                   = 0
+pp_data->cap[3]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[3]->NotButton.LogicalMin                = 0
+pp_data->cap[3]->NotButton.LogicalMax                = 15
+pp_data->cap[3]->NotButton.PhysicalMin               = 0
+pp_data->cap[3]->NotButton.PhysicalMax               = 0
+pp_data->cap[3]->Units                    = 0
+pp_data->cap[3]->UnitsExp                 = 0
+
+pp_data->cap[4]->UsagePage                    = 0xFF01
+pp_data->cap[4]->ReportID                     = 0x01
+pp_data->cap[4]->BitPosition                  = 7
+pp_data->cap[4]->BitSize                      = 1
+pp_data->cap[4]->ReportCount                  = 1
+pp_data->cap[4]->BytePosition                 = 0x0008
+pp_data->cap[4]->BitCount                     = 1
+pp_data->cap[4]->BitField                     = 0x02
+pp_data->cap[4]->NextBytePosition             = 0x0009
+pp_data->cap[4]->LinkCollection               = 0x0001
+pp_data->cap[4]->LinkUsagePage                = 0xFF01
+pp_data->cap[4]->LinkUsage                    = 0x0001
+pp_data->cap[4]->IsMultipleItemsForArray      = 0
+pp_data->cap[4]->IsButtonCap                  = 1
+pp_data->cap[4]->IsPadding                    = 0
+pp_data->cap[4]->IsAbsolute                   = 1
+pp_data->cap[4]->IsRange                      = 0
+pp_data->cap[4]->IsAlias                      = 0
+pp_data->cap[4]->IsStringRange                = 0
+pp_data->cap[4]->IsDesignatorRange            = 0
+pp_data->cap[4]->Reserved1                    = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[4]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[4]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[4]->NotRange.Usage                        = 0x0002
+pp_data->cap[4]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[4]->NotRange.StringIndex                  = 0
+pp_data->cap[4]->NotRange.Reserved2                    = 0
+pp_data->cap[4]->NotRange.DesignatorIndex              = 0
+pp_data->cap[4]->NotRange.Reserved3                    = 0
+pp_data->cap[4]->NotRange.DataIndex                    = 4
+pp_data->cap[4]->NotRange.Reserved4                    = 4
+pp_data->cap[4]->Button.LogicalMin                   = 0
+pp_data->cap[4]->Button.LogicalMax                   = 0
+pp_data->cap[4]->Units                    = 0
+pp_data->cap[4]->UnitsExp                 = 0
+
+pp_data->cap[5]->UsagePage                    = 0xFF01
+pp_data->cap[5]->ReportID                     = 0x01
+pp_data->cap[5]->BitPosition                  = 6
+pp_data->cap[5]->BitSize                      = 1
+pp_data->cap[5]->ReportCount                  = 1
+pp_data->cap[5]->BytePosition                 = 0x0008
+pp_data->cap[5]->BitCount                     = 1
+pp_data->cap[5]->BitField                     = 0x02
+pp_data->cap[5]->NextBytePosition             = 0x0009
+pp_data->cap[5]->LinkCollection               = 0x0001
+pp_data->cap[5]->LinkUsagePage                = 0xFF01
+pp_data->cap[5]->LinkUsage                    = 0x0001
+pp_data->cap[5]->IsMultipleItemsForArray      = 0
+pp_data->cap[5]->IsButtonCap                  = 1
+pp_data->cap[5]->IsPadding                    = 0
+pp_data->cap[5]->IsAbsolute                   = 1
+pp_data->cap[5]->IsRange                      = 0
+pp_data->cap[5]->IsAlias                      = 0
+pp_data->cap[5]->IsStringRange                = 0
+pp_data->cap[5]->IsDesignatorRange            = 0
+pp_data->cap[5]->Reserved1                    = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[5]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[5]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[5]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[5]->NotRange.Usage                        = 0x0002
+pp_data->cap[5]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[5]->NotRange.StringIndex                  = 0
+pp_data->cap[5]->NotRange.Reserved2                    = 0
+pp_data->cap[5]->NotRange.DesignatorIndex              = 0
+pp_data->cap[5]->NotRange.Reserved3                    = 0
+pp_data->cap[5]->NotRange.DataIndex                    = 5
+pp_data->cap[5]->NotRange.Reserved4                    = 5
+pp_data->cap[5]->Button.LogicalMin                   = 0
+pp_data->cap[5]->Button.LogicalMax                   = 0
+pp_data->cap[5]->Units                    = 0
+pp_data->cap[5]->UnitsExp                 = 0
+
+pp_data->cap[6]->UsagePage                    = 0xFF01
+pp_data->cap[6]->ReportID                     = 0x01
+pp_data->cap[6]->BitPosition                  = 5
+pp_data->cap[6]->BitSize                      = 1
+pp_data->cap[6]->ReportCount                  = 1
+pp_data->cap[6]->BytePosition                 = 0x0008
+pp_data->cap[6]->BitCount                     = 1
+pp_data->cap[6]->BitField                     = 0x02
+pp_data->cap[6]->NextBytePosition             = 0x0009
+pp_data->cap[6]->LinkCollection               = 0x0001
+pp_data->cap[6]->LinkUsagePage                = 0xFF01
+pp_data->cap[6]->LinkUsage                    = 0x0001
+pp_data->cap[6]->IsMultipleItemsForArray      = 0
+pp_data->cap[6]->IsButtonCap                  = 1
+pp_data->cap[6]->IsPadding                    = 0
+pp_data->cap[6]->IsAbsolute                   = 1
+pp_data->cap[6]->IsRange                      = 0
+pp_data->cap[6]->IsAlias                      = 0
+pp_data->cap[6]->IsStringRange                = 0
+pp_data->cap[6]->IsDesignatorRange            = 0
+pp_data->cap[6]->Reserved1                    = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[6]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[6]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[6]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[6]->NotRange.Usage                        = 0x0002
+pp_data->cap[6]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[6]->NotRange.StringIndex                  = 0
+pp_data->cap[6]->NotRange.Reserved2                    = 0
+pp_data->cap[6]->NotRange.DesignatorIndex              = 0
+pp_data->cap[6]->NotRange.Reserved3                    = 0
+pp_data->cap[6]->NotRange.DataIndex                    = 6
+pp_data->cap[6]->NotRange.Reserved4                    = 6
+pp_data->cap[6]->Button.LogicalMin                   = 0
+pp_data->cap[6]->Button.LogicalMax                   = 0
+pp_data->cap[6]->Units                    = 0
+pp_data->cap[6]->UnitsExp                 = 0
+
+pp_data->cap[7]->UsagePage                    = 0xFF01
+pp_data->cap[7]->ReportID                     = 0x01
+pp_data->cap[7]->BitPosition                  = 4
+pp_data->cap[7]->BitSize                      = 1
+pp_data->cap[7]->ReportCount                  = 1
+pp_data->cap[7]->BytePosition                 = 0x0008
+pp_data->cap[7]->BitCount                     = 1
+pp_data->cap[7]->BitField                     = 0x02
+pp_data->cap[7]->NextBytePosition             = 0x0009
+pp_data->cap[7]->LinkCollection               = 0x0001
+pp_data->cap[7]->LinkUsagePage                = 0xFF01
+pp_data->cap[7]->LinkUsage                    = 0x0001
+pp_data->cap[7]->IsMultipleItemsForArray      = 0
+pp_data->cap[7]->IsButtonCap                  = 1
+pp_data->cap[7]->IsPadding                    = 0
+pp_data->cap[7]->IsAbsolute                   = 1
+pp_data->cap[7]->IsRange                      = 0
+pp_data->cap[7]->IsAlias                      = 0
+pp_data->cap[7]->IsStringRange                = 0
+pp_data->cap[7]->IsDesignatorRange            = 0
+pp_data->cap[7]->Reserved1                    = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[7]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[7]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[7]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[7]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[7]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[7]->NotRange.Usage                        = 0x0002
+pp_data->cap[7]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[7]->NotRange.StringIndex                  = 0
+pp_data->cap[7]->NotRange.Reserved2                    = 0
+pp_data->cap[7]->NotRange.DesignatorIndex              = 0
+pp_data->cap[7]->NotRange.Reserved3                    = 0
+pp_data->cap[7]->NotRange.DataIndex                    = 7
+pp_data->cap[7]->NotRange.Reserved4                    = 7
+pp_data->cap[7]->Button.LogicalMin                   = 0
+pp_data->cap[7]->Button.LogicalMax                   = 0
+pp_data->cap[7]->Units                    = 0
+pp_data->cap[7]->UnitsExp                 = 0
+
+pp_data->cap[8]->UsagePage                    = 0xFF01
+pp_data->cap[8]->ReportID                     = 0x01
+pp_data->cap[8]->BitPosition                  = 3
+pp_data->cap[8]->BitSize                      = 1
+pp_data->cap[8]->ReportCount                  = 1
+pp_data->cap[8]->BytePosition                 = 0x0008
+pp_data->cap[8]->BitCount                     = 1
+pp_data->cap[8]->BitField                     = 0x02
+pp_data->cap[8]->NextBytePosition             = 0x0009
+pp_data->cap[8]->LinkCollection               = 0x0001
+pp_data->cap[8]->LinkUsagePage                = 0xFF01
+pp_data->cap[8]->LinkUsage                    = 0x0001
+pp_data->cap[8]->IsMultipleItemsForArray      = 0
+pp_data->cap[8]->IsButtonCap                  = 1
+pp_data->cap[8]->IsPadding                    = 0
+pp_data->cap[8]->IsAbsolute                   = 1
+pp_data->cap[8]->IsRange                      = 0
+pp_data->cap[8]->IsAlias                      = 0
+pp_data->cap[8]->IsStringRange                = 0
+pp_data->cap[8]->IsDesignatorRange            = 0
+pp_data->cap[8]->Reserved1                    = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[8]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[8]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[8]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[8]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[8]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[8]->NotRange.Usage                        = 0x0002
+pp_data->cap[8]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[8]->NotRange.StringIndex                  = 0
+pp_data->cap[8]->NotRange.Reserved2                    = 0
+pp_data->cap[8]->NotRange.DesignatorIndex              = 0
+pp_data->cap[8]->NotRange.Reserved3                    = 0
+pp_data->cap[8]->NotRange.DataIndex                    = 8
+pp_data->cap[8]->NotRange.Reserved4                    = 8
+pp_data->cap[8]->Button.LogicalMin                   = 0
+pp_data->cap[8]->Button.LogicalMax                   = 0
+pp_data->cap[8]->Units                    = 0
+pp_data->cap[8]->UnitsExp                 = 0
+
+pp_data->cap[9]->UsagePage                    = 0xFF01
+pp_data->cap[9]->ReportID                     = 0x01
+pp_data->cap[9]->BitPosition                  = 2
+pp_data->cap[9]->BitSize                      = 1
+pp_data->cap[9]->ReportCount                  = 1
+pp_data->cap[9]->BytePosition                 = 0x0008
+pp_data->cap[9]->BitCount                     = 1
+pp_data->cap[9]->BitField                     = 0x02
+pp_data->cap[9]->NextBytePosition             = 0x0009
+pp_data->cap[9]->LinkCollection               = 0x0001
+pp_data->cap[9]->LinkUsagePage                = 0xFF01
+pp_data->cap[9]->LinkUsage                    = 0x0001
+pp_data->cap[9]->IsMultipleItemsForArray      = 0
+pp_data->cap[9]->IsButtonCap                  = 1
+pp_data->cap[9]->IsPadding                    = 0
+pp_data->cap[9]->IsAbsolute                   = 1
+pp_data->cap[9]->IsRange                      = 0
+pp_data->cap[9]->IsAlias                      = 0
+pp_data->cap[9]->IsStringRange                = 0
+pp_data->cap[9]->IsDesignatorRange            = 0
+pp_data->cap[9]->Reserved1                    = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[9]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[9]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[9]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[9]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[9]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[9]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[9]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[9]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[9]->NotRange.Usage                        = 0x0002
+pp_data->cap[9]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[9]->NotRange.StringIndex                  = 0
+pp_data->cap[9]->NotRange.Reserved2                    = 0
+pp_data->cap[9]->NotRange.DesignatorIndex              = 0
+pp_data->cap[9]->NotRange.Reserved3                    = 0
+pp_data->cap[9]->NotRange.DataIndex                    = 9
+pp_data->cap[9]->NotRange.Reserved4                    = 9
+pp_data->cap[9]->Button.LogicalMin                   = 0
+pp_data->cap[9]->Button.LogicalMax                   = 0
+pp_data->cap[9]->Units                    = 0
+pp_data->cap[9]->UnitsExp                 = 0
+
+pp_data->cap[10]->UsagePage                    = 0xFF01
+pp_data->cap[10]->ReportID                     = 0x01
+pp_data->cap[10]->BitPosition                  = 1
+pp_data->cap[10]->BitSize                      = 1
+pp_data->cap[10]->ReportCount                  = 1
+pp_data->cap[10]->BytePosition                 = 0x0008
+pp_data->cap[10]->BitCount                     = 1
+pp_data->cap[10]->BitField                     = 0x02
+pp_data->cap[10]->NextBytePosition             = 0x0009
+pp_data->cap[10]->LinkCollection               = 0x0001
+pp_data->cap[10]->LinkUsagePage                = 0xFF01
+pp_data->cap[10]->LinkUsage                    = 0x0001
+pp_data->cap[10]->IsMultipleItemsForArray      = 0
+pp_data->cap[10]->IsButtonCap                  = 1
+pp_data->cap[10]->IsPadding                    = 0
+pp_data->cap[10]->IsAbsolute                   = 1
+pp_data->cap[10]->IsRange                      = 0
+pp_data->cap[10]->IsAlias                      = 0
+pp_data->cap[10]->IsStringRange                = 0
+pp_data->cap[10]->IsDesignatorRange            = 0
+pp_data->cap[10]->Reserved1                    = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[10]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[10]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[10]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[10]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[10]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[10]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[10]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[10]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[10]->NotRange.Usage                        = 0x0002
+pp_data->cap[10]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[10]->NotRange.StringIndex                  = 0
+pp_data->cap[10]->NotRange.Reserved2                    = 0
+pp_data->cap[10]->NotRange.DesignatorIndex              = 0
+pp_data->cap[10]->NotRange.Reserved3                    = 0
+pp_data->cap[10]->NotRange.DataIndex                    = 10
+pp_data->cap[10]->NotRange.Reserved4                    = 10
+pp_data->cap[10]->Button.LogicalMin                   = 0
+pp_data->cap[10]->Button.LogicalMax                   = 0
+pp_data->cap[10]->Units                    = 0
+pp_data->cap[10]->UnitsExp                 = 0
+
+pp_data->cap[11]->UsagePage                    = 0xFF01
+pp_data->cap[11]->ReportID                     = 0x01
+pp_data->cap[11]->BitPosition                  = 0
+pp_data->cap[11]->BitSize                      = 1
+pp_data->cap[11]->ReportCount                  = 1
+pp_data->cap[11]->BytePosition                 = 0x0008
+pp_data->cap[11]->BitCount                     = 1
+pp_data->cap[11]->BitField                     = 0x02
+pp_data->cap[11]->NextBytePosition             = 0x0009
+pp_data->cap[11]->LinkCollection               = 0x0001
+pp_data->cap[11]->LinkUsagePage                = 0xFF01
+pp_data->cap[11]->LinkUsage                    = 0x0001
+pp_data->cap[11]->IsMultipleItemsForArray      = 0
+pp_data->cap[11]->IsButtonCap                  = 1
+pp_data->cap[11]->IsPadding                    = 0
+pp_data->cap[11]->IsAbsolute                   = 1
+pp_data->cap[11]->IsRange                      = 0
+pp_data->cap[11]->IsAlias                      = 0
+pp_data->cap[11]->IsStringRange                = 0
+pp_data->cap[11]->IsDesignatorRange            = 0
+pp_data->cap[11]->Reserved1                    = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[11]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[11]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[11]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[11]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[11]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[11]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[11]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[11]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[11]->NotRange.Usage                        = 0x0002
+pp_data->cap[11]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[11]->NotRange.StringIndex                  = 0
+pp_data->cap[11]->NotRange.Reserved2                    = 0
+pp_data->cap[11]->NotRange.DesignatorIndex              = 0
+pp_data->cap[11]->NotRange.Reserved3                    = 0
+pp_data->cap[11]->NotRange.DataIndex                    = 11
+pp_data->cap[11]->NotRange.Reserved4                    = 11
+pp_data->cap[11]->Button.LogicalMin                   = 0
+pp_data->cap[11]->Button.LogicalMax                   = 0
+pp_data->cap[11]->Units                    = 0
+pp_data->cap[11]->UnitsExp                 = 0
+
+pp_data->cap[12]->UsagePage                    = 0xFF01
+pp_data->cap[12]->ReportID                     = 0x01
+pp_data->cap[12]->BitPosition                  = 7
+pp_data->cap[12]->BitSize                      = 1
+pp_data->cap[12]->ReportCount                  = 1
+pp_data->cap[12]->BytePosition                 = 0x0007
+pp_data->cap[12]->BitCount                     = 1
+pp_data->cap[12]->BitField                     = 0x02
+pp_data->cap[12]->NextBytePosition             = 0x0008
+pp_data->cap[12]->LinkCollection               = 0x0001
+pp_data->cap[12]->LinkUsagePage                = 0xFF01
+pp_data->cap[12]->LinkUsage                    = 0x0001
+pp_data->cap[12]->IsMultipleItemsForArray      = 0
+pp_data->cap[12]->IsButtonCap                  = 1
+pp_data->cap[12]->IsPadding                    = 0
+pp_data->cap[12]->IsAbsolute                   = 1
+pp_data->cap[12]->IsRange                      = 0
+pp_data->cap[12]->IsAlias                      = 0
+pp_data->cap[12]->IsStringRange                = 0
+pp_data->cap[12]->IsDesignatorRange            = 0
+pp_data->cap[12]->Reserved1                    = 0x000000
+pp_data->cap[12]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[12]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[12]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[12]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[12]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[12]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[12]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[12]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[12]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[12]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[12]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[12]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[12]->NotRange.Usage                        = 0x0002
+pp_data->cap[12]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[12]->NotRange.StringIndex                  = 0
+pp_data->cap[12]->NotRange.Reserved2                    = 0
+pp_data->cap[12]->NotRange.DesignatorIndex              = 0
+pp_data->cap[12]->NotRange.Reserved3                    = 0
+pp_data->cap[12]->NotRange.DataIndex                    = 12
+pp_data->cap[12]->NotRange.Reserved4                    = 12
+pp_data->cap[12]->Button.LogicalMin                   = 0
+pp_data->cap[12]->Button.LogicalMax                   = 0
+pp_data->cap[12]->Units                    = 0
+pp_data->cap[12]->UnitsExp                 = 0
+
+pp_data->cap[13]->UsagePage                    = 0xFF01
+pp_data->cap[13]->ReportID                     = 0x01
+pp_data->cap[13]->BitPosition                  = 6
+pp_data->cap[13]->BitSize                      = 1
+pp_data->cap[13]->ReportCount                  = 1
+pp_data->cap[13]->BytePosition                 = 0x0007
+pp_data->cap[13]->BitCount                     = 1
+pp_data->cap[13]->BitField                     = 0x02
+pp_data->cap[13]->NextBytePosition             = 0x0008
+pp_data->cap[13]->LinkCollection               = 0x0001
+pp_data->cap[13]->LinkUsagePage                = 0xFF01
+pp_data->cap[13]->LinkUsage                    = 0x0001
+pp_data->cap[13]->IsMultipleItemsForArray      = 0
+pp_data->cap[13]->IsButtonCap                  = 1
+pp_data->cap[13]->IsPadding                    = 0
+pp_data->cap[13]->IsAbsolute                   = 1
+pp_data->cap[13]->IsRange                      = 0
+pp_data->cap[13]->IsAlias                      = 0
+pp_data->cap[13]->IsStringRange                = 0
+pp_data->cap[13]->IsDesignatorRange            = 0
+pp_data->cap[13]->Reserved1                    = 0x000000
+pp_data->cap[13]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[13]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[13]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[13]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[13]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[13]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[13]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[13]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[13]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[13]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[13]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[13]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[13]->NotRange.Usage                        = 0x0002
+pp_data->cap[13]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[13]->NotRange.StringIndex                  = 0
+pp_data->cap[13]->NotRange.Reserved2                    = 0
+pp_data->cap[13]->NotRange.DesignatorIndex              = 0
+pp_data->cap[13]->NotRange.Reserved3                    = 0
+pp_data->cap[13]->NotRange.DataIndex                    = 13
+pp_data->cap[13]->NotRange.Reserved4                    = 13
+pp_data->cap[13]->Button.LogicalMin                   = 0
+pp_data->cap[13]->Button.LogicalMax                   = 0
+pp_data->cap[13]->Units                    = 0
+pp_data->cap[13]->UnitsExp                 = 0
+
+pp_data->cap[14]->UsagePage                    = 0xFF01
+pp_data->cap[14]->ReportID                     = 0x01
+pp_data->cap[14]->BitPosition                  = 5
+pp_data->cap[14]->BitSize                      = 1
+pp_data->cap[14]->ReportCount                  = 1
+pp_data->cap[14]->BytePosition                 = 0x0007
+pp_data->cap[14]->BitCount                     = 1
+pp_data->cap[14]->BitField                     = 0x02
+pp_data->cap[14]->NextBytePosition             = 0x0008
+pp_data->cap[14]->LinkCollection               = 0x0001
+pp_data->cap[14]->LinkUsagePage                = 0xFF01
+pp_data->cap[14]->LinkUsage                    = 0x0001
+pp_data->cap[14]->IsMultipleItemsForArray      = 0
+pp_data->cap[14]->IsButtonCap                  = 1
+pp_data->cap[14]->IsPadding                    = 0
+pp_data->cap[14]->IsAbsolute                   = 1
+pp_data->cap[14]->IsRange                      = 0
+pp_data->cap[14]->IsAlias                      = 0
+pp_data->cap[14]->IsStringRange                = 0
+pp_data->cap[14]->IsDesignatorRange            = 0
+pp_data->cap[14]->Reserved1                    = 0x000000
+pp_data->cap[14]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[14]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[14]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[14]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[14]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[14]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[14]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[14]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[14]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[14]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[14]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[14]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[14]->NotRange.Usage                        = 0x0002
+pp_data->cap[14]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[14]->NotRange.StringIndex                  = 0
+pp_data->cap[14]->NotRange.Reserved2                    = 0
+pp_data->cap[14]->NotRange.DesignatorIndex              = 0
+pp_data->cap[14]->NotRange.Reserved3                    = 0
+pp_data->cap[14]->NotRange.DataIndex                    = 14
+pp_data->cap[14]->NotRange.Reserved4                    = 14
+pp_data->cap[14]->Button.LogicalMin                   = 0
+pp_data->cap[14]->Button.LogicalMax                   = 0
+pp_data->cap[14]->Units                    = 0
+pp_data->cap[14]->UnitsExp                 = 0
+
+pp_data->cap[15]->UsagePage                    = 0xFF01
+pp_data->cap[15]->ReportID                     = 0x01
+pp_data->cap[15]->BitPosition                  = 4
+pp_data->cap[15]->BitSize                      = 1
+pp_data->cap[15]->ReportCount                  = 1
+pp_data->cap[15]->BytePosition                 = 0x0007
+pp_data->cap[15]->BitCount                     = 1
+pp_data->cap[15]->BitField                     = 0x02
+pp_data->cap[15]->NextBytePosition             = 0x0008
+pp_data->cap[15]->LinkCollection               = 0x0001
+pp_data->cap[15]->LinkUsagePage                = 0xFF01
+pp_data->cap[15]->LinkUsage                    = 0x0001
+pp_data->cap[15]->IsMultipleItemsForArray      = 0
+pp_data->cap[15]->IsButtonCap                  = 1
+pp_data->cap[15]->IsPadding                    = 0
+pp_data->cap[15]->IsAbsolute                   = 1
+pp_data->cap[15]->IsRange                      = 0
+pp_data->cap[15]->IsAlias                      = 0
+pp_data->cap[15]->IsStringRange                = 0
+pp_data->cap[15]->IsDesignatorRange            = 0
+pp_data->cap[15]->Reserved1                    = 0x000000
+pp_data->cap[15]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[15]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[15]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[15]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[15]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[15]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[15]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[15]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[15]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[15]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[15]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[15]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[15]->NotRange.Usage                        = 0x0002
+pp_data->cap[15]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[15]->NotRange.StringIndex                  = 0
+pp_data->cap[15]->NotRange.Reserved2                    = 0
+pp_data->cap[15]->NotRange.DesignatorIndex              = 0
+pp_data->cap[15]->NotRange.Reserved3                    = 0
+pp_data->cap[15]->NotRange.DataIndex                    = 15
+pp_data->cap[15]->NotRange.Reserved4                    = 15
+pp_data->cap[15]->Button.LogicalMin                   = 0
+pp_data->cap[15]->Button.LogicalMax                   = 0
+pp_data->cap[15]->Units                    = 0
+pp_data->cap[15]->UnitsExp                 = 0
+
+pp_data->cap[16]->UsagePage                    = 0xFF01
+pp_data->cap[16]->ReportID                     = 0x01
+pp_data->cap[16]->BitPosition                  = 3
+pp_data->cap[16]->BitSize                      = 1
+pp_data->cap[16]->ReportCount                  = 1
+pp_data->cap[16]->BytePosition                 = 0x0007
+pp_data->cap[16]->BitCount                     = 1
+pp_data->cap[16]->BitField                     = 0x02
+pp_data->cap[16]->NextBytePosition             = 0x0008
+pp_data->cap[16]->LinkCollection               = 0x0001
+pp_data->cap[16]->LinkUsagePage                = 0xFF01
+pp_data->cap[16]->LinkUsage                    = 0x0001
+pp_data->cap[16]->IsMultipleItemsForArray      = 0
+pp_data->cap[16]->IsButtonCap                  = 1
+pp_data->cap[16]->IsPadding                    = 0
+pp_data->cap[16]->IsAbsolute                   = 1
+pp_data->cap[16]->IsRange                      = 0
+pp_data->cap[16]->IsAlias                      = 0
+pp_data->cap[16]->IsStringRange                = 0
+pp_data->cap[16]->IsDesignatorRange            = 0
+pp_data->cap[16]->Reserved1                    = 0x000000
+pp_data->cap[16]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[16]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[16]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[16]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[16]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[16]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[16]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[16]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[16]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[16]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[16]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[16]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[16]->NotRange.Usage                        = 0x0002
+pp_data->cap[16]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[16]->NotRange.StringIndex                  = 0
+pp_data->cap[16]->NotRange.Reserved2                    = 0
+pp_data->cap[16]->NotRange.DesignatorIndex              = 0
+pp_data->cap[16]->NotRange.Reserved3                    = 0
+pp_data->cap[16]->NotRange.DataIndex                    = 16
+pp_data->cap[16]->NotRange.Reserved4                    = 16
+pp_data->cap[16]->Button.LogicalMin                   = 0
+pp_data->cap[16]->Button.LogicalMax                   = 0
+pp_data->cap[16]->Units                    = 0
+pp_data->cap[16]->UnitsExp                 = 0
+
+pp_data->cap[17]->UsagePage                    = 0xFF01
+pp_data->cap[17]->ReportID                     = 0x01
+pp_data->cap[17]->BitPosition                  = 2
+pp_data->cap[17]->BitSize                      = 1
+pp_data->cap[17]->ReportCount                  = 1
+pp_data->cap[17]->BytePosition                 = 0x0007
+pp_data->cap[17]->BitCount                     = 1
+pp_data->cap[17]->BitField                     = 0x02
+pp_data->cap[17]->NextBytePosition             = 0x0008
+pp_data->cap[17]->LinkCollection               = 0x0001
+pp_data->cap[17]->LinkUsagePage                = 0xFF01
+pp_data->cap[17]->LinkUsage                    = 0x0001
+pp_data->cap[17]->IsMultipleItemsForArray      = 0
+pp_data->cap[17]->IsButtonCap                  = 1
+pp_data->cap[17]->IsPadding                    = 0
+pp_data->cap[17]->IsAbsolute                   = 1
+pp_data->cap[17]->IsRange                      = 0
+pp_data->cap[17]->IsAlias                      = 0
+pp_data->cap[17]->IsStringRange                = 0
+pp_data->cap[17]->IsDesignatorRange            = 0
+pp_data->cap[17]->Reserved1                    = 0x000000
+pp_data->cap[17]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[17]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[17]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[17]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[17]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[17]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[17]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[17]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[17]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[17]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[17]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[17]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[17]->NotRange.Usage                        = 0x0002
+pp_data->cap[17]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[17]->NotRange.StringIndex                  = 0
+pp_data->cap[17]->NotRange.Reserved2                    = 0
+pp_data->cap[17]->NotRange.DesignatorIndex              = 0
+pp_data->cap[17]->NotRange.Reserved3                    = 0
+pp_data->cap[17]->NotRange.DataIndex                    = 17
+pp_data->cap[17]->NotRange.Reserved4                    = 17
+pp_data->cap[17]->Button.LogicalMin                   = 0
+pp_data->cap[17]->Button.LogicalMax                   = 0
+pp_data->cap[17]->Units                    = 0
+pp_data->cap[17]->UnitsExp                 = 0
+
+pp_data->cap[18]->UsagePage                    = 0xFF01
+pp_data->cap[18]->ReportID                     = 0x01
+pp_data->cap[18]->BitPosition                  = 1
+pp_data->cap[18]->BitSize                      = 1
+pp_data->cap[18]->ReportCount                  = 1
+pp_data->cap[18]->BytePosition                 = 0x0007
+pp_data->cap[18]->BitCount                     = 1
+pp_data->cap[18]->BitField                     = 0x02
+pp_data->cap[18]->NextBytePosition             = 0x0008
+pp_data->cap[18]->LinkCollection               = 0x0001
+pp_data->cap[18]->LinkUsagePage                = 0xFF01
+pp_data->cap[18]->LinkUsage                    = 0x0001
+pp_data->cap[18]->IsMultipleItemsForArray      = 0
+pp_data->cap[18]->IsButtonCap                  = 1
+pp_data->cap[18]->IsPadding                    = 0
+pp_data->cap[18]->IsAbsolute                   = 1
+pp_data->cap[18]->IsRange                      = 0
+pp_data->cap[18]->IsAlias                      = 0
+pp_data->cap[18]->IsStringRange                = 0
+pp_data->cap[18]->IsDesignatorRange            = 0
+pp_data->cap[18]->Reserved1                    = 0x000000
+pp_data->cap[18]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[18]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[18]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[18]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[18]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[18]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[18]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[18]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[18]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[18]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[18]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[18]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[18]->NotRange.Usage                        = 0x0002
+pp_data->cap[18]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[18]->NotRange.StringIndex                  = 0
+pp_data->cap[18]->NotRange.Reserved2                    = 0
+pp_data->cap[18]->NotRange.DesignatorIndex              = 0
+pp_data->cap[18]->NotRange.Reserved3                    = 0
+pp_data->cap[18]->NotRange.DataIndex                    = 18
+pp_data->cap[18]->NotRange.Reserved4                    = 18
+pp_data->cap[18]->Button.LogicalMin                   = 0
+pp_data->cap[18]->Button.LogicalMax                   = 0
+pp_data->cap[18]->Units                    = 0
+pp_data->cap[18]->UnitsExp                 = 0
+
+pp_data->cap[19]->UsagePage                    = 0xFF01
+pp_data->cap[19]->ReportID                     = 0x01
+pp_data->cap[19]->BitPosition                  = 0
+pp_data->cap[19]->BitSize                      = 1
+pp_data->cap[19]->ReportCount                  = 1
+pp_data->cap[19]->BytePosition                 = 0x0007
+pp_data->cap[19]->BitCount                     = 1
+pp_data->cap[19]->BitField                     = 0x02
+pp_data->cap[19]->NextBytePosition             = 0x0008
+pp_data->cap[19]->LinkCollection               = 0x0001
+pp_data->cap[19]->LinkUsagePage                = 0xFF01
+pp_data->cap[19]->LinkUsage                    = 0x0001
+pp_data->cap[19]->IsMultipleItemsForArray      = 0
+pp_data->cap[19]->IsButtonCap                  = 1
+pp_data->cap[19]->IsPadding                    = 0
+pp_data->cap[19]->IsAbsolute                   = 1
+pp_data->cap[19]->IsRange                      = 0
+pp_data->cap[19]->IsAlias                      = 0
+pp_data->cap[19]->IsStringRange                = 0
+pp_data->cap[19]->IsDesignatorRange            = 0
+pp_data->cap[19]->Reserved1                    = 0x000000
+pp_data->cap[19]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[19]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[19]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[19]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[19]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[19]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[19]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[19]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[19]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[19]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[19]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[19]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[19]->NotRange.Usage                        = 0x0002
+pp_data->cap[19]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[19]->NotRange.StringIndex                  = 0
+pp_data->cap[19]->NotRange.Reserved2                    = 0
+pp_data->cap[19]->NotRange.DesignatorIndex              = 0
+pp_data->cap[19]->NotRange.Reserved3                    = 0
+pp_data->cap[19]->NotRange.DataIndex                    = 19
+pp_data->cap[19]->NotRange.Reserved4                    = 19
+pp_data->cap[19]->Button.LogicalMin                   = 0
+pp_data->cap[19]->Button.LogicalMax                   = 0
+pp_data->cap[19]->Units                    = 0
+pp_data->cap[19]->UnitsExp                 = 0
+
+pp_data->cap[20]->UsagePage                    = 0xFF01
+pp_data->cap[20]->ReportID                     = 0x01
+pp_data->cap[20]->BitPosition                  = 7
+pp_data->cap[20]->BitSize                      = 1
+pp_data->cap[20]->ReportCount                  = 1
+pp_data->cap[20]->BytePosition                 = 0x0006
+pp_data->cap[20]->BitCount                     = 1
+pp_data->cap[20]->BitField                     = 0x02
+pp_data->cap[20]->NextBytePosition             = 0x0007
+pp_data->cap[20]->LinkCollection               = 0x0001
+pp_data->cap[20]->LinkUsagePage                = 0xFF01
+pp_data->cap[20]->LinkUsage                    = 0x0001
+pp_data->cap[20]->IsMultipleItemsForArray      = 0
+pp_data->cap[20]->IsButtonCap                  = 1
+pp_data->cap[20]->IsPadding                    = 0
+pp_data->cap[20]->IsAbsolute                   = 1
+pp_data->cap[20]->IsRange                      = 0
+pp_data->cap[20]->IsAlias                      = 0
+pp_data->cap[20]->IsStringRange                = 0
+pp_data->cap[20]->IsDesignatorRange            = 0
+pp_data->cap[20]->Reserved1                    = 0x000000
+pp_data->cap[20]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[20]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[20]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[20]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[20]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[20]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[20]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[20]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[20]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[20]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[20]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[20]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[20]->NotRange.Usage                        = 0x0002
+pp_data->cap[20]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[20]->NotRange.StringIndex                  = 0
+pp_data->cap[20]->NotRange.Reserved2                    = 0
+pp_data->cap[20]->NotRange.DesignatorIndex              = 0
+pp_data->cap[20]->NotRange.Reserved3                    = 0
+pp_data->cap[20]->NotRange.DataIndex                    = 20
+pp_data->cap[20]->NotRange.Reserved4                    = 20
+pp_data->cap[20]->Button.LogicalMin                   = 0
+pp_data->cap[20]->Button.LogicalMax                   = 0
+pp_data->cap[20]->Units                    = 0
+pp_data->cap[20]->UnitsExp                 = 0
+
+pp_data->cap[21]->UsagePage                    = 0xFF01
+pp_data->cap[21]->ReportID                     = 0x01
+pp_data->cap[21]->BitPosition                  = 6
+pp_data->cap[21]->BitSize                      = 1
+pp_data->cap[21]->ReportCount                  = 1
+pp_data->cap[21]->BytePosition                 = 0x0006
+pp_data->cap[21]->BitCount                     = 1
+pp_data->cap[21]->BitField                     = 0x02
+pp_data->cap[21]->NextBytePosition             = 0x0007
+pp_data->cap[21]->LinkCollection               = 0x0001
+pp_data->cap[21]->LinkUsagePage                = 0xFF01
+pp_data->cap[21]->LinkUsage                    = 0x0001
+pp_data->cap[21]->IsMultipleItemsForArray      = 0
+pp_data->cap[21]->IsButtonCap                  = 1
+pp_data->cap[21]->IsPadding                    = 0
+pp_data->cap[21]->IsAbsolute                   = 1
+pp_data->cap[21]->IsRange                      = 0
+pp_data->cap[21]->IsAlias                      = 0
+pp_data->cap[21]->IsStringRange                = 0
+pp_data->cap[21]->IsDesignatorRange            = 0
+pp_data->cap[21]->Reserved1                    = 0x000000
+pp_data->cap[21]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[21]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[21]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[21]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[21]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[21]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[21]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[21]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[21]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[21]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[21]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[21]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[21]->NotRange.Usage                        = 0x0002
+pp_data->cap[21]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[21]->NotRange.StringIndex                  = 0
+pp_data->cap[21]->NotRange.Reserved2                    = 0
+pp_data->cap[21]->NotRange.DesignatorIndex              = 0
+pp_data->cap[21]->NotRange.Reserved3                    = 0
+pp_data->cap[21]->NotRange.DataIndex                    = 21
+pp_data->cap[21]->NotRange.Reserved4                    = 21
+pp_data->cap[21]->Button.LogicalMin                   = 0
+pp_data->cap[21]->Button.LogicalMax                   = 0
+pp_data->cap[21]->Units                    = 0
+pp_data->cap[21]->UnitsExp                 = 0
+
+pp_data->cap[22]->UsagePage                    = 0xFF01
+pp_data->cap[22]->ReportID                     = 0x01
+pp_data->cap[22]->BitPosition                  = 5
+pp_data->cap[22]->BitSize                      = 1
+pp_data->cap[22]->ReportCount                  = 1
+pp_data->cap[22]->BytePosition                 = 0x0006
+pp_data->cap[22]->BitCount                     = 1
+pp_data->cap[22]->BitField                     = 0x02
+pp_data->cap[22]->NextBytePosition             = 0x0007
+pp_data->cap[22]->LinkCollection               = 0x0001
+pp_data->cap[22]->LinkUsagePage                = 0xFF01
+pp_data->cap[22]->LinkUsage                    = 0x0001
+pp_data->cap[22]->IsMultipleItemsForArray      = 0
+pp_data->cap[22]->IsButtonCap                  = 1
+pp_data->cap[22]->IsPadding                    = 0
+pp_data->cap[22]->IsAbsolute                   = 1
+pp_data->cap[22]->IsRange                      = 0
+pp_data->cap[22]->IsAlias                      = 0
+pp_data->cap[22]->IsStringRange                = 0
+pp_data->cap[22]->IsDesignatorRange            = 0
+pp_data->cap[22]->Reserved1                    = 0x000000
+pp_data->cap[22]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[22]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[22]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[22]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[22]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[22]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[22]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[22]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[22]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[22]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[22]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[22]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[22]->NotRange.Usage                        = 0x0002
+pp_data->cap[22]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[22]->NotRange.StringIndex                  = 0
+pp_data->cap[22]->NotRange.Reserved2                    = 0
+pp_data->cap[22]->NotRange.DesignatorIndex              = 0
+pp_data->cap[22]->NotRange.Reserved3                    = 0
+pp_data->cap[22]->NotRange.DataIndex                    = 22
+pp_data->cap[22]->NotRange.Reserved4                    = 22
+pp_data->cap[22]->Button.LogicalMin                   = 0
+pp_data->cap[22]->Button.LogicalMax                   = 0
+pp_data->cap[22]->Units                    = 0
+pp_data->cap[22]->UnitsExp                 = 0
+
+pp_data->cap[23]->UsagePage                    = 0xFF01
+pp_data->cap[23]->ReportID                     = 0x01
+pp_data->cap[23]->BitPosition                  = 4
+pp_data->cap[23]->BitSize                      = 1
+pp_data->cap[23]->ReportCount                  = 1
+pp_data->cap[23]->BytePosition                 = 0x0006
+pp_data->cap[23]->BitCount                     = 1
+pp_data->cap[23]->BitField                     = 0x02
+pp_data->cap[23]->NextBytePosition             = 0x0007
+pp_data->cap[23]->LinkCollection               = 0x0001
+pp_data->cap[23]->LinkUsagePage                = 0xFF01
+pp_data->cap[23]->LinkUsage                    = 0x0001
+pp_data->cap[23]->IsMultipleItemsForArray      = 0
+pp_data->cap[23]->IsButtonCap                  = 1
+pp_data->cap[23]->IsPadding                    = 0
+pp_data->cap[23]->IsAbsolute                   = 1
+pp_data->cap[23]->IsRange                      = 0
+pp_data->cap[23]->IsAlias                      = 0
+pp_data->cap[23]->IsStringRange                = 0
+pp_data->cap[23]->IsDesignatorRange            = 0
+pp_data->cap[23]->Reserved1                    = 0x000000
+pp_data->cap[23]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[23]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[23]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[23]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[23]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[23]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[23]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[23]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[23]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[23]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[23]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[23]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[23]->NotRange.Usage                        = 0x0002
+pp_data->cap[23]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[23]->NotRange.StringIndex                  = 0
+pp_data->cap[23]->NotRange.Reserved2                    = 0
+pp_data->cap[23]->NotRange.DesignatorIndex              = 0
+pp_data->cap[23]->NotRange.Reserved3                    = 0
+pp_data->cap[23]->NotRange.DataIndex                    = 23
+pp_data->cap[23]->NotRange.Reserved4                    = 23
+pp_data->cap[23]->Button.LogicalMin                   = 0
+pp_data->cap[23]->Button.LogicalMax                   = 0
+pp_data->cap[23]->Units                    = 0
+pp_data->cap[23]->UnitsExp                 = 0
+
+pp_data->cap[24]->UsagePage                    = 0xFF01
+pp_data->cap[24]->ReportID                     = 0x01
+pp_data->cap[24]->BitPosition                  = 3
+pp_data->cap[24]->BitSize                      = 1
+pp_data->cap[24]->ReportCount                  = 1
+pp_data->cap[24]->BytePosition                 = 0x0006
+pp_data->cap[24]->BitCount                     = 1
+pp_data->cap[24]->BitField                     = 0x02
+pp_data->cap[24]->NextBytePosition             = 0x0007
+pp_data->cap[24]->LinkCollection               = 0x0001
+pp_data->cap[24]->LinkUsagePage                = 0xFF01
+pp_data->cap[24]->LinkUsage                    = 0x0001
+pp_data->cap[24]->IsMultipleItemsForArray      = 0
+pp_data->cap[24]->IsButtonCap                  = 1
+pp_data->cap[24]->IsPadding                    = 0
+pp_data->cap[24]->IsAbsolute                   = 1
+pp_data->cap[24]->IsRange                      = 0
+pp_data->cap[24]->IsAlias                      = 0
+pp_data->cap[24]->IsStringRange                = 0
+pp_data->cap[24]->IsDesignatorRange            = 0
+pp_data->cap[24]->Reserved1                    = 0x000000
+pp_data->cap[24]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[24]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[24]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[24]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[24]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[24]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[24]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[24]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[24]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[24]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[24]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[24]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[24]->NotRange.Usage                        = 0x0002
+pp_data->cap[24]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[24]->NotRange.StringIndex                  = 0
+pp_data->cap[24]->NotRange.Reserved2                    = 0
+pp_data->cap[24]->NotRange.DesignatorIndex              = 0
+pp_data->cap[24]->NotRange.Reserved3                    = 0
+pp_data->cap[24]->NotRange.DataIndex                    = 24
+pp_data->cap[24]->NotRange.Reserved4                    = 24
+pp_data->cap[24]->Button.LogicalMin                   = 0
+pp_data->cap[24]->Button.LogicalMax                   = 0
+pp_data->cap[24]->Units                    = 0
+pp_data->cap[24]->UnitsExp                 = 0
+
+pp_data->cap[25]->UsagePage                    = 0xFF01
+pp_data->cap[25]->ReportID                     = 0x01
+pp_data->cap[25]->BitPosition                  = 2
+pp_data->cap[25]->BitSize                      = 1
+pp_data->cap[25]->ReportCount                  = 1
+pp_data->cap[25]->BytePosition                 = 0x0006
+pp_data->cap[25]->BitCount                     = 1
+pp_data->cap[25]->BitField                     = 0x02
+pp_data->cap[25]->NextBytePosition             = 0x0007
+pp_data->cap[25]->LinkCollection               = 0x0001
+pp_data->cap[25]->LinkUsagePage                = 0xFF01
+pp_data->cap[25]->LinkUsage                    = 0x0001
+pp_data->cap[25]->IsMultipleItemsForArray      = 0
+pp_data->cap[25]->IsButtonCap                  = 1
+pp_data->cap[25]->IsPadding                    = 0
+pp_data->cap[25]->IsAbsolute                   = 1
+pp_data->cap[25]->IsRange                      = 0
+pp_data->cap[25]->IsAlias                      = 0
+pp_data->cap[25]->IsStringRange                = 0
+pp_data->cap[25]->IsDesignatorRange            = 0
+pp_data->cap[25]->Reserved1                    = 0x000000
+pp_data->cap[25]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[25]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[25]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[25]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[25]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[25]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[25]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[25]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[25]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[25]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[25]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[25]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[25]->NotRange.Usage                        = 0x0002
+pp_data->cap[25]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[25]->NotRange.StringIndex                  = 0
+pp_data->cap[25]->NotRange.Reserved2                    = 0
+pp_data->cap[25]->NotRange.DesignatorIndex              = 0
+pp_data->cap[25]->NotRange.Reserved3                    = 0
+pp_data->cap[25]->NotRange.DataIndex                    = 25
+pp_data->cap[25]->NotRange.Reserved4                    = 25
+pp_data->cap[25]->Button.LogicalMin                   = 0
+pp_data->cap[25]->Button.LogicalMax                   = 0
+pp_data->cap[25]->Units                    = 0
+pp_data->cap[25]->UnitsExp                 = 0
+
+pp_data->cap[26]->UsagePage                    = 0xFF01
+pp_data->cap[26]->ReportID                     = 0x01
+pp_data->cap[26]->BitPosition                  = 1
+pp_data->cap[26]->BitSize                      = 1
+pp_data->cap[26]->ReportCount                  = 1
+pp_data->cap[26]->BytePosition                 = 0x0006
+pp_data->cap[26]->BitCount                     = 1
+pp_data->cap[26]->BitField                     = 0x02
+pp_data->cap[26]->NextBytePosition             = 0x0007
+pp_data->cap[26]->LinkCollection               = 0x0001
+pp_data->cap[26]->LinkUsagePage                = 0xFF01
+pp_data->cap[26]->LinkUsage                    = 0x0001
+pp_data->cap[26]->IsMultipleItemsForArray      = 0
+pp_data->cap[26]->IsButtonCap                  = 1
+pp_data->cap[26]->IsPadding                    = 0
+pp_data->cap[26]->IsAbsolute                   = 1
+pp_data->cap[26]->IsRange                      = 0
+pp_data->cap[26]->IsAlias                      = 0
+pp_data->cap[26]->IsStringRange                = 0
+pp_data->cap[26]->IsDesignatorRange            = 0
+pp_data->cap[26]->Reserved1                    = 0x000000
+pp_data->cap[26]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[26]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[26]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[26]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[26]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[26]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[26]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[26]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[26]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[26]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[26]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[26]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[26]->NotRange.Usage                        = 0x0002
+pp_data->cap[26]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[26]->NotRange.StringIndex                  = 0
+pp_data->cap[26]->NotRange.Reserved2                    = 0
+pp_data->cap[26]->NotRange.DesignatorIndex              = 0
+pp_data->cap[26]->NotRange.Reserved3                    = 0
+pp_data->cap[26]->NotRange.DataIndex                    = 26
+pp_data->cap[26]->NotRange.Reserved4                    = 26
+pp_data->cap[26]->Button.LogicalMin                   = 0
+pp_data->cap[26]->Button.LogicalMax                   = 0
+pp_data->cap[26]->Units                    = 0
+pp_data->cap[26]->UnitsExp                 = 0
+
+pp_data->cap[27]->UsagePage                    = 0xFF01
+pp_data->cap[27]->ReportID                     = 0x01
+pp_data->cap[27]->BitPosition                  = 0
+pp_data->cap[27]->BitSize                      = 1
+pp_data->cap[27]->ReportCount                  = 1
+pp_data->cap[27]->BytePosition                 = 0x0006
+pp_data->cap[27]->BitCount                     = 1
+pp_data->cap[27]->BitField                     = 0x02
+pp_data->cap[27]->NextBytePosition             = 0x0007
+pp_data->cap[27]->LinkCollection               = 0x0001
+pp_data->cap[27]->LinkUsagePage                = 0xFF01
+pp_data->cap[27]->LinkUsage                    = 0x0001
+pp_data->cap[27]->IsMultipleItemsForArray      = 0
+pp_data->cap[27]->IsButtonCap                  = 1
+pp_data->cap[27]->IsPadding                    = 0
+pp_data->cap[27]->IsAbsolute                   = 1
+pp_data->cap[27]->IsRange                      = 0
+pp_data->cap[27]->IsAlias                      = 0
+pp_data->cap[27]->IsStringRange                = 0
+pp_data->cap[27]->IsDesignatorRange            = 0
+pp_data->cap[27]->Reserved1                    = 0x000000
+pp_data->cap[27]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[27]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[27]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[27]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[27]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[27]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[27]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[27]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[27]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[27]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[27]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[27]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[27]->NotRange.Usage                        = 0x0002
+pp_data->cap[27]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[27]->NotRange.StringIndex                  = 0
+pp_data->cap[27]->NotRange.Reserved2                    = 0
+pp_data->cap[27]->NotRange.DesignatorIndex              = 0
+pp_data->cap[27]->NotRange.Reserved3                    = 0
+pp_data->cap[27]->NotRange.DataIndex                    = 27
+pp_data->cap[27]->NotRange.Reserved4                    = 27
+pp_data->cap[27]->Button.LogicalMin                   = 0
+pp_data->cap[27]->Button.LogicalMax                   = 0
+pp_data->cap[27]->Units                    = 0
+pp_data->cap[27]->UnitsExp                 = 0
+
+pp_data->cap[28]->UsagePage                    = 0xFF01
+pp_data->cap[28]->ReportID                     = 0x01
+pp_data->cap[28]->BitPosition                  = 7
+pp_data->cap[28]->BitSize                      = 1
+pp_data->cap[28]->ReportCount                  = 1
+pp_data->cap[28]->BytePosition                 = 0x0005
+pp_data->cap[28]->BitCount                     = 1
+pp_data->cap[28]->BitField                     = 0x02
+pp_data->cap[28]->NextBytePosition             = 0x0006
+pp_data->cap[28]->LinkCollection               = 0x0001
+pp_data->cap[28]->LinkUsagePage                = 0xFF01
+pp_data->cap[28]->LinkUsage                    = 0x0001
+pp_data->cap[28]->IsMultipleItemsForArray      = 0
+pp_data->cap[28]->IsButtonCap                  = 1
+pp_data->cap[28]->IsPadding                    = 0
+pp_data->cap[28]->IsAbsolute                   = 1
+pp_data->cap[28]->IsRange                      = 0
+pp_data->cap[28]->IsAlias                      = 0
+pp_data->cap[28]->IsStringRange                = 0
+pp_data->cap[28]->IsDesignatorRange            = 0
+pp_data->cap[28]->Reserved1                    = 0x000000
+pp_data->cap[28]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[28]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[28]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[28]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[28]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[28]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[28]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[28]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[28]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[28]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[28]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[28]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[28]->NotRange.Usage                        = 0x0002
+pp_data->cap[28]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[28]->NotRange.StringIndex                  = 0
+pp_data->cap[28]->NotRange.Reserved2                    = 0
+pp_data->cap[28]->NotRange.DesignatorIndex              = 0
+pp_data->cap[28]->NotRange.Reserved3                    = 0
+pp_data->cap[28]->NotRange.DataIndex                    = 28
+pp_data->cap[28]->NotRange.Reserved4                    = 28
+pp_data->cap[28]->Button.LogicalMin                   = 0
+pp_data->cap[28]->Button.LogicalMax                   = 0
+pp_data->cap[28]->Units                    = 0
+pp_data->cap[28]->UnitsExp                 = 0
+
+pp_data->cap[29]->UsagePage                    = 0xFF01
+pp_data->cap[29]->ReportID                     = 0x01
+pp_data->cap[29]->BitPosition                  = 6
+pp_data->cap[29]->BitSize                      = 1
+pp_data->cap[29]->ReportCount                  = 1
+pp_data->cap[29]->BytePosition                 = 0x0005
+pp_data->cap[29]->BitCount                     = 1
+pp_data->cap[29]->BitField                     = 0x02
+pp_data->cap[29]->NextBytePosition             = 0x0006
+pp_data->cap[29]->LinkCollection               = 0x0001
+pp_data->cap[29]->LinkUsagePage                = 0xFF01
+pp_data->cap[29]->LinkUsage                    = 0x0001
+pp_data->cap[29]->IsMultipleItemsForArray      = 0
+pp_data->cap[29]->IsButtonCap                  = 1
+pp_data->cap[29]->IsPadding                    = 0
+pp_data->cap[29]->IsAbsolute                   = 1
+pp_data->cap[29]->IsRange                      = 0
+pp_data->cap[29]->IsAlias                      = 0
+pp_data->cap[29]->IsStringRange                = 0
+pp_data->cap[29]->IsDesignatorRange            = 0
+pp_data->cap[29]->Reserved1                    = 0x000000
+pp_data->cap[29]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[29]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[29]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[29]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[29]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[29]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[29]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[29]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[29]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[29]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[29]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[29]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[29]->NotRange.Usage                        = 0x0002
+pp_data->cap[29]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[29]->NotRange.StringIndex                  = 0
+pp_data->cap[29]->NotRange.Reserved2                    = 0
+pp_data->cap[29]->NotRange.DesignatorIndex              = 0
+pp_data->cap[29]->NotRange.Reserved3                    = 0
+pp_data->cap[29]->NotRange.DataIndex                    = 29
+pp_data->cap[29]->NotRange.Reserved4                    = 29
+pp_data->cap[29]->Button.LogicalMin                   = 0
+pp_data->cap[29]->Button.LogicalMax                   = 0
+pp_data->cap[29]->Units                    = 0
+pp_data->cap[29]->UnitsExp                 = 0
+
+pp_data->cap[30]->UsagePage                    = 0xFF01
+pp_data->cap[30]->ReportID                     = 0x01
+pp_data->cap[30]->BitPosition                  = 5
+pp_data->cap[30]->BitSize                      = 1
+pp_data->cap[30]->ReportCount                  = 1
+pp_data->cap[30]->BytePosition                 = 0x0005
+pp_data->cap[30]->BitCount                     = 1
+pp_data->cap[30]->BitField                     = 0x02
+pp_data->cap[30]->NextBytePosition             = 0x0006
+pp_data->cap[30]->LinkCollection               = 0x0001
+pp_data->cap[30]->LinkUsagePage                = 0xFF01
+pp_data->cap[30]->LinkUsage                    = 0x0001
+pp_data->cap[30]->IsMultipleItemsForArray      = 0
+pp_data->cap[30]->IsButtonCap                  = 1
+pp_data->cap[30]->IsPadding                    = 0
+pp_data->cap[30]->IsAbsolute                   = 1
+pp_data->cap[30]->IsRange                      = 0
+pp_data->cap[30]->IsAlias                      = 0
+pp_data->cap[30]->IsStringRange                = 0
+pp_data->cap[30]->IsDesignatorRange            = 0
+pp_data->cap[30]->Reserved1                    = 0x000000
+pp_data->cap[30]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[30]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[30]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[30]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[30]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[30]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[30]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[30]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[30]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[30]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[30]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[30]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[30]->NotRange.Usage                        = 0x0002
+pp_data->cap[30]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[30]->NotRange.StringIndex                  = 0
+pp_data->cap[30]->NotRange.Reserved2                    = 0
+pp_data->cap[30]->NotRange.DesignatorIndex              = 0
+pp_data->cap[30]->NotRange.Reserved3                    = 0
+pp_data->cap[30]->NotRange.DataIndex                    = 30
+pp_data->cap[30]->NotRange.Reserved4                    = 30
+pp_data->cap[30]->Button.LogicalMin                   = 0
+pp_data->cap[30]->Button.LogicalMax                   = 0
+pp_data->cap[30]->Units                    = 0
+pp_data->cap[30]->UnitsExp                 = 0
+
+pp_data->cap[31]->UsagePage                    = 0xFF01
+pp_data->cap[31]->ReportID                     = 0x01
+pp_data->cap[31]->BitPosition                  = 4
+pp_data->cap[31]->BitSize                      = 1
+pp_data->cap[31]->ReportCount                  = 1
+pp_data->cap[31]->BytePosition                 = 0x0005
+pp_data->cap[31]->BitCount                     = 1
+pp_data->cap[31]->BitField                     = 0x02
+pp_data->cap[31]->NextBytePosition             = 0x0006
+pp_data->cap[31]->LinkCollection               = 0x0001
+pp_data->cap[31]->LinkUsagePage                = 0xFF01
+pp_data->cap[31]->LinkUsage                    = 0x0001
+pp_data->cap[31]->IsMultipleItemsForArray      = 0
+pp_data->cap[31]->IsButtonCap                  = 1
+pp_data->cap[31]->IsPadding                    = 0
+pp_data->cap[31]->IsAbsolute                   = 1
+pp_data->cap[31]->IsRange                      = 0
+pp_data->cap[31]->IsAlias                      = 0
+pp_data->cap[31]->IsStringRange                = 0
+pp_data->cap[31]->IsDesignatorRange            = 0
+pp_data->cap[31]->Reserved1                    = 0x000000
+pp_data->cap[31]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[31]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[31]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[31]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[31]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[31]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[31]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[31]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[31]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[31]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[31]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[31]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[31]->NotRange.Usage                        = 0x0002
+pp_data->cap[31]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[31]->NotRange.StringIndex                  = 0
+pp_data->cap[31]->NotRange.Reserved2                    = 0
+pp_data->cap[31]->NotRange.DesignatorIndex              = 0
+pp_data->cap[31]->NotRange.Reserved3                    = 0
+pp_data->cap[31]->NotRange.DataIndex                    = 31
+pp_data->cap[31]->NotRange.Reserved4                    = 31
+pp_data->cap[31]->Button.LogicalMin                   = 0
+pp_data->cap[31]->Button.LogicalMax                   = 0
+pp_data->cap[31]->Units                    = 0
+pp_data->cap[31]->UnitsExp                 = 0
+
+pp_data->cap[32]->UsagePage                    = 0xFF01
+pp_data->cap[32]->ReportID                     = 0x01
+pp_data->cap[32]->BitPosition                  = 3
+pp_data->cap[32]->BitSize                      = 1
+pp_data->cap[32]->ReportCount                  = 1
+pp_data->cap[32]->BytePosition                 = 0x0005
+pp_data->cap[32]->BitCount                     = 1
+pp_data->cap[32]->BitField                     = 0x02
+pp_data->cap[32]->NextBytePosition             = 0x0006
+pp_data->cap[32]->LinkCollection               = 0x0001
+pp_data->cap[32]->LinkUsagePage                = 0xFF01
+pp_data->cap[32]->LinkUsage                    = 0x0001
+pp_data->cap[32]->IsMultipleItemsForArray      = 0
+pp_data->cap[32]->IsButtonCap                  = 1
+pp_data->cap[32]->IsPadding                    = 0
+pp_data->cap[32]->IsAbsolute                   = 1
+pp_data->cap[32]->IsRange                      = 0
+pp_data->cap[32]->IsAlias                      = 0
+pp_data->cap[32]->IsStringRange                = 0
+pp_data->cap[32]->IsDesignatorRange            = 0
+pp_data->cap[32]->Reserved1                    = 0x000000
+pp_data->cap[32]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[32]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[32]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[32]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[32]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[32]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[32]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[32]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[32]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[32]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[32]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[32]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[32]->NotRange.Usage                        = 0x0002
+pp_data->cap[32]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[32]->NotRange.StringIndex                  = 0
+pp_data->cap[32]->NotRange.Reserved2                    = 0
+pp_data->cap[32]->NotRange.DesignatorIndex              = 0
+pp_data->cap[32]->NotRange.Reserved3                    = 0
+pp_data->cap[32]->NotRange.DataIndex                    = 32
+pp_data->cap[32]->NotRange.Reserved4                    = 32
+pp_data->cap[32]->Button.LogicalMin                   = 0
+pp_data->cap[32]->Button.LogicalMax                   = 0
+pp_data->cap[32]->Units                    = 0
+pp_data->cap[32]->UnitsExp                 = 0
+
+pp_data->cap[33]->UsagePage                    = 0xFF01
+pp_data->cap[33]->ReportID                     = 0x01
+pp_data->cap[33]->BitPosition                  = 2
+pp_data->cap[33]->BitSize                      = 1
+pp_data->cap[33]->ReportCount                  = 1
+pp_data->cap[33]->BytePosition                 = 0x0005
+pp_data->cap[33]->BitCount                     = 1
+pp_data->cap[33]->BitField                     = 0x02
+pp_data->cap[33]->NextBytePosition             = 0x0006
+pp_data->cap[33]->LinkCollection               = 0x0001
+pp_data->cap[33]->LinkUsagePage                = 0xFF01
+pp_data->cap[33]->LinkUsage                    = 0x0001
+pp_data->cap[33]->IsMultipleItemsForArray      = 0
+pp_data->cap[33]->IsButtonCap                  = 1
+pp_data->cap[33]->IsPadding                    = 0
+pp_data->cap[33]->IsAbsolute                   = 1
+pp_data->cap[33]->IsRange                      = 0
+pp_data->cap[33]->IsAlias                      = 0
+pp_data->cap[33]->IsStringRange                = 0
+pp_data->cap[33]->IsDesignatorRange            = 0
+pp_data->cap[33]->Reserved1                    = 0x000000
+pp_data->cap[33]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[33]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[33]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[33]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[33]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[33]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[33]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[33]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[33]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[33]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[33]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[33]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[33]->NotRange.Usage                        = 0x0002
+pp_data->cap[33]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[33]->NotRange.StringIndex                  = 0
+pp_data->cap[33]->NotRange.Reserved2                    = 0
+pp_data->cap[33]->NotRange.DesignatorIndex              = 0
+pp_data->cap[33]->NotRange.Reserved3                    = 0
+pp_data->cap[33]->NotRange.DataIndex                    = 33
+pp_data->cap[33]->NotRange.Reserved4                    = 33
+pp_data->cap[33]->Button.LogicalMin                   = 0
+pp_data->cap[33]->Button.LogicalMax                   = 0
+pp_data->cap[33]->Units                    = 0
+pp_data->cap[33]->UnitsExp                 = 0
+
+pp_data->cap[34]->UsagePage                    = 0xFF01
+pp_data->cap[34]->ReportID                     = 0x01
+pp_data->cap[34]->BitPosition                  = 1
+pp_data->cap[34]->BitSize                      = 1
+pp_data->cap[34]->ReportCount                  = 1
+pp_data->cap[34]->BytePosition                 = 0x0005
+pp_data->cap[34]->BitCount                     = 1
+pp_data->cap[34]->BitField                     = 0x02
+pp_data->cap[34]->NextBytePosition             = 0x0006
+pp_data->cap[34]->LinkCollection               = 0x0001
+pp_data->cap[34]->LinkUsagePage                = 0xFF01
+pp_data->cap[34]->LinkUsage                    = 0x0001
+pp_data->cap[34]->IsMultipleItemsForArray      = 0
+pp_data->cap[34]->IsButtonCap                  = 1
+pp_data->cap[34]->IsPadding                    = 0
+pp_data->cap[34]->IsAbsolute                   = 1
+pp_data->cap[34]->IsRange                      = 0
+pp_data->cap[34]->IsAlias                      = 0
+pp_data->cap[34]->IsStringRange                = 0
+pp_data->cap[34]->IsDesignatorRange            = 0
+pp_data->cap[34]->Reserved1                    = 0x000000
+pp_data->cap[34]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[34]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[34]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[34]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[34]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[34]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[34]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[34]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[34]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[34]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[34]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[34]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[34]->NotRange.Usage                        = 0x0002
+pp_data->cap[34]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[34]->NotRange.StringIndex                  = 0
+pp_data->cap[34]->NotRange.Reserved2                    = 0
+pp_data->cap[34]->NotRange.DesignatorIndex              = 0
+pp_data->cap[34]->NotRange.Reserved3                    = 0
+pp_data->cap[34]->NotRange.DataIndex                    = 34
+pp_data->cap[34]->NotRange.Reserved4                    = 34
+pp_data->cap[34]->Button.LogicalMin                   = 0
+pp_data->cap[34]->Button.LogicalMax                   = 0
+pp_data->cap[34]->Units                    = 0
+pp_data->cap[34]->UnitsExp                 = 0
+
+pp_data->cap[35]->UsagePage                    = 0xFF01
+pp_data->cap[35]->ReportID                     = 0x01
+pp_data->cap[35]->BitPosition                  = 0
+pp_data->cap[35]->BitSize                      = 1
+pp_data->cap[35]->ReportCount                  = 1
+pp_data->cap[35]->BytePosition                 = 0x0005
+pp_data->cap[35]->BitCount                     = 1
+pp_data->cap[35]->BitField                     = 0x02
+pp_data->cap[35]->NextBytePosition             = 0x0006
+pp_data->cap[35]->LinkCollection               = 0x0001
+pp_data->cap[35]->LinkUsagePage                = 0xFF01
+pp_data->cap[35]->LinkUsage                    = 0x0001
+pp_data->cap[35]->IsMultipleItemsForArray      = 0
+pp_data->cap[35]->IsButtonCap                  = 1
+pp_data->cap[35]->IsPadding                    = 0
+pp_data->cap[35]->IsAbsolute                   = 1
+pp_data->cap[35]->IsRange                      = 0
+pp_data->cap[35]->IsAlias                      = 0
+pp_data->cap[35]->IsStringRange                = 0
+pp_data->cap[35]->IsDesignatorRange            = 0
+pp_data->cap[35]->Reserved1                    = 0x000000
+pp_data->cap[35]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[35]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[35]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[35]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[35]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[35]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[35]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[35]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[35]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[35]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[35]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[35]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[35]->NotRange.Usage                        = 0x0002
+pp_data->cap[35]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[35]->NotRange.StringIndex                  = 0
+pp_data->cap[35]->NotRange.Reserved2                    = 0
+pp_data->cap[35]->NotRange.DesignatorIndex              = 0
+pp_data->cap[35]->NotRange.Reserved3                    = 0
+pp_data->cap[35]->NotRange.DataIndex                    = 35
+pp_data->cap[35]->NotRange.Reserved4                    = 35
+pp_data->cap[35]->Button.LogicalMin                   = 0
+pp_data->cap[35]->Button.LogicalMax                   = 0
+pp_data->cap[35]->Units                    = 0
+pp_data->cap[35]->UnitsExp                 = 0
+
+pp_data->cap[36]->UsagePage                    = 0xFF01
+pp_data->cap[36]->ReportID                     = 0x01
+pp_data->cap[36]->BitPosition                  = 7
+pp_data->cap[36]->BitSize                      = 1
+pp_data->cap[36]->ReportCount                  = 1
+pp_data->cap[36]->BytePosition                 = 0x0004
+pp_data->cap[36]->BitCount                     = 1
+pp_data->cap[36]->BitField                     = 0x02
+pp_data->cap[36]->NextBytePosition             = 0x0005
+pp_data->cap[36]->LinkCollection               = 0x0001
+pp_data->cap[36]->LinkUsagePage                = 0xFF01
+pp_data->cap[36]->LinkUsage                    = 0x0001
+pp_data->cap[36]->IsMultipleItemsForArray      = 0
+pp_data->cap[36]->IsButtonCap                  = 1
+pp_data->cap[36]->IsPadding                    = 0
+pp_data->cap[36]->IsAbsolute                   = 1
+pp_data->cap[36]->IsRange                      = 0
+pp_data->cap[36]->IsAlias                      = 0
+pp_data->cap[36]->IsStringRange                = 0
+pp_data->cap[36]->IsDesignatorRange            = 0
+pp_data->cap[36]->Reserved1                    = 0x000000
+pp_data->cap[36]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[36]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[36]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[36]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[36]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[36]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[36]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[36]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[36]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[36]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[36]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[36]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[36]->NotRange.Usage                        = 0x0002
+pp_data->cap[36]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[36]->NotRange.StringIndex                  = 0
+pp_data->cap[36]->NotRange.Reserved2                    = 0
+pp_data->cap[36]->NotRange.DesignatorIndex              = 0
+pp_data->cap[36]->NotRange.Reserved3                    = 0
+pp_data->cap[36]->NotRange.DataIndex                    = 36
+pp_data->cap[36]->NotRange.Reserved4                    = 36
+pp_data->cap[36]->Button.LogicalMin                   = 0
+pp_data->cap[36]->Button.LogicalMax                   = 0
+pp_data->cap[36]->Units                    = 0
+pp_data->cap[36]->UnitsExp                 = 0
+
+pp_data->cap[37]->UsagePage                    = 0xFF01
+pp_data->cap[37]->ReportID                     = 0x01
+pp_data->cap[37]->BitPosition                  = 6
+pp_data->cap[37]->BitSize                      = 1
+pp_data->cap[37]->ReportCount                  = 1
+pp_data->cap[37]->BytePosition                 = 0x0004
+pp_data->cap[37]->BitCount                     = 1
+pp_data->cap[37]->BitField                     = 0x02
+pp_data->cap[37]->NextBytePosition             = 0x0005
+pp_data->cap[37]->LinkCollection               = 0x0001
+pp_data->cap[37]->LinkUsagePage                = 0xFF01
+pp_data->cap[37]->LinkUsage                    = 0x0001
+pp_data->cap[37]->IsMultipleItemsForArray      = 0
+pp_data->cap[37]->IsButtonCap                  = 1
+pp_data->cap[37]->IsPadding                    = 0
+pp_data->cap[37]->IsAbsolute                   = 1
+pp_data->cap[37]->IsRange                      = 0
+pp_data->cap[37]->IsAlias                      = 0
+pp_data->cap[37]->IsStringRange                = 0
+pp_data->cap[37]->IsDesignatorRange            = 0
+pp_data->cap[37]->Reserved1                    = 0x000000
+pp_data->cap[37]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[37]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[37]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[37]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[37]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[37]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[37]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[37]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[37]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[37]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[37]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[37]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[37]->NotRange.Usage                        = 0x0002
+pp_data->cap[37]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[37]->NotRange.StringIndex                  = 0
+pp_data->cap[37]->NotRange.Reserved2                    = 0
+pp_data->cap[37]->NotRange.DesignatorIndex              = 0
+pp_data->cap[37]->NotRange.Reserved3                    = 0
+pp_data->cap[37]->NotRange.DataIndex                    = 37
+pp_data->cap[37]->NotRange.Reserved4                    = 37
+pp_data->cap[37]->Button.LogicalMin                   = 0
+pp_data->cap[37]->Button.LogicalMax                   = 0
+pp_data->cap[37]->Units                    = 0
+pp_data->cap[37]->UnitsExp                 = 0
+
+pp_data->cap[38]->UsagePage                    = 0xFF01
+pp_data->cap[38]->ReportID                     = 0x01
+pp_data->cap[38]->BitPosition                  = 5
+pp_data->cap[38]->BitSize                      = 1
+pp_data->cap[38]->ReportCount                  = 1
+pp_data->cap[38]->BytePosition                 = 0x0004
+pp_data->cap[38]->BitCount                     = 1
+pp_data->cap[38]->BitField                     = 0x02
+pp_data->cap[38]->NextBytePosition             = 0x0005
+pp_data->cap[38]->LinkCollection               = 0x0001
+pp_data->cap[38]->LinkUsagePage                = 0xFF01
+pp_data->cap[38]->LinkUsage                    = 0x0001
+pp_data->cap[38]->IsMultipleItemsForArray      = 0
+pp_data->cap[38]->IsButtonCap                  = 1
+pp_data->cap[38]->IsPadding                    = 0
+pp_data->cap[38]->IsAbsolute                   = 1
+pp_data->cap[38]->IsRange                      = 0
+pp_data->cap[38]->IsAlias                      = 0
+pp_data->cap[38]->IsStringRange                = 0
+pp_data->cap[38]->IsDesignatorRange            = 0
+pp_data->cap[38]->Reserved1                    = 0x000000
+pp_data->cap[38]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[38]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[38]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[38]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[38]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[38]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[38]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[38]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[38]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[38]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[38]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[38]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[38]->NotRange.Usage                        = 0x0002
+pp_data->cap[38]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[38]->NotRange.StringIndex                  = 0
+pp_data->cap[38]->NotRange.Reserved2                    = 0
+pp_data->cap[38]->NotRange.DesignatorIndex              = 0
+pp_data->cap[38]->NotRange.Reserved3                    = 0
+pp_data->cap[38]->NotRange.DataIndex                    = 38
+pp_data->cap[38]->NotRange.Reserved4                    = 38
+pp_data->cap[38]->Button.LogicalMin                   = 0
+pp_data->cap[38]->Button.LogicalMax                   = 0
+pp_data->cap[38]->Units                    = 0
+pp_data->cap[38]->UnitsExp                 = 0
+
+pp_data->cap[39]->UsagePage                    = 0xFF01
+pp_data->cap[39]->ReportID                     = 0x01
+pp_data->cap[39]->BitPosition                  = 4
+pp_data->cap[39]->BitSize                      = 1
+pp_data->cap[39]->ReportCount                  = 1
+pp_data->cap[39]->BytePosition                 = 0x0004
+pp_data->cap[39]->BitCount                     = 1
+pp_data->cap[39]->BitField                     = 0x02
+pp_data->cap[39]->NextBytePosition             = 0x0005
+pp_data->cap[39]->LinkCollection               = 0x0001
+pp_data->cap[39]->LinkUsagePage                = 0xFF01
+pp_data->cap[39]->LinkUsage                    = 0x0001
+pp_data->cap[39]->IsMultipleItemsForArray      = 0
+pp_data->cap[39]->IsButtonCap                  = 1
+pp_data->cap[39]->IsPadding                    = 0
+pp_data->cap[39]->IsAbsolute                   = 1
+pp_data->cap[39]->IsRange                      = 0
+pp_data->cap[39]->IsAlias                      = 0
+pp_data->cap[39]->IsStringRange                = 0
+pp_data->cap[39]->IsDesignatorRange            = 0
+pp_data->cap[39]->Reserved1                    = 0x000000
+pp_data->cap[39]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[39]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[39]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[39]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[39]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[39]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[39]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[39]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[39]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[39]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[39]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[39]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[39]->NotRange.Usage                        = 0x0002
+pp_data->cap[39]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[39]->NotRange.StringIndex                  = 0
+pp_data->cap[39]->NotRange.Reserved2                    = 0
+pp_data->cap[39]->NotRange.DesignatorIndex              = 0
+pp_data->cap[39]->NotRange.Reserved3                    = 0
+pp_data->cap[39]->NotRange.DataIndex                    = 39
+pp_data->cap[39]->NotRange.Reserved4                    = 39
+pp_data->cap[39]->Button.LogicalMin                   = 0
+pp_data->cap[39]->Button.LogicalMax                   = 0
+pp_data->cap[39]->Units                    = 0
+pp_data->cap[39]->UnitsExp                 = 0
+
+pp_data->cap[40]->UsagePage                    = 0xFF01
+pp_data->cap[40]->ReportID                     = 0x01
+pp_data->cap[40]->BitPosition                  = 3
+pp_data->cap[40]->BitSize                      = 1
+pp_data->cap[40]->ReportCount                  = 1
+pp_data->cap[40]->BytePosition                 = 0x0004
+pp_data->cap[40]->BitCount                     = 1
+pp_data->cap[40]->BitField                     = 0x02
+pp_data->cap[40]->NextBytePosition             = 0x0005
+pp_data->cap[40]->LinkCollection               = 0x0001
+pp_data->cap[40]->LinkUsagePage                = 0xFF01
+pp_data->cap[40]->LinkUsage                    = 0x0001
+pp_data->cap[40]->IsMultipleItemsForArray      = 0
+pp_data->cap[40]->IsButtonCap                  = 1
+pp_data->cap[40]->IsPadding                    = 0
+pp_data->cap[40]->IsAbsolute                   = 1
+pp_data->cap[40]->IsRange                      = 0
+pp_data->cap[40]->IsAlias                      = 0
+pp_data->cap[40]->IsStringRange                = 0
+pp_data->cap[40]->IsDesignatorRange            = 0
+pp_data->cap[40]->Reserved1                    = 0x000000
+pp_data->cap[40]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[40]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[40]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[40]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[40]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[40]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[40]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[40]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[40]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[40]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[40]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[40]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[40]->NotRange.Usage                        = 0x0002
+pp_data->cap[40]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[40]->NotRange.StringIndex                  = 0
+pp_data->cap[40]->NotRange.Reserved2                    = 0
+pp_data->cap[40]->NotRange.DesignatorIndex              = 0
+pp_data->cap[40]->NotRange.Reserved3                    = 0
+pp_data->cap[40]->NotRange.DataIndex                    = 40
+pp_data->cap[40]->NotRange.Reserved4                    = 40
+pp_data->cap[40]->Button.LogicalMin                   = 0
+pp_data->cap[40]->Button.LogicalMax                   = 0
+pp_data->cap[40]->Units                    = 0
+pp_data->cap[40]->UnitsExp                 = 0
+
+pp_data->cap[41]->UsagePage                    = 0xFF01
+pp_data->cap[41]->ReportID                     = 0x01
+pp_data->cap[41]->BitPosition                  = 2
+pp_data->cap[41]->BitSize                      = 1
+pp_data->cap[41]->ReportCount                  = 1
+pp_data->cap[41]->BytePosition                 = 0x0004
+pp_data->cap[41]->BitCount                     = 1
+pp_data->cap[41]->BitField                     = 0x02
+pp_data->cap[41]->NextBytePosition             = 0x0005
+pp_data->cap[41]->LinkCollection               = 0x0001
+pp_data->cap[41]->LinkUsagePage                = 0xFF01
+pp_data->cap[41]->LinkUsage                    = 0x0001
+pp_data->cap[41]->IsMultipleItemsForArray      = 0
+pp_data->cap[41]->IsButtonCap                  = 1
+pp_data->cap[41]->IsPadding                    = 0
+pp_data->cap[41]->IsAbsolute                   = 1
+pp_data->cap[41]->IsRange                      = 0
+pp_data->cap[41]->IsAlias                      = 0
+pp_data->cap[41]->IsStringRange                = 0
+pp_data->cap[41]->IsDesignatorRange            = 0
+pp_data->cap[41]->Reserved1                    = 0x000000
+pp_data->cap[41]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[41]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[41]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[41]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[41]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[41]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[41]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[41]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[41]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[41]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[41]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[41]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[41]->NotRange.Usage                        = 0x0002
+pp_data->cap[41]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[41]->NotRange.StringIndex                  = 0
+pp_data->cap[41]->NotRange.Reserved2                    = 0
+pp_data->cap[41]->NotRange.DesignatorIndex              = 0
+pp_data->cap[41]->NotRange.Reserved3                    = 0
+pp_data->cap[41]->NotRange.DataIndex                    = 41
+pp_data->cap[41]->NotRange.Reserved4                    = 41
+pp_data->cap[41]->Button.LogicalMin                   = 0
+pp_data->cap[41]->Button.LogicalMax                   = 0
+pp_data->cap[41]->Units                    = 0
+pp_data->cap[41]->UnitsExp                 = 0
+
+pp_data->cap[42]->UsagePage                    = 0xFF01
+pp_data->cap[42]->ReportID                     = 0x01
+pp_data->cap[42]->BitPosition                  = 1
+pp_data->cap[42]->BitSize                      = 1
+pp_data->cap[42]->ReportCount                  = 1
+pp_data->cap[42]->BytePosition                 = 0x0004
+pp_data->cap[42]->BitCount                     = 1
+pp_data->cap[42]->BitField                     = 0x02
+pp_data->cap[42]->NextBytePosition             = 0x0005
+pp_data->cap[42]->LinkCollection               = 0x0001
+pp_data->cap[42]->LinkUsagePage                = 0xFF01
+pp_data->cap[42]->LinkUsage                    = 0x0001
+pp_data->cap[42]->IsMultipleItemsForArray      = 0
+pp_data->cap[42]->IsButtonCap                  = 1
+pp_data->cap[42]->IsPadding                    = 0
+pp_data->cap[42]->IsAbsolute                   = 1
+pp_data->cap[42]->IsRange                      = 0
+pp_data->cap[42]->IsAlias                      = 0
+pp_data->cap[42]->IsStringRange                = 0
+pp_data->cap[42]->IsDesignatorRange            = 0
+pp_data->cap[42]->Reserved1                    = 0x000000
+pp_data->cap[42]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[42]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[42]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[42]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[42]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[42]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[42]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[42]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[42]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[42]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[42]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[42]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[42]->NotRange.Usage                        = 0x0002
+pp_data->cap[42]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[42]->NotRange.StringIndex                  = 0
+pp_data->cap[42]->NotRange.Reserved2                    = 0
+pp_data->cap[42]->NotRange.DesignatorIndex              = 0
+pp_data->cap[42]->NotRange.Reserved3                    = 0
+pp_data->cap[42]->NotRange.DataIndex                    = 42
+pp_data->cap[42]->NotRange.Reserved4                    = 42
+pp_data->cap[42]->Button.LogicalMin                   = 0
+pp_data->cap[42]->Button.LogicalMax                   = 0
+pp_data->cap[42]->Units                    = 0
+pp_data->cap[42]->UnitsExp                 = 0
+
+pp_data->cap[43]->UsagePage                    = 0xFF01
+pp_data->cap[43]->ReportID                     = 0x01
+pp_data->cap[43]->BitPosition                  = 0
+pp_data->cap[43]->BitSize                      = 1
+pp_data->cap[43]->ReportCount                  = 1
+pp_data->cap[43]->BytePosition                 = 0x0004
+pp_data->cap[43]->BitCount                     = 1
+pp_data->cap[43]->BitField                     = 0x02
+pp_data->cap[43]->NextBytePosition             = 0x0005
+pp_data->cap[43]->LinkCollection               = 0x0001
+pp_data->cap[43]->LinkUsagePage                = 0xFF01
+pp_data->cap[43]->LinkUsage                    = 0x0001
+pp_data->cap[43]->IsMultipleItemsForArray      = 0
+pp_data->cap[43]->IsButtonCap                  = 1
+pp_data->cap[43]->IsPadding                    = 0
+pp_data->cap[43]->IsAbsolute                   = 1
+pp_data->cap[43]->IsRange                      = 0
+pp_data->cap[43]->IsAlias                      = 0
+pp_data->cap[43]->IsStringRange                = 0
+pp_data->cap[43]->IsDesignatorRange            = 0
+pp_data->cap[43]->Reserved1                    = 0x000000
+pp_data->cap[43]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[43]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[43]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[43]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[43]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[43]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[43]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[43]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[43]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[43]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[43]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[43]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[43]->NotRange.Usage                        = 0x0002
+pp_data->cap[43]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[43]->NotRange.StringIndex                  = 0
+pp_data->cap[43]->NotRange.Reserved2                    = 0
+pp_data->cap[43]->NotRange.DesignatorIndex              = 0
+pp_data->cap[43]->NotRange.Reserved3                    = 0
+pp_data->cap[43]->NotRange.DataIndex                    = 43
+pp_data->cap[43]->NotRange.Reserved4                    = 43
+pp_data->cap[43]->Button.LogicalMin                   = 0
+pp_data->cap[43]->Button.LogicalMax                   = 0
+pp_data->cap[43]->Units                    = 0
+pp_data->cap[43]->UnitsExp                 = 0
+
+pp_data->cap[44]->UsagePage                    = 0xFF01
+pp_data->cap[44]->ReportID                     = 0x01
+pp_data->cap[44]->BitPosition                  = 7
+pp_data->cap[44]->BitSize                      = 1
+pp_data->cap[44]->ReportCount                  = 1
+pp_data->cap[44]->BytePosition                 = 0x0003
+pp_data->cap[44]->BitCount                     = 1
+pp_data->cap[44]->BitField                     = 0x02
+pp_data->cap[44]->NextBytePosition             = 0x0004
+pp_data->cap[44]->LinkCollection               = 0x0001
+pp_data->cap[44]->LinkUsagePage                = 0xFF01
+pp_data->cap[44]->LinkUsage                    = 0x0001
+pp_data->cap[44]->IsMultipleItemsForArray      = 0
+pp_data->cap[44]->IsButtonCap                  = 1
+pp_data->cap[44]->IsPadding                    = 0
+pp_data->cap[44]->IsAbsolute                   = 1
+pp_data->cap[44]->IsRange                      = 0
+pp_data->cap[44]->IsAlias                      = 0
+pp_data->cap[44]->IsStringRange                = 0
+pp_data->cap[44]->IsDesignatorRange            = 0
+pp_data->cap[44]->Reserved1                    = 0x000000
+pp_data->cap[44]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[44]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[44]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[44]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[44]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[44]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[44]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[44]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[44]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[44]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[44]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[44]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[44]->NotRange.Usage                        = 0x0002
+pp_data->cap[44]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[44]->NotRange.StringIndex                  = 0
+pp_data->cap[44]->NotRange.Reserved2                    = 0
+pp_data->cap[44]->NotRange.DesignatorIndex              = 0
+pp_data->cap[44]->NotRange.Reserved3                    = 0
+pp_data->cap[44]->NotRange.DataIndex                    = 44
+pp_data->cap[44]->NotRange.Reserved4                    = 44
+pp_data->cap[44]->Button.LogicalMin                   = 0
+pp_data->cap[44]->Button.LogicalMax                   = 0
+pp_data->cap[44]->Units                    = 0
+pp_data->cap[44]->UnitsExp                 = 0
+
+pp_data->cap[45]->UsagePage                    = 0xFF01
+pp_data->cap[45]->ReportID                     = 0x01
+pp_data->cap[45]->BitPosition                  = 6
+pp_data->cap[45]->BitSize                      = 1
+pp_data->cap[45]->ReportCount                  = 1
+pp_data->cap[45]->BytePosition                 = 0x0003
+pp_data->cap[45]->BitCount                     = 1
+pp_data->cap[45]->BitField                     = 0x02
+pp_data->cap[45]->NextBytePosition             = 0x0004
+pp_data->cap[45]->LinkCollection               = 0x0001
+pp_data->cap[45]->LinkUsagePage                = 0xFF01
+pp_data->cap[45]->LinkUsage                    = 0x0001
+pp_data->cap[45]->IsMultipleItemsForArray      = 0
+pp_data->cap[45]->IsButtonCap                  = 1
+pp_data->cap[45]->IsPadding                    = 0
+pp_data->cap[45]->IsAbsolute                   = 1
+pp_data->cap[45]->IsRange                      = 0
+pp_data->cap[45]->IsAlias                      = 0
+pp_data->cap[45]->IsStringRange                = 0
+pp_data->cap[45]->IsDesignatorRange            = 0
+pp_data->cap[45]->Reserved1                    = 0x000000
+pp_data->cap[45]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[45]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[45]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[45]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[45]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[45]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[45]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[45]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[45]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[45]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[45]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[45]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[45]->NotRange.Usage                        = 0x0002
+pp_data->cap[45]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[45]->NotRange.StringIndex                  = 0
+pp_data->cap[45]->NotRange.Reserved2                    = 0
+pp_data->cap[45]->NotRange.DesignatorIndex              = 0
+pp_data->cap[45]->NotRange.Reserved3                    = 0
+pp_data->cap[45]->NotRange.DataIndex                    = 45
+pp_data->cap[45]->NotRange.Reserved4                    = 45
+pp_data->cap[45]->Button.LogicalMin                   = 0
+pp_data->cap[45]->Button.LogicalMax                   = 0
+pp_data->cap[45]->Units                    = 0
+pp_data->cap[45]->UnitsExp                 = 0
+
+pp_data->cap[46]->UsagePage                    = 0xFF01
+pp_data->cap[46]->ReportID                     = 0x01
+pp_data->cap[46]->BitPosition                  = 5
+pp_data->cap[46]->BitSize                      = 1
+pp_data->cap[46]->ReportCount                  = 1
+pp_data->cap[46]->BytePosition                 = 0x0003
+pp_data->cap[46]->BitCount                     = 1
+pp_data->cap[46]->BitField                     = 0x02
+pp_data->cap[46]->NextBytePosition             = 0x0004
+pp_data->cap[46]->LinkCollection               = 0x0001
+pp_data->cap[46]->LinkUsagePage                = 0xFF01
+pp_data->cap[46]->LinkUsage                    = 0x0001
+pp_data->cap[46]->IsMultipleItemsForArray      = 0
+pp_data->cap[46]->IsButtonCap                  = 1
+pp_data->cap[46]->IsPadding                    = 0
+pp_data->cap[46]->IsAbsolute                   = 1
+pp_data->cap[46]->IsRange                      = 0
+pp_data->cap[46]->IsAlias                      = 0
+pp_data->cap[46]->IsStringRange                = 0
+pp_data->cap[46]->IsDesignatorRange            = 0
+pp_data->cap[46]->Reserved1                    = 0x000000
+pp_data->cap[46]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[46]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[46]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[46]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[46]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[46]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[46]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[46]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[46]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[46]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[46]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[46]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[46]->NotRange.Usage                        = 0x0002
+pp_data->cap[46]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[46]->NotRange.StringIndex                  = 0
+pp_data->cap[46]->NotRange.Reserved2                    = 0
+pp_data->cap[46]->NotRange.DesignatorIndex              = 0
+pp_data->cap[46]->NotRange.Reserved3                    = 0
+pp_data->cap[46]->NotRange.DataIndex                    = 46
+pp_data->cap[46]->NotRange.Reserved4                    = 46
+pp_data->cap[46]->Button.LogicalMin                   = 0
+pp_data->cap[46]->Button.LogicalMax                   = 0
+pp_data->cap[46]->Units                    = 0
+pp_data->cap[46]->UnitsExp                 = 0
+
+pp_data->cap[47]->UsagePage                    = 0xFF01
+pp_data->cap[47]->ReportID                     = 0x01
+pp_data->cap[47]->BitPosition                  = 4
+pp_data->cap[47]->BitSize                      = 1
+pp_data->cap[47]->ReportCount                  = 1
+pp_data->cap[47]->BytePosition                 = 0x0003
+pp_data->cap[47]->BitCount                     = 1
+pp_data->cap[47]->BitField                     = 0x02
+pp_data->cap[47]->NextBytePosition             = 0x0004
+pp_data->cap[47]->LinkCollection               = 0x0001
+pp_data->cap[47]->LinkUsagePage                = 0xFF01
+pp_data->cap[47]->LinkUsage                    = 0x0001
+pp_data->cap[47]->IsMultipleItemsForArray      = 0
+pp_data->cap[47]->IsButtonCap                  = 1
+pp_data->cap[47]->IsPadding                    = 0
+pp_data->cap[47]->IsAbsolute                   = 1
+pp_data->cap[47]->IsRange                      = 0
+pp_data->cap[47]->IsAlias                      = 0
+pp_data->cap[47]->IsStringRange                = 0
+pp_data->cap[47]->IsDesignatorRange            = 0
+pp_data->cap[47]->Reserved1                    = 0x000000
+pp_data->cap[47]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[47]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[47]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[47]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[47]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[47]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[47]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[47]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[47]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[47]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[47]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[47]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[47]->NotRange.Usage                        = 0x0002
+pp_data->cap[47]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[47]->NotRange.StringIndex                  = 0
+pp_data->cap[47]->NotRange.Reserved2                    = 0
+pp_data->cap[47]->NotRange.DesignatorIndex              = 0
+pp_data->cap[47]->NotRange.Reserved3                    = 0
+pp_data->cap[47]->NotRange.DataIndex                    = 47
+pp_data->cap[47]->NotRange.Reserved4                    = 47
+pp_data->cap[47]->Button.LogicalMin                   = 0
+pp_data->cap[47]->Button.LogicalMax                   = 0
+pp_data->cap[47]->Units                    = 0
+pp_data->cap[47]->UnitsExp                 = 0
+
+pp_data->cap[48]->UsagePage                    = 0xFF01
+pp_data->cap[48]->ReportID                     = 0x01
+pp_data->cap[48]->BitPosition                  = 3
+pp_data->cap[48]->BitSize                      = 1
+pp_data->cap[48]->ReportCount                  = 1
+pp_data->cap[48]->BytePosition                 = 0x0003
+pp_data->cap[48]->BitCount                     = 1
+pp_data->cap[48]->BitField                     = 0x02
+pp_data->cap[48]->NextBytePosition             = 0x0004
+pp_data->cap[48]->LinkCollection               = 0x0001
+pp_data->cap[48]->LinkUsagePage                = 0xFF01
+pp_data->cap[48]->LinkUsage                    = 0x0001
+pp_data->cap[48]->IsMultipleItemsForArray      = 0
+pp_data->cap[48]->IsButtonCap                  = 1
+pp_data->cap[48]->IsPadding                    = 0
+pp_data->cap[48]->IsAbsolute                   = 1
+pp_data->cap[48]->IsRange                      = 0
+pp_data->cap[48]->IsAlias                      = 0
+pp_data->cap[48]->IsStringRange                = 0
+pp_data->cap[48]->IsDesignatorRange            = 0
+pp_data->cap[48]->Reserved1                    = 0x000000
+pp_data->cap[48]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[48]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[48]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[48]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[48]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[48]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[48]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[48]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[48]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[48]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[48]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[48]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[48]->NotRange.Usage                        = 0x0002
+pp_data->cap[48]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[48]->NotRange.StringIndex                  = 0
+pp_data->cap[48]->NotRange.Reserved2                    = 0
+pp_data->cap[48]->NotRange.DesignatorIndex              = 0
+pp_data->cap[48]->NotRange.Reserved3                    = 0
+pp_data->cap[48]->NotRange.DataIndex                    = 48
+pp_data->cap[48]->NotRange.Reserved4                    = 48
+pp_data->cap[48]->Button.LogicalMin                   = 0
+pp_data->cap[48]->Button.LogicalMax                   = 0
+pp_data->cap[48]->Units                    = 0
+pp_data->cap[48]->UnitsExp                 = 0
+
+pp_data->cap[49]->UsagePage                    = 0xFF01
+pp_data->cap[49]->ReportID                     = 0x01
+pp_data->cap[49]->BitPosition                  = 2
+pp_data->cap[49]->BitSize                      = 1
+pp_data->cap[49]->ReportCount                  = 1
+pp_data->cap[49]->BytePosition                 = 0x0003
+pp_data->cap[49]->BitCount                     = 1
+pp_data->cap[49]->BitField                     = 0x02
+pp_data->cap[49]->NextBytePosition             = 0x0004
+pp_data->cap[49]->LinkCollection               = 0x0001
+pp_data->cap[49]->LinkUsagePage                = 0xFF01
+pp_data->cap[49]->LinkUsage                    = 0x0001
+pp_data->cap[49]->IsMultipleItemsForArray      = 0
+pp_data->cap[49]->IsButtonCap                  = 1
+pp_data->cap[49]->IsPadding                    = 0
+pp_data->cap[49]->IsAbsolute                   = 1
+pp_data->cap[49]->IsRange                      = 0
+pp_data->cap[49]->IsAlias                      = 0
+pp_data->cap[49]->IsStringRange                = 0
+pp_data->cap[49]->IsDesignatorRange            = 0
+pp_data->cap[49]->Reserved1                    = 0x000000
+pp_data->cap[49]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[49]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[49]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[49]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[49]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[49]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[49]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[49]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[49]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[49]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[49]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[49]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[49]->NotRange.Usage                        = 0x0002
+pp_data->cap[49]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[49]->NotRange.StringIndex                  = 0
+pp_data->cap[49]->NotRange.Reserved2                    = 0
+pp_data->cap[49]->NotRange.DesignatorIndex              = 0
+pp_data->cap[49]->NotRange.Reserved3                    = 0
+pp_data->cap[49]->NotRange.DataIndex                    = 49
+pp_data->cap[49]->NotRange.Reserved4                    = 49
+pp_data->cap[49]->Button.LogicalMin                   = 0
+pp_data->cap[49]->Button.LogicalMax                   = 0
+pp_data->cap[49]->Units                    = 0
+pp_data->cap[49]->UnitsExp                 = 0
+
+pp_data->cap[50]->UsagePage                    = 0xFF01
+pp_data->cap[50]->ReportID                     = 0x01
+pp_data->cap[50]->BitPosition                  = 1
+pp_data->cap[50]->BitSize                      = 1
+pp_data->cap[50]->ReportCount                  = 1
+pp_data->cap[50]->BytePosition                 = 0x0003
+pp_data->cap[50]->BitCount                     = 1
+pp_data->cap[50]->BitField                     = 0x02
+pp_data->cap[50]->NextBytePosition             = 0x0004
+pp_data->cap[50]->LinkCollection               = 0x0001
+pp_data->cap[50]->LinkUsagePage                = 0xFF01
+pp_data->cap[50]->LinkUsage                    = 0x0001
+pp_data->cap[50]->IsMultipleItemsForArray      = 0
+pp_data->cap[50]->IsButtonCap                  = 1
+pp_data->cap[50]->IsPadding                    = 0
+pp_data->cap[50]->IsAbsolute                   = 1
+pp_data->cap[50]->IsRange                      = 0
+pp_data->cap[50]->IsAlias                      = 0
+pp_data->cap[50]->IsStringRange                = 0
+pp_data->cap[50]->IsDesignatorRange            = 0
+pp_data->cap[50]->Reserved1                    = 0x000000
+pp_data->cap[50]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[50]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[50]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[50]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[50]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[50]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[50]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[50]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[50]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[50]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[50]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[50]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[50]->NotRange.Usage                        = 0x0002
+pp_data->cap[50]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[50]->NotRange.StringIndex                  = 0
+pp_data->cap[50]->NotRange.Reserved2                    = 0
+pp_data->cap[50]->NotRange.DesignatorIndex              = 0
+pp_data->cap[50]->NotRange.Reserved3                    = 0
+pp_data->cap[50]->NotRange.DataIndex                    = 50
+pp_data->cap[50]->NotRange.Reserved4                    = 50
+pp_data->cap[50]->Button.LogicalMin                   = 0
+pp_data->cap[50]->Button.LogicalMax                   = 0
+pp_data->cap[50]->Units                    = 0
+pp_data->cap[50]->UnitsExp                 = 0
+
+pp_data->cap[51]->UsagePage                    = 0xFF01
+pp_data->cap[51]->ReportID                     = 0x01
+pp_data->cap[51]->BitPosition                  = 0
+pp_data->cap[51]->BitSize                      = 1
+pp_data->cap[51]->ReportCount                  = 1
+pp_data->cap[51]->BytePosition                 = 0x0003
+pp_data->cap[51]->BitCount                     = 1
+pp_data->cap[51]->BitField                     = 0x02
+pp_data->cap[51]->NextBytePosition             = 0x0004
+pp_data->cap[51]->LinkCollection               = 0x0001
+pp_data->cap[51]->LinkUsagePage                = 0xFF01
+pp_data->cap[51]->LinkUsage                    = 0x0001
+pp_data->cap[51]->IsMultipleItemsForArray      = 0
+pp_data->cap[51]->IsButtonCap                  = 1
+pp_data->cap[51]->IsPadding                    = 0
+pp_data->cap[51]->IsAbsolute                   = 1
+pp_data->cap[51]->IsRange                      = 0
+pp_data->cap[51]->IsAlias                      = 0
+pp_data->cap[51]->IsStringRange                = 0
+pp_data->cap[51]->IsDesignatorRange            = 0
+pp_data->cap[51]->Reserved1                    = 0x000000
+pp_data->cap[51]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[51]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[51]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[51]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[51]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[51]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[51]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[51]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[51]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[51]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[51]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[51]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[51]->NotRange.Usage                        = 0x0002
+pp_data->cap[51]->NotRange.Reserved1                    = 0x0002
+pp_data->cap[51]->NotRange.StringIndex                  = 0
+pp_data->cap[51]->NotRange.Reserved2                    = 0
+pp_data->cap[51]->NotRange.DesignatorIndex              = 0
+pp_data->cap[51]->NotRange.Reserved3                    = 0
+pp_data->cap[51]->NotRange.DataIndex                    = 51
+pp_data->cap[51]->NotRange.Reserved4                    = 51
+pp_data->cap[51]->Button.LogicalMin                   = 0
+pp_data->cap[51]->Button.LogicalMax                   = 0
+pp_data->cap[51]->Units                    = 0
+pp_data->cap[51]->UnitsExp                 = 0
+
+pp_data->cap[52]->UsagePage                    = 0xFF01
+pp_data->cap[52]->ReportID                     = 0x01
+pp_data->cap[52]->BitPosition                  = 7
+pp_data->cap[52]->BitSize                      = 1
+pp_data->cap[52]->ReportCount                  = 1
+pp_data->cap[52]->BytePosition                 = 0x0009
+pp_data->cap[52]->BitCount                     = 1
+pp_data->cap[52]->BitField                     = 0x02
+pp_data->cap[52]->NextBytePosition             = 0x000A
+pp_data->cap[52]->LinkCollection               = 0x0001
+pp_data->cap[52]->LinkUsagePage                = 0xFF01
+pp_data->cap[52]->LinkUsage                    = 0x0001
+pp_data->cap[52]->IsMultipleItemsForArray      = 0
+pp_data->cap[52]->IsButtonCap                  = 1
+pp_data->cap[52]->IsPadding                    = 0
+pp_data->cap[52]->IsAbsolute                   = 1
+pp_data->cap[52]->IsRange                      = 0
+pp_data->cap[52]->IsAlias                      = 0
+pp_data->cap[52]->IsStringRange                = 0
+pp_data->cap[52]->IsDesignatorRange            = 0
+pp_data->cap[52]->Reserved1                    = 0x000000
+pp_data->cap[52]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[52]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[52]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[52]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[52]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[52]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[52]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[52]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[52]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[52]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[52]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[52]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[52]->NotRange.Usage                        = 0x000B
+pp_data->cap[52]->NotRange.Reserved1                    = 0x000B
+pp_data->cap[52]->NotRange.StringIndex                  = 0
+pp_data->cap[52]->NotRange.Reserved2                    = 0
+pp_data->cap[52]->NotRange.DesignatorIndex              = 0
+pp_data->cap[52]->NotRange.Reserved3                    = 0
+pp_data->cap[52]->NotRange.DataIndex                    = 52
+pp_data->cap[52]->NotRange.Reserved4                    = 52
+pp_data->cap[52]->Button.LogicalMin                   = 0
+pp_data->cap[52]->Button.LogicalMax                   = 0
+pp_data->cap[52]->Units                    = 0
+pp_data->cap[52]->UnitsExp                 = 0
+
+pp_data->cap[53]->UsagePage                    = 0xFF01
+pp_data->cap[53]->ReportID                     = 0x01
+pp_data->cap[53]->BitPosition                  = 6
+pp_data->cap[53]->BitSize                      = 1
+pp_data->cap[53]->ReportCount                  = 1
+pp_data->cap[53]->BytePosition                 = 0x0009
+pp_data->cap[53]->BitCount                     = 1
+pp_data->cap[53]->BitField                     = 0x02
+pp_data->cap[53]->NextBytePosition             = 0x000A
+pp_data->cap[53]->LinkCollection               = 0x0001
+pp_data->cap[53]->LinkUsagePage                = 0xFF01
+pp_data->cap[53]->LinkUsage                    = 0x0001
+pp_data->cap[53]->IsMultipleItemsForArray      = 0
+pp_data->cap[53]->IsButtonCap                  = 1
+pp_data->cap[53]->IsPadding                    = 0
+pp_data->cap[53]->IsAbsolute                   = 1
+pp_data->cap[53]->IsRange                      = 0
+pp_data->cap[53]->IsAlias                      = 0
+pp_data->cap[53]->IsStringRange                = 0
+pp_data->cap[53]->IsDesignatorRange            = 0
+pp_data->cap[53]->Reserved1                    = 0x000000
+pp_data->cap[53]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[53]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[53]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[53]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[53]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[53]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[53]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[53]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[53]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[53]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[53]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[53]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[53]->NotRange.Usage                        = 0x000B
+pp_data->cap[53]->NotRange.Reserved1                    = 0x000B
+pp_data->cap[53]->NotRange.StringIndex                  = 0
+pp_data->cap[53]->NotRange.Reserved2                    = 0
+pp_data->cap[53]->NotRange.DesignatorIndex              = 0
+pp_data->cap[53]->NotRange.Reserved3                    = 0
+pp_data->cap[53]->NotRange.DataIndex                    = 53
+pp_data->cap[53]->NotRange.Reserved4                    = 53
+pp_data->cap[53]->Button.LogicalMin                   = 0
+pp_data->cap[53]->Button.LogicalMax                   = 0
+pp_data->cap[53]->Units                    = 0
+pp_data->cap[53]->UnitsExp                 = 0
+
+pp_data->cap[54]->UsagePage                    = 0xFF01
+pp_data->cap[54]->ReportID                     = 0x01
+pp_data->cap[54]->BitPosition                  = 5
+pp_data->cap[54]->BitSize                      = 1
+pp_data->cap[54]->ReportCount                  = 1
+pp_data->cap[54]->BytePosition                 = 0x0009
+pp_data->cap[54]->BitCount                     = 1
+pp_data->cap[54]->BitField                     = 0x02
+pp_data->cap[54]->NextBytePosition             = 0x000A
+pp_data->cap[54]->LinkCollection               = 0x0001
+pp_data->cap[54]->LinkUsagePage                = 0xFF01
+pp_data->cap[54]->LinkUsage                    = 0x0001
+pp_data->cap[54]->IsMultipleItemsForArray      = 0
+pp_data->cap[54]->IsButtonCap                  = 1
+pp_data->cap[54]->IsPadding                    = 0
+pp_data->cap[54]->IsAbsolute                   = 1
+pp_data->cap[54]->IsRange                      = 0
+pp_data->cap[54]->IsAlias                      = 0
+pp_data->cap[54]->IsStringRange                = 0
+pp_data->cap[54]->IsDesignatorRange            = 0
+pp_data->cap[54]->Reserved1                    = 0x000000
+pp_data->cap[54]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[54]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[54]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[54]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[54]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[54]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[54]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[54]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[54]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[54]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[54]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[54]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[54]->NotRange.Usage                        = 0x000B
+pp_data->cap[54]->NotRange.Reserved1                    = 0x000B
+pp_data->cap[54]->NotRange.StringIndex                  = 0
+pp_data->cap[54]->NotRange.Reserved2                    = 0
+pp_data->cap[54]->NotRange.DesignatorIndex              = 0
+pp_data->cap[54]->NotRange.Reserved3                    = 0
+pp_data->cap[54]->NotRange.DataIndex                    = 54
+pp_data->cap[54]->NotRange.Reserved4                    = 54
+pp_data->cap[54]->Button.LogicalMin                   = 0
+pp_data->cap[54]->Button.LogicalMax                   = 0
+pp_data->cap[54]->Units                    = 0
+pp_data->cap[54]->UnitsExp                 = 0
+
+pp_data->cap[55]->UsagePage                    = 0xFF01
+pp_data->cap[55]->ReportID                     = 0x01
+pp_data->cap[55]->BitPosition                  = 4
+pp_data->cap[55]->BitSize                      = 1
+pp_data->cap[55]->ReportCount                  = 1
+pp_data->cap[55]->BytePosition                 = 0x0009
+pp_data->cap[55]->BitCount                     = 1
+pp_data->cap[55]->BitField                     = 0x02
+pp_data->cap[55]->NextBytePosition             = 0x000A
+pp_data->cap[55]->LinkCollection               = 0x0001
+pp_data->cap[55]->LinkUsagePage                = 0xFF01
+pp_data->cap[55]->LinkUsage                    = 0x0001
+pp_data->cap[55]->IsMultipleItemsForArray      = 0
+pp_data->cap[55]->IsButtonCap                  = 1
+pp_data->cap[55]->IsPadding                    = 0
+pp_data->cap[55]->IsAbsolute                   = 1
+pp_data->cap[55]->IsRange                      = 0
+pp_data->cap[55]->IsAlias                      = 0
+pp_data->cap[55]->IsStringRange                = 0
+pp_data->cap[55]->IsDesignatorRange            = 0
+pp_data->cap[55]->Reserved1                    = 0x000000
+pp_data->cap[55]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[55]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[55]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[55]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[55]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[55]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[55]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[55]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[55]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[55]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[55]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[55]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[55]->NotRange.Usage                        = 0x000B
+pp_data->cap[55]->NotRange.Reserved1                    = 0x000B
+pp_data->cap[55]->NotRange.StringIndex                  = 0
+pp_data->cap[55]->NotRange.Reserved2                    = 0
+pp_data->cap[55]->NotRange.DesignatorIndex              = 0
+pp_data->cap[55]->NotRange.Reserved3                    = 0
+pp_data->cap[55]->NotRange.DataIndex                    = 55
+pp_data->cap[55]->NotRange.Reserved4                    = 55
+pp_data->cap[55]->Button.LogicalMin                   = 0
+pp_data->cap[55]->Button.LogicalMax                   = 0
+pp_data->cap[55]->Units                    = 0
+pp_data->cap[55]->UnitsExp                 = 0
+
+pp_data->cap[56]->UsagePage                    = 0xFF01
+pp_data->cap[56]->ReportID                     = 0x01
+pp_data->cap[56]->BitPosition                  = 3
+pp_data->cap[56]->BitSize                      = 1
+pp_data->cap[56]->ReportCount                  = 1
+pp_data->cap[56]->BytePosition                 = 0x0009
+pp_data->cap[56]->BitCount                     = 1
+pp_data->cap[56]->BitField                     = 0x02
+pp_data->cap[56]->NextBytePosition             = 0x000A
+pp_data->cap[56]->LinkCollection               = 0x0001
+pp_data->cap[56]->LinkUsagePage                = 0xFF01
+pp_data->cap[56]->LinkUsage                    = 0x0001
+pp_data->cap[56]->IsMultipleItemsForArray      = 0
+pp_data->cap[56]->IsButtonCap                  = 1
+pp_data->cap[56]->IsPadding                    = 0
+pp_data->cap[56]->IsAbsolute                   = 1
+pp_data->cap[56]->IsRange                      = 0
+pp_data->cap[56]->IsAlias                      = 0
+pp_data->cap[56]->IsStringRange                = 0
+pp_data->cap[56]->IsDesignatorRange            = 0
+pp_data->cap[56]->Reserved1                    = 0x000000
+pp_data->cap[56]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[56]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[56]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[56]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[56]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[56]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[56]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[56]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[56]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[56]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[56]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[56]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[56]->NotRange.Usage                        = 0x000B
+pp_data->cap[56]->NotRange.Reserved1                    = 0x000B
+pp_data->cap[56]->NotRange.StringIndex                  = 0
+pp_data->cap[56]->NotRange.Reserved2                    = 0
+pp_data->cap[56]->NotRange.DesignatorIndex              = 0
+pp_data->cap[56]->NotRange.Reserved3                    = 0
+pp_data->cap[56]->NotRange.DataIndex                    = 56
+pp_data->cap[56]->NotRange.Reserved4                    = 56
+pp_data->cap[56]->Button.LogicalMin                   = 0
+pp_data->cap[56]->Button.LogicalMax                   = 0
+pp_data->cap[56]->Units                    = 0
+pp_data->cap[56]->UnitsExp                 = 0
+
+pp_data->cap[57]->UsagePage                    = 0xFF01
+pp_data->cap[57]->ReportID                     = 0x01
+pp_data->cap[57]->BitPosition                  = 2
+pp_data->cap[57]->BitSize                      = 1
+pp_data->cap[57]->ReportCount                  = 1
+pp_data->cap[57]->BytePosition                 = 0x0009
+pp_data->cap[57]->BitCount                     = 1
+pp_data->cap[57]->BitField                     = 0x02
+pp_data->cap[57]->NextBytePosition             = 0x000A
+pp_data->cap[57]->LinkCollection               = 0x0001
+pp_data->cap[57]->LinkUsagePage                = 0xFF01
+pp_data->cap[57]->LinkUsage                    = 0x0001
+pp_data->cap[57]->IsMultipleItemsForArray      = 0
+pp_data->cap[57]->IsButtonCap                  = 1
+pp_data->cap[57]->IsPadding                    = 0
+pp_data->cap[57]->IsAbsolute                   = 1
+pp_data->cap[57]->IsRange                      = 0
+pp_data->cap[57]->IsAlias                      = 0
+pp_data->cap[57]->IsStringRange                = 0
+pp_data->cap[57]->IsDesignatorRange            = 0
+pp_data->cap[57]->Reserved1                    = 0x000000
+pp_data->cap[57]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[57]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[57]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[57]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[57]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[57]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[57]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[57]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[57]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[57]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[57]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[57]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[57]->NotRange.Usage                        = 0x000B
+pp_data->cap[57]->NotRange.Reserved1                    = 0x000B
+pp_data->cap[57]->NotRange.StringIndex                  = 0
+pp_data->cap[57]->NotRange.Reserved2                    = 0
+pp_data->cap[57]->NotRange.DesignatorIndex              = 0
+pp_data->cap[57]->NotRange.Reserved3                    = 0
+pp_data->cap[57]->NotRange.DataIndex                    = 57
+pp_data->cap[57]->NotRange.Reserved4                    = 57
+pp_data->cap[57]->Button.LogicalMin                   = 0
+pp_data->cap[57]->Button.LogicalMax                   = 0
+pp_data->cap[57]->Units                    = 0
+pp_data->cap[57]->UnitsExp                 = 0
+
+pp_data->cap[58]->UsagePage                    = 0xFF01
+pp_data->cap[58]->ReportID                     = 0x01
+pp_data->cap[58]->BitPosition                  = 1
+pp_data->cap[58]->BitSize                      = 1
+pp_data->cap[58]->ReportCount                  = 1
+pp_data->cap[58]->BytePosition                 = 0x0009
+pp_data->cap[58]->BitCount                     = 1
+pp_data->cap[58]->BitField                     = 0x02
+pp_data->cap[58]->NextBytePosition             = 0x000A
+pp_data->cap[58]->LinkCollection               = 0x0001
+pp_data->cap[58]->LinkUsagePage                = 0xFF01
+pp_data->cap[58]->LinkUsage                    = 0x0001
+pp_data->cap[58]->IsMultipleItemsForArray      = 0
+pp_data->cap[58]->IsButtonCap                  = 1
+pp_data->cap[58]->IsPadding                    = 0
+pp_data->cap[58]->IsAbsolute                   = 1
+pp_data->cap[58]->IsRange                      = 0
+pp_data->cap[58]->IsAlias                      = 0
+pp_data->cap[58]->IsStringRange                = 0
+pp_data->cap[58]->IsDesignatorRange            = 0
+pp_data->cap[58]->Reserved1                    = 0x000000
+pp_data->cap[58]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[58]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[58]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[58]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[58]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[58]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[58]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[58]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[58]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[58]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[58]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[58]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[58]->NotRange.Usage                        = 0x000B
+pp_data->cap[58]->NotRange.Reserved1                    = 0x000B
+pp_data->cap[58]->NotRange.StringIndex                  = 0
+pp_data->cap[58]->NotRange.Reserved2                    = 0
+pp_data->cap[58]->NotRange.DesignatorIndex              = 0
+pp_data->cap[58]->NotRange.Reserved3                    = 0
+pp_data->cap[58]->NotRange.DataIndex                    = 58
+pp_data->cap[58]->NotRange.Reserved4                    = 58
+pp_data->cap[58]->Button.LogicalMin                   = 0
+pp_data->cap[58]->Button.LogicalMax                   = 0
+pp_data->cap[58]->Units                    = 0
+pp_data->cap[58]->UnitsExp                 = 0
+
+pp_data->cap[59]->UsagePage                    = 0xFF01
+pp_data->cap[59]->ReportID                     = 0x01
+pp_data->cap[59]->BitPosition                  = 0
+pp_data->cap[59]->BitSize                      = 1
+pp_data->cap[59]->ReportCount                  = 1
+pp_data->cap[59]->BytePosition                 = 0x0009
+pp_data->cap[59]->BitCount                     = 1
+pp_data->cap[59]->BitField                     = 0x02
+pp_data->cap[59]->NextBytePosition             = 0x000A
+pp_data->cap[59]->LinkCollection               = 0x0001
+pp_data->cap[59]->LinkUsagePage                = 0xFF01
+pp_data->cap[59]->LinkUsage                    = 0x0001
+pp_data->cap[59]->IsMultipleItemsForArray      = 0
+pp_data->cap[59]->IsButtonCap                  = 1
+pp_data->cap[59]->IsPadding                    = 0
+pp_data->cap[59]->IsAbsolute                   = 1
+pp_data->cap[59]->IsRange                      = 0
+pp_data->cap[59]->IsAlias                      = 0
+pp_data->cap[59]->IsStringRange                = 0
+pp_data->cap[59]->IsDesignatorRange            = 0
+pp_data->cap[59]->Reserved1                    = 0x000000
+pp_data->cap[59]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[59]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[59]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[59]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[59]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[59]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[59]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[59]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[59]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[59]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[59]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[59]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[59]->NotRange.Usage                        = 0x000B
+pp_data->cap[59]->NotRange.Reserved1                    = 0x000B
+pp_data->cap[59]->NotRange.StringIndex                  = 0
+pp_data->cap[59]->NotRange.Reserved2                    = 0
+pp_data->cap[59]->NotRange.DesignatorIndex              = 0
+pp_data->cap[59]->NotRange.Reserved3                    = 0
+pp_data->cap[59]->NotRange.DataIndex                    = 59
+pp_data->cap[59]->NotRange.Reserved4                    = 59
+pp_data->cap[59]->Button.LogicalMin                   = 0
+pp_data->cap[59]->Button.LogicalMax                   = 0
+pp_data->cap[59]->Units                    = 0
+pp_data->cap[59]->UnitsExp                 = 0
+
+pp_data->cap[60]->UsagePage                    = 0xFF01
+pp_data->cap[60]->ReportID                     = 0x02
+pp_data->cap[60]->BitPosition                  = 0
+pp_data->cap[60]->BitSize                      = 16
+pp_data->cap[60]->ReportCount                  = 1
+pp_data->cap[60]->BytePosition                 = 0x0033
+pp_data->cap[60]->BitCount                     = 16
+pp_data->cap[60]->BitField                     = 0x02
+pp_data->cap[60]->NextBytePosition             = 0x0035
+pp_data->cap[60]->LinkCollection               = 0x0002
+pp_data->cap[60]->LinkUsagePage                = 0xFF01
+pp_data->cap[60]->LinkUsage                    = 0x0002
+pp_data->cap[60]->IsMultipleItemsForArray      = 0
+pp_data->cap[60]->IsButtonCap                  = 0
+pp_data->cap[60]->IsPadding                    = 0
+pp_data->cap[60]->IsAbsolute                   = 1
+pp_data->cap[60]->IsRange                      = 0
+pp_data->cap[60]->IsAlias                      = 0
+pp_data->cap[60]->IsStringRange                = 0
+pp_data->cap[60]->IsDesignatorRange            = 0
+pp_data->cap[60]->Reserved1                    = 0x000000
+pp_data->cap[60]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[60]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[60]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[60]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[60]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[60]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[60]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[60]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[60]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[60]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[60]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[60]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[60]->NotRange.Usage                        = 0x0004
+pp_data->cap[60]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[60]->NotRange.StringIndex                  = 0
+pp_data->cap[60]->NotRange.Reserved2                    = 0
+pp_data->cap[60]->NotRange.DesignatorIndex              = 0
+pp_data->cap[60]->NotRange.Reserved3                    = 0
+pp_data->cap[60]->NotRange.DataIndex                    = 60
+pp_data->cap[60]->NotRange.Reserved4                    = 60
+pp_data->cap[60]->NotButton.HasNull                   = 0
+pp_data->cap[60]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[60]->NotButton.LogicalMin                = 0
+pp_data->cap[60]->NotButton.LogicalMax                = 4095
+pp_data->cap[60]->NotButton.PhysicalMin               = 0
+pp_data->cap[60]->NotButton.PhysicalMax               = 0
+pp_data->cap[60]->Units                    = 0
+pp_data->cap[60]->UnitsExp                 = 0
+
+pp_data->cap[61]->UsagePage                    = 0xFF01
+pp_data->cap[61]->ReportID                     = 0x02
+pp_data->cap[61]->BitPosition                  = 0
+pp_data->cap[61]->BitSize                      = 16
+pp_data->cap[61]->ReportCount                  = 1
+pp_data->cap[61]->BytePosition                 = 0x0031
+pp_data->cap[61]->BitCount                     = 16
+pp_data->cap[61]->BitField                     = 0x02
+pp_data->cap[61]->NextBytePosition             = 0x0033
+pp_data->cap[61]->LinkCollection               = 0x0002
+pp_data->cap[61]->LinkUsagePage                = 0xFF01
+pp_data->cap[61]->LinkUsage                    = 0x0002
+pp_data->cap[61]->IsMultipleItemsForArray      = 0
+pp_data->cap[61]->IsButtonCap                  = 0
+pp_data->cap[61]->IsPadding                    = 0
+pp_data->cap[61]->IsAbsolute                   = 1
+pp_data->cap[61]->IsRange                      = 0
+pp_data->cap[61]->IsAlias                      = 0
+pp_data->cap[61]->IsStringRange                = 0
+pp_data->cap[61]->IsDesignatorRange            = 0
+pp_data->cap[61]->Reserved1                    = 0x000000
+pp_data->cap[61]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[61]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[61]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[61]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[61]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[61]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[61]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[61]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[61]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[61]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[61]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[61]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[61]->NotRange.Usage                        = 0x0004
+pp_data->cap[61]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[61]->NotRange.StringIndex                  = 0
+pp_data->cap[61]->NotRange.Reserved2                    = 0
+pp_data->cap[61]->NotRange.DesignatorIndex              = 0
+pp_data->cap[61]->NotRange.Reserved3                    = 0
+pp_data->cap[61]->NotRange.DataIndex                    = 61
+pp_data->cap[61]->NotRange.Reserved4                    = 61
+pp_data->cap[61]->NotButton.HasNull                   = 0
+pp_data->cap[61]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[61]->NotButton.LogicalMin                = 0
+pp_data->cap[61]->NotButton.LogicalMax                = 4095
+pp_data->cap[61]->NotButton.PhysicalMin               = 0
+pp_data->cap[61]->NotButton.PhysicalMax               = 0
+pp_data->cap[61]->Units                    = 0
+pp_data->cap[61]->UnitsExp                 = 0
+
+pp_data->cap[62]->UsagePage                    = 0xFF01
+pp_data->cap[62]->ReportID                     = 0x02
+pp_data->cap[62]->BitPosition                  = 0
+pp_data->cap[62]->BitSize                      = 16
+pp_data->cap[62]->ReportCount                  = 1
+pp_data->cap[62]->BytePosition                 = 0x002F
+pp_data->cap[62]->BitCount                     = 16
+pp_data->cap[62]->BitField                     = 0x02
+pp_data->cap[62]->NextBytePosition             = 0x0031
+pp_data->cap[62]->LinkCollection               = 0x0002
+pp_data->cap[62]->LinkUsagePage                = 0xFF01
+pp_data->cap[62]->LinkUsage                    = 0x0002
+pp_data->cap[62]->IsMultipleItemsForArray      = 0
+pp_data->cap[62]->IsButtonCap                  = 0
+pp_data->cap[62]->IsPadding                    = 0
+pp_data->cap[62]->IsAbsolute                   = 1
+pp_data->cap[62]->IsRange                      = 0
+pp_data->cap[62]->IsAlias                      = 0
+pp_data->cap[62]->IsStringRange                = 0
+pp_data->cap[62]->IsDesignatorRange            = 0
+pp_data->cap[62]->Reserved1                    = 0x000000
+pp_data->cap[62]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[62]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[62]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[62]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[62]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[62]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[62]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[62]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[62]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[62]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[62]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[62]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[62]->NotRange.Usage                        = 0x0004
+pp_data->cap[62]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[62]->NotRange.StringIndex                  = 0
+pp_data->cap[62]->NotRange.Reserved2                    = 0
+pp_data->cap[62]->NotRange.DesignatorIndex              = 0
+pp_data->cap[62]->NotRange.Reserved3                    = 0
+pp_data->cap[62]->NotRange.DataIndex                    = 62
+pp_data->cap[62]->NotRange.Reserved4                    = 62
+pp_data->cap[62]->NotButton.HasNull                   = 0
+pp_data->cap[62]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[62]->NotButton.LogicalMin                = 0
+pp_data->cap[62]->NotButton.LogicalMax                = 4095
+pp_data->cap[62]->NotButton.PhysicalMin               = 0
+pp_data->cap[62]->NotButton.PhysicalMax               = 0
+pp_data->cap[62]->Units                    = 0
+pp_data->cap[62]->UnitsExp                 = 0
+
+pp_data->cap[63]->UsagePage                    = 0xFF01
+pp_data->cap[63]->ReportID                     = 0x02
+pp_data->cap[63]->BitPosition                  = 0
+pp_data->cap[63]->BitSize                      = 16
+pp_data->cap[63]->ReportCount                  = 1
+pp_data->cap[63]->BytePosition                 = 0x002D
+pp_data->cap[63]->BitCount                     = 16
+pp_data->cap[63]->BitField                     = 0x02
+pp_data->cap[63]->NextBytePosition             = 0x002F
+pp_data->cap[63]->LinkCollection               = 0x0002
+pp_data->cap[63]->LinkUsagePage                = 0xFF01
+pp_data->cap[63]->LinkUsage                    = 0x0002
+pp_data->cap[63]->IsMultipleItemsForArray      = 0
+pp_data->cap[63]->IsButtonCap                  = 0
+pp_data->cap[63]->IsPadding                    = 0
+pp_data->cap[63]->IsAbsolute                   = 1
+pp_data->cap[63]->IsRange                      = 0
+pp_data->cap[63]->IsAlias                      = 0
+pp_data->cap[63]->IsStringRange                = 0
+pp_data->cap[63]->IsDesignatorRange            = 0
+pp_data->cap[63]->Reserved1                    = 0x000000
+pp_data->cap[63]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[63]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[63]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[63]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[63]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[63]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[63]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[63]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[63]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[63]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[63]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[63]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[63]->NotRange.Usage                        = 0x0004
+pp_data->cap[63]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[63]->NotRange.StringIndex                  = 0
+pp_data->cap[63]->NotRange.Reserved2                    = 0
+pp_data->cap[63]->NotRange.DesignatorIndex              = 0
+pp_data->cap[63]->NotRange.Reserved3                    = 0
+pp_data->cap[63]->NotRange.DataIndex                    = 63
+pp_data->cap[63]->NotRange.Reserved4                    = 63
+pp_data->cap[63]->NotButton.HasNull                   = 0
+pp_data->cap[63]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[63]->NotButton.LogicalMin                = 0
+pp_data->cap[63]->NotButton.LogicalMax                = 4095
+pp_data->cap[63]->NotButton.PhysicalMin               = 0
+pp_data->cap[63]->NotButton.PhysicalMax               = 0
+pp_data->cap[63]->Units                    = 0
+pp_data->cap[63]->UnitsExp                 = 0
+
+pp_data->cap[64]->UsagePage                    = 0xFF01
+pp_data->cap[64]->ReportID                     = 0x02
+pp_data->cap[64]->BitPosition                  = 0
+pp_data->cap[64]->BitSize                      = 16
+pp_data->cap[64]->ReportCount                  = 1
+pp_data->cap[64]->BytePosition                 = 0x002B
+pp_data->cap[64]->BitCount                     = 16
+pp_data->cap[64]->BitField                     = 0x02
+pp_data->cap[64]->NextBytePosition             = 0x002D
+pp_data->cap[64]->LinkCollection               = 0x0002
+pp_data->cap[64]->LinkUsagePage                = 0xFF01
+pp_data->cap[64]->LinkUsage                    = 0x0002
+pp_data->cap[64]->IsMultipleItemsForArray      = 0
+pp_data->cap[64]->IsButtonCap                  = 0
+pp_data->cap[64]->IsPadding                    = 0
+pp_data->cap[64]->IsAbsolute                   = 1
+pp_data->cap[64]->IsRange                      = 0
+pp_data->cap[64]->IsAlias                      = 0
+pp_data->cap[64]->IsStringRange                = 0
+pp_data->cap[64]->IsDesignatorRange            = 0
+pp_data->cap[64]->Reserved1                    = 0x000000
+pp_data->cap[64]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[64]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[64]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[64]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[64]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[64]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[64]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[64]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[64]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[64]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[64]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[64]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[64]->NotRange.Usage                        = 0x0004
+pp_data->cap[64]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[64]->NotRange.StringIndex                  = 0
+pp_data->cap[64]->NotRange.Reserved2                    = 0
+pp_data->cap[64]->NotRange.DesignatorIndex              = 0
+pp_data->cap[64]->NotRange.Reserved3                    = 0
+pp_data->cap[64]->NotRange.DataIndex                    = 64
+pp_data->cap[64]->NotRange.Reserved4                    = 64
+pp_data->cap[64]->NotButton.HasNull                   = 0
+pp_data->cap[64]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[64]->NotButton.LogicalMin                = 0
+pp_data->cap[64]->NotButton.LogicalMax                = 4095
+pp_data->cap[64]->NotButton.PhysicalMin               = 0
+pp_data->cap[64]->NotButton.PhysicalMax               = 0
+pp_data->cap[64]->Units                    = 0
+pp_data->cap[64]->UnitsExp                 = 0
+
+pp_data->cap[65]->UsagePage                    = 0xFF01
+pp_data->cap[65]->ReportID                     = 0x02
+pp_data->cap[65]->BitPosition                  = 0
+pp_data->cap[65]->BitSize                      = 16
+pp_data->cap[65]->ReportCount                  = 1
+pp_data->cap[65]->BytePosition                 = 0x0029
+pp_data->cap[65]->BitCount                     = 16
+pp_data->cap[65]->BitField                     = 0x02
+pp_data->cap[65]->NextBytePosition             = 0x002B
+pp_data->cap[65]->LinkCollection               = 0x0002
+pp_data->cap[65]->LinkUsagePage                = 0xFF01
+pp_data->cap[65]->LinkUsage                    = 0x0002
+pp_data->cap[65]->IsMultipleItemsForArray      = 0
+pp_data->cap[65]->IsButtonCap                  = 0
+pp_data->cap[65]->IsPadding                    = 0
+pp_data->cap[65]->IsAbsolute                   = 1
+pp_data->cap[65]->IsRange                      = 0
+pp_data->cap[65]->IsAlias                      = 0
+pp_data->cap[65]->IsStringRange                = 0
+pp_data->cap[65]->IsDesignatorRange            = 0
+pp_data->cap[65]->Reserved1                    = 0x000000
+pp_data->cap[65]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[65]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[65]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[65]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[65]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[65]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[65]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[65]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[65]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[65]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[65]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[65]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[65]->NotRange.Usage                        = 0x0004
+pp_data->cap[65]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[65]->NotRange.StringIndex                  = 0
+pp_data->cap[65]->NotRange.Reserved2                    = 0
+pp_data->cap[65]->NotRange.DesignatorIndex              = 0
+pp_data->cap[65]->NotRange.Reserved3                    = 0
+pp_data->cap[65]->NotRange.DataIndex                    = 65
+pp_data->cap[65]->NotRange.Reserved4                    = 65
+pp_data->cap[65]->NotButton.HasNull                   = 0
+pp_data->cap[65]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[65]->NotButton.LogicalMin                = 0
+pp_data->cap[65]->NotButton.LogicalMax                = 4095
+pp_data->cap[65]->NotButton.PhysicalMin               = 0
+pp_data->cap[65]->NotButton.PhysicalMax               = 0
+pp_data->cap[65]->Units                    = 0
+pp_data->cap[65]->UnitsExp                 = 0
+
+pp_data->cap[66]->UsagePage                    = 0xFF01
+pp_data->cap[66]->ReportID                     = 0x02
+pp_data->cap[66]->BitPosition                  = 0
+pp_data->cap[66]->BitSize                      = 16
+pp_data->cap[66]->ReportCount                  = 1
+pp_data->cap[66]->BytePosition                 = 0x0027
+pp_data->cap[66]->BitCount                     = 16
+pp_data->cap[66]->BitField                     = 0x02
+pp_data->cap[66]->NextBytePosition             = 0x0029
+pp_data->cap[66]->LinkCollection               = 0x0002
+pp_data->cap[66]->LinkUsagePage                = 0xFF01
+pp_data->cap[66]->LinkUsage                    = 0x0002
+pp_data->cap[66]->IsMultipleItemsForArray      = 0
+pp_data->cap[66]->IsButtonCap                  = 0
+pp_data->cap[66]->IsPadding                    = 0
+pp_data->cap[66]->IsAbsolute                   = 1
+pp_data->cap[66]->IsRange                      = 0
+pp_data->cap[66]->IsAlias                      = 0
+pp_data->cap[66]->IsStringRange                = 0
+pp_data->cap[66]->IsDesignatorRange            = 0
+pp_data->cap[66]->Reserved1                    = 0x000000
+pp_data->cap[66]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[66]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[66]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[66]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[66]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[66]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[66]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[66]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[66]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[66]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[66]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[66]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[66]->NotRange.Usage                        = 0x0004
+pp_data->cap[66]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[66]->NotRange.StringIndex                  = 0
+pp_data->cap[66]->NotRange.Reserved2                    = 0
+pp_data->cap[66]->NotRange.DesignatorIndex              = 0
+pp_data->cap[66]->NotRange.Reserved3                    = 0
+pp_data->cap[66]->NotRange.DataIndex                    = 66
+pp_data->cap[66]->NotRange.Reserved4                    = 66
+pp_data->cap[66]->NotButton.HasNull                   = 0
+pp_data->cap[66]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[66]->NotButton.LogicalMin                = 0
+pp_data->cap[66]->NotButton.LogicalMax                = 4095
+pp_data->cap[66]->NotButton.PhysicalMin               = 0
+pp_data->cap[66]->NotButton.PhysicalMax               = 0
+pp_data->cap[66]->Units                    = 0
+pp_data->cap[66]->UnitsExp                 = 0
+
+pp_data->cap[67]->UsagePage                    = 0xFF01
+pp_data->cap[67]->ReportID                     = 0x02
+pp_data->cap[67]->BitPosition                  = 0
+pp_data->cap[67]->BitSize                      = 16
+pp_data->cap[67]->ReportCount                  = 1
+pp_data->cap[67]->BytePosition                 = 0x0025
+pp_data->cap[67]->BitCount                     = 16
+pp_data->cap[67]->BitField                     = 0x02
+pp_data->cap[67]->NextBytePosition             = 0x0027
+pp_data->cap[67]->LinkCollection               = 0x0002
+pp_data->cap[67]->LinkUsagePage                = 0xFF01
+pp_data->cap[67]->LinkUsage                    = 0x0002
+pp_data->cap[67]->IsMultipleItemsForArray      = 0
+pp_data->cap[67]->IsButtonCap                  = 0
+pp_data->cap[67]->IsPadding                    = 0
+pp_data->cap[67]->IsAbsolute                   = 1
+pp_data->cap[67]->IsRange                      = 0
+pp_data->cap[67]->IsAlias                      = 0
+pp_data->cap[67]->IsStringRange                = 0
+pp_data->cap[67]->IsDesignatorRange            = 0
+pp_data->cap[67]->Reserved1                    = 0x000000
+pp_data->cap[67]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[67]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[67]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[67]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[67]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[67]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[67]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[67]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[67]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[67]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[67]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[67]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[67]->NotRange.Usage                        = 0x0004
+pp_data->cap[67]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[67]->NotRange.StringIndex                  = 0
+pp_data->cap[67]->NotRange.Reserved2                    = 0
+pp_data->cap[67]->NotRange.DesignatorIndex              = 0
+pp_data->cap[67]->NotRange.Reserved3                    = 0
+pp_data->cap[67]->NotRange.DataIndex                    = 67
+pp_data->cap[67]->NotRange.Reserved4                    = 67
+pp_data->cap[67]->NotButton.HasNull                   = 0
+pp_data->cap[67]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[67]->NotButton.LogicalMin                = 0
+pp_data->cap[67]->NotButton.LogicalMax                = 4095
+pp_data->cap[67]->NotButton.PhysicalMin               = 0
+pp_data->cap[67]->NotButton.PhysicalMax               = 0
+pp_data->cap[67]->Units                    = 0
+pp_data->cap[67]->UnitsExp                 = 0
+
+pp_data->cap[68]->UsagePage                    = 0xFF01
+pp_data->cap[68]->ReportID                     = 0x02
+pp_data->cap[68]->BitPosition                  = 0
+pp_data->cap[68]->BitSize                      = 16
+pp_data->cap[68]->ReportCount                  = 1
+pp_data->cap[68]->BytePosition                 = 0x0023
+pp_data->cap[68]->BitCount                     = 16
+pp_data->cap[68]->BitField                     = 0x02
+pp_data->cap[68]->NextBytePosition             = 0x0025
+pp_data->cap[68]->LinkCollection               = 0x0002
+pp_data->cap[68]->LinkUsagePage                = 0xFF01
+pp_data->cap[68]->LinkUsage                    = 0x0002
+pp_data->cap[68]->IsMultipleItemsForArray      = 0
+pp_data->cap[68]->IsButtonCap                  = 0
+pp_data->cap[68]->IsPadding                    = 0
+pp_data->cap[68]->IsAbsolute                   = 1
+pp_data->cap[68]->IsRange                      = 0
+pp_data->cap[68]->IsAlias                      = 0
+pp_data->cap[68]->IsStringRange                = 0
+pp_data->cap[68]->IsDesignatorRange            = 0
+pp_data->cap[68]->Reserved1                    = 0x000000
+pp_data->cap[68]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[68]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[68]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[68]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[68]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[68]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[68]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[68]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[68]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[68]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[68]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[68]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[68]->NotRange.Usage                        = 0x0004
+pp_data->cap[68]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[68]->NotRange.StringIndex                  = 0
+pp_data->cap[68]->NotRange.Reserved2                    = 0
+pp_data->cap[68]->NotRange.DesignatorIndex              = 0
+pp_data->cap[68]->NotRange.Reserved3                    = 0
+pp_data->cap[68]->NotRange.DataIndex                    = 68
+pp_data->cap[68]->NotRange.Reserved4                    = 68
+pp_data->cap[68]->NotButton.HasNull                   = 0
+pp_data->cap[68]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[68]->NotButton.LogicalMin                = 0
+pp_data->cap[68]->NotButton.LogicalMax                = 4095
+pp_data->cap[68]->NotButton.PhysicalMin               = 0
+pp_data->cap[68]->NotButton.PhysicalMax               = 0
+pp_data->cap[68]->Units                    = 0
+pp_data->cap[68]->UnitsExp                 = 0
+
+pp_data->cap[69]->UsagePage                    = 0xFF01
+pp_data->cap[69]->ReportID                     = 0x02
+pp_data->cap[69]->BitPosition                  = 0
+pp_data->cap[69]->BitSize                      = 16
+pp_data->cap[69]->ReportCount                  = 1
+pp_data->cap[69]->BytePosition                 = 0x0021
+pp_data->cap[69]->BitCount                     = 16
+pp_data->cap[69]->BitField                     = 0x02
+pp_data->cap[69]->NextBytePosition             = 0x0023
+pp_data->cap[69]->LinkCollection               = 0x0002
+pp_data->cap[69]->LinkUsagePage                = 0xFF01
+pp_data->cap[69]->LinkUsage                    = 0x0002
+pp_data->cap[69]->IsMultipleItemsForArray      = 0
+pp_data->cap[69]->IsButtonCap                  = 0
+pp_data->cap[69]->IsPadding                    = 0
+pp_data->cap[69]->IsAbsolute                   = 1
+pp_data->cap[69]->IsRange                      = 0
+pp_data->cap[69]->IsAlias                      = 0
+pp_data->cap[69]->IsStringRange                = 0
+pp_data->cap[69]->IsDesignatorRange            = 0
+pp_data->cap[69]->Reserved1                    = 0x000000
+pp_data->cap[69]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[69]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[69]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[69]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[69]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[69]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[69]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[69]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[69]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[69]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[69]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[69]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[69]->NotRange.Usage                        = 0x0004
+pp_data->cap[69]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[69]->NotRange.StringIndex                  = 0
+pp_data->cap[69]->NotRange.Reserved2                    = 0
+pp_data->cap[69]->NotRange.DesignatorIndex              = 0
+pp_data->cap[69]->NotRange.Reserved3                    = 0
+pp_data->cap[69]->NotRange.DataIndex                    = 69
+pp_data->cap[69]->NotRange.Reserved4                    = 69
+pp_data->cap[69]->NotButton.HasNull                   = 0
+pp_data->cap[69]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[69]->NotButton.LogicalMin                = 0
+pp_data->cap[69]->NotButton.LogicalMax                = 4095
+pp_data->cap[69]->NotButton.PhysicalMin               = 0
+pp_data->cap[69]->NotButton.PhysicalMax               = 0
+pp_data->cap[69]->Units                    = 0
+pp_data->cap[69]->UnitsExp                 = 0
+
+pp_data->cap[70]->UsagePage                    = 0xFF01
+pp_data->cap[70]->ReportID                     = 0x02
+pp_data->cap[70]->BitPosition                  = 0
+pp_data->cap[70]->BitSize                      = 16
+pp_data->cap[70]->ReportCount                  = 1
+pp_data->cap[70]->BytePosition                 = 0x001F
+pp_data->cap[70]->BitCount                     = 16
+pp_data->cap[70]->BitField                     = 0x02
+pp_data->cap[70]->NextBytePosition             = 0x0021
+pp_data->cap[70]->LinkCollection               = 0x0002
+pp_data->cap[70]->LinkUsagePage                = 0xFF01
+pp_data->cap[70]->LinkUsage                    = 0x0002
+pp_data->cap[70]->IsMultipleItemsForArray      = 0
+pp_data->cap[70]->IsButtonCap                  = 0
+pp_data->cap[70]->IsPadding                    = 0
+pp_data->cap[70]->IsAbsolute                   = 1
+pp_data->cap[70]->IsRange                      = 0
+pp_data->cap[70]->IsAlias                      = 0
+pp_data->cap[70]->IsStringRange                = 0
+pp_data->cap[70]->IsDesignatorRange            = 0
+pp_data->cap[70]->Reserved1                    = 0x000000
+pp_data->cap[70]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[70]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[70]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[70]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[70]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[70]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[70]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[70]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[70]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[70]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[70]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[70]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[70]->NotRange.Usage                        = 0x0004
+pp_data->cap[70]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[70]->NotRange.StringIndex                  = 0
+pp_data->cap[70]->NotRange.Reserved2                    = 0
+pp_data->cap[70]->NotRange.DesignatorIndex              = 0
+pp_data->cap[70]->NotRange.Reserved3                    = 0
+pp_data->cap[70]->NotRange.DataIndex                    = 70
+pp_data->cap[70]->NotRange.Reserved4                    = 70
+pp_data->cap[70]->NotButton.HasNull                   = 0
+pp_data->cap[70]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[70]->NotButton.LogicalMin                = 0
+pp_data->cap[70]->NotButton.LogicalMax                = 4095
+pp_data->cap[70]->NotButton.PhysicalMin               = 0
+pp_data->cap[70]->NotButton.PhysicalMax               = 0
+pp_data->cap[70]->Units                    = 0
+pp_data->cap[70]->UnitsExp                 = 0
+
+pp_data->cap[71]->UsagePage                    = 0xFF01
+pp_data->cap[71]->ReportID                     = 0x02
+pp_data->cap[71]->BitPosition                  = 0
+pp_data->cap[71]->BitSize                      = 16
+pp_data->cap[71]->ReportCount                  = 1
+pp_data->cap[71]->BytePosition                 = 0x001D
+pp_data->cap[71]->BitCount                     = 16
+pp_data->cap[71]->BitField                     = 0x02
+pp_data->cap[71]->NextBytePosition             = 0x001F
+pp_data->cap[71]->LinkCollection               = 0x0002
+pp_data->cap[71]->LinkUsagePage                = 0xFF01
+pp_data->cap[71]->LinkUsage                    = 0x0002
+pp_data->cap[71]->IsMultipleItemsForArray      = 0
+pp_data->cap[71]->IsButtonCap                  = 0
+pp_data->cap[71]->IsPadding                    = 0
+pp_data->cap[71]->IsAbsolute                   = 1
+pp_data->cap[71]->IsRange                      = 0
+pp_data->cap[71]->IsAlias                      = 0
+pp_data->cap[71]->IsStringRange                = 0
+pp_data->cap[71]->IsDesignatorRange            = 0
+pp_data->cap[71]->Reserved1                    = 0x000000
+pp_data->cap[71]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[71]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[71]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[71]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[71]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[71]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[71]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[71]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[71]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[71]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[71]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[71]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[71]->NotRange.Usage                        = 0x0004
+pp_data->cap[71]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[71]->NotRange.StringIndex                  = 0
+pp_data->cap[71]->NotRange.Reserved2                    = 0
+pp_data->cap[71]->NotRange.DesignatorIndex              = 0
+pp_data->cap[71]->NotRange.Reserved3                    = 0
+pp_data->cap[71]->NotRange.DataIndex                    = 71
+pp_data->cap[71]->NotRange.Reserved4                    = 71
+pp_data->cap[71]->NotButton.HasNull                   = 0
+pp_data->cap[71]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[71]->NotButton.LogicalMin                = 0
+pp_data->cap[71]->NotButton.LogicalMax                = 4095
+pp_data->cap[71]->NotButton.PhysicalMin               = 0
+pp_data->cap[71]->NotButton.PhysicalMax               = 0
+pp_data->cap[71]->Units                    = 0
+pp_data->cap[71]->UnitsExp                 = 0
+
+pp_data->cap[72]->UsagePage                    = 0xFF01
+pp_data->cap[72]->ReportID                     = 0x02
+pp_data->cap[72]->BitPosition                  = 0
+pp_data->cap[72]->BitSize                      = 16
+pp_data->cap[72]->ReportCount                  = 1
+pp_data->cap[72]->BytePosition                 = 0x001B
+pp_data->cap[72]->BitCount                     = 16
+pp_data->cap[72]->BitField                     = 0x02
+pp_data->cap[72]->NextBytePosition             = 0x001D
+pp_data->cap[72]->LinkCollection               = 0x0002
+pp_data->cap[72]->LinkUsagePage                = 0xFF01
+pp_data->cap[72]->LinkUsage                    = 0x0002
+pp_data->cap[72]->IsMultipleItemsForArray      = 0
+pp_data->cap[72]->IsButtonCap                  = 0
+pp_data->cap[72]->IsPadding                    = 0
+pp_data->cap[72]->IsAbsolute                   = 1
+pp_data->cap[72]->IsRange                      = 0
+pp_data->cap[72]->IsAlias                      = 0
+pp_data->cap[72]->IsStringRange                = 0
+pp_data->cap[72]->IsDesignatorRange            = 0
+pp_data->cap[72]->Reserved1                    = 0x000000
+pp_data->cap[72]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[72]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[72]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[72]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[72]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[72]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[72]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[72]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[72]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[72]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[72]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[72]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[72]->NotRange.Usage                        = 0x0004
+pp_data->cap[72]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[72]->NotRange.StringIndex                  = 0
+pp_data->cap[72]->NotRange.Reserved2                    = 0
+pp_data->cap[72]->NotRange.DesignatorIndex              = 0
+pp_data->cap[72]->NotRange.Reserved3                    = 0
+pp_data->cap[72]->NotRange.DataIndex                    = 72
+pp_data->cap[72]->NotRange.Reserved4                    = 72
+pp_data->cap[72]->NotButton.HasNull                   = 0
+pp_data->cap[72]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[72]->NotButton.LogicalMin                = 0
+pp_data->cap[72]->NotButton.LogicalMax                = 4095
+pp_data->cap[72]->NotButton.PhysicalMin               = 0
+pp_data->cap[72]->NotButton.PhysicalMax               = 0
+pp_data->cap[72]->Units                    = 0
+pp_data->cap[72]->UnitsExp                 = 0
+
+pp_data->cap[73]->UsagePage                    = 0xFF01
+pp_data->cap[73]->ReportID                     = 0x02
+pp_data->cap[73]->BitPosition                  = 0
+pp_data->cap[73]->BitSize                      = 16
+pp_data->cap[73]->ReportCount                  = 1
+pp_data->cap[73]->BytePosition                 = 0x0019
+pp_data->cap[73]->BitCount                     = 16
+pp_data->cap[73]->BitField                     = 0x02
+pp_data->cap[73]->NextBytePosition             = 0x001B
+pp_data->cap[73]->LinkCollection               = 0x0002
+pp_data->cap[73]->LinkUsagePage                = 0xFF01
+pp_data->cap[73]->LinkUsage                    = 0x0002
+pp_data->cap[73]->IsMultipleItemsForArray      = 0
+pp_data->cap[73]->IsButtonCap                  = 0
+pp_data->cap[73]->IsPadding                    = 0
+pp_data->cap[73]->IsAbsolute                   = 1
+pp_data->cap[73]->IsRange                      = 0
+pp_data->cap[73]->IsAlias                      = 0
+pp_data->cap[73]->IsStringRange                = 0
+pp_data->cap[73]->IsDesignatorRange            = 0
+pp_data->cap[73]->Reserved1                    = 0x000000
+pp_data->cap[73]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[73]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[73]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[73]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[73]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[73]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[73]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[73]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[73]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[73]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[73]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[73]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[73]->NotRange.Usage                        = 0x0004
+pp_data->cap[73]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[73]->NotRange.StringIndex                  = 0
+pp_data->cap[73]->NotRange.Reserved2                    = 0
+pp_data->cap[73]->NotRange.DesignatorIndex              = 0
+pp_data->cap[73]->NotRange.Reserved3                    = 0
+pp_data->cap[73]->NotRange.DataIndex                    = 73
+pp_data->cap[73]->NotRange.Reserved4                    = 73
+pp_data->cap[73]->NotButton.HasNull                   = 0
+pp_data->cap[73]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[73]->NotButton.LogicalMin                = 0
+pp_data->cap[73]->NotButton.LogicalMax                = 4095
+pp_data->cap[73]->NotButton.PhysicalMin               = 0
+pp_data->cap[73]->NotButton.PhysicalMax               = 0
+pp_data->cap[73]->Units                    = 0
+pp_data->cap[73]->UnitsExp                 = 0
+
+pp_data->cap[74]->UsagePage                    = 0xFF01
+pp_data->cap[74]->ReportID                     = 0x02
+pp_data->cap[74]->BitPosition                  = 0
+pp_data->cap[74]->BitSize                      = 16
+pp_data->cap[74]->ReportCount                  = 1
+pp_data->cap[74]->BytePosition                 = 0x0017
+pp_data->cap[74]->BitCount                     = 16
+pp_data->cap[74]->BitField                     = 0x02
+pp_data->cap[74]->NextBytePosition             = 0x0019
+pp_data->cap[74]->LinkCollection               = 0x0002
+pp_data->cap[74]->LinkUsagePage                = 0xFF01
+pp_data->cap[74]->LinkUsage                    = 0x0002
+pp_data->cap[74]->IsMultipleItemsForArray      = 0
+pp_data->cap[74]->IsButtonCap                  = 0
+pp_data->cap[74]->IsPadding                    = 0
+pp_data->cap[74]->IsAbsolute                   = 1
+pp_data->cap[74]->IsRange                      = 0
+pp_data->cap[74]->IsAlias                      = 0
+pp_data->cap[74]->IsStringRange                = 0
+pp_data->cap[74]->IsDesignatorRange            = 0
+pp_data->cap[74]->Reserved1                    = 0x000000
+pp_data->cap[74]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[74]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[74]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[74]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[74]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[74]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[74]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[74]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[74]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[74]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[74]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[74]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[74]->NotRange.Usage                        = 0x0004
+pp_data->cap[74]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[74]->NotRange.StringIndex                  = 0
+pp_data->cap[74]->NotRange.Reserved2                    = 0
+pp_data->cap[74]->NotRange.DesignatorIndex              = 0
+pp_data->cap[74]->NotRange.Reserved3                    = 0
+pp_data->cap[74]->NotRange.DataIndex                    = 74
+pp_data->cap[74]->NotRange.Reserved4                    = 74
+pp_data->cap[74]->NotButton.HasNull                   = 0
+pp_data->cap[74]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[74]->NotButton.LogicalMin                = 0
+pp_data->cap[74]->NotButton.LogicalMax                = 4095
+pp_data->cap[74]->NotButton.PhysicalMin               = 0
+pp_data->cap[74]->NotButton.PhysicalMax               = 0
+pp_data->cap[74]->Units                    = 0
+pp_data->cap[74]->UnitsExp                 = 0
+
+pp_data->cap[75]->UsagePage                    = 0xFF01
+pp_data->cap[75]->ReportID                     = 0x02
+pp_data->cap[75]->BitPosition                  = 0
+pp_data->cap[75]->BitSize                      = 16
+pp_data->cap[75]->ReportCount                  = 1
+pp_data->cap[75]->BytePosition                 = 0x0015
+pp_data->cap[75]->BitCount                     = 16
+pp_data->cap[75]->BitField                     = 0x02
+pp_data->cap[75]->NextBytePosition             = 0x0017
+pp_data->cap[75]->LinkCollection               = 0x0002
+pp_data->cap[75]->LinkUsagePage                = 0xFF01
+pp_data->cap[75]->LinkUsage                    = 0x0002
+pp_data->cap[75]->IsMultipleItemsForArray      = 0
+pp_data->cap[75]->IsButtonCap                  = 0
+pp_data->cap[75]->IsPadding                    = 0
+pp_data->cap[75]->IsAbsolute                   = 1
+pp_data->cap[75]->IsRange                      = 0
+pp_data->cap[75]->IsAlias                      = 0
+pp_data->cap[75]->IsStringRange                = 0
+pp_data->cap[75]->IsDesignatorRange            = 0
+pp_data->cap[75]->Reserved1                    = 0x000000
+pp_data->cap[75]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[75]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[75]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[75]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[75]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[75]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[75]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[75]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[75]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[75]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[75]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[75]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[75]->NotRange.Usage                        = 0x0004
+pp_data->cap[75]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[75]->NotRange.StringIndex                  = 0
+pp_data->cap[75]->NotRange.Reserved2                    = 0
+pp_data->cap[75]->NotRange.DesignatorIndex              = 0
+pp_data->cap[75]->NotRange.Reserved3                    = 0
+pp_data->cap[75]->NotRange.DataIndex                    = 75
+pp_data->cap[75]->NotRange.Reserved4                    = 75
+pp_data->cap[75]->NotButton.HasNull                   = 0
+pp_data->cap[75]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[75]->NotButton.LogicalMin                = 0
+pp_data->cap[75]->NotButton.LogicalMax                = 4095
+pp_data->cap[75]->NotButton.PhysicalMin               = 0
+pp_data->cap[75]->NotButton.PhysicalMax               = 0
+pp_data->cap[75]->Units                    = 0
+pp_data->cap[75]->UnitsExp                 = 0
+
+pp_data->cap[76]->UsagePage                    = 0xFF01
+pp_data->cap[76]->ReportID                     = 0x02
+pp_data->cap[76]->BitPosition                  = 0
+pp_data->cap[76]->BitSize                      = 16
+pp_data->cap[76]->ReportCount                  = 1
+pp_data->cap[76]->BytePosition                 = 0x0013
+pp_data->cap[76]->BitCount                     = 16
+pp_data->cap[76]->BitField                     = 0x02
+pp_data->cap[76]->NextBytePosition             = 0x0015
+pp_data->cap[76]->LinkCollection               = 0x0002
+pp_data->cap[76]->LinkUsagePage                = 0xFF01
+pp_data->cap[76]->LinkUsage                    = 0x0002
+pp_data->cap[76]->IsMultipleItemsForArray      = 0
+pp_data->cap[76]->IsButtonCap                  = 0
+pp_data->cap[76]->IsPadding                    = 0
+pp_data->cap[76]->IsAbsolute                   = 1
+pp_data->cap[76]->IsRange                      = 0
+pp_data->cap[76]->IsAlias                      = 0
+pp_data->cap[76]->IsStringRange                = 0
+pp_data->cap[76]->IsDesignatorRange            = 0
+pp_data->cap[76]->Reserved1                    = 0x000000
+pp_data->cap[76]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[76]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[76]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[76]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[76]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[76]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[76]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[76]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[76]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[76]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[76]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[76]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[76]->NotRange.Usage                        = 0x0004
+pp_data->cap[76]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[76]->NotRange.StringIndex                  = 0
+pp_data->cap[76]->NotRange.Reserved2                    = 0
+pp_data->cap[76]->NotRange.DesignatorIndex              = 0
+pp_data->cap[76]->NotRange.Reserved3                    = 0
+pp_data->cap[76]->NotRange.DataIndex                    = 76
+pp_data->cap[76]->NotRange.Reserved4                    = 76
+pp_data->cap[76]->NotButton.HasNull                   = 0
+pp_data->cap[76]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[76]->NotButton.LogicalMin                = 0
+pp_data->cap[76]->NotButton.LogicalMax                = 4095
+pp_data->cap[76]->NotButton.PhysicalMin               = 0
+pp_data->cap[76]->NotButton.PhysicalMax               = 0
+pp_data->cap[76]->Units                    = 0
+pp_data->cap[76]->UnitsExp                 = 0
+
+pp_data->cap[77]->UsagePage                    = 0xFF01
+pp_data->cap[77]->ReportID                     = 0x02
+pp_data->cap[77]->BitPosition                  = 0
+pp_data->cap[77]->BitSize                      = 16
+pp_data->cap[77]->ReportCount                  = 1
+pp_data->cap[77]->BytePosition                 = 0x0011
+pp_data->cap[77]->BitCount                     = 16
+pp_data->cap[77]->BitField                     = 0x02
+pp_data->cap[77]->NextBytePosition             = 0x0013
+pp_data->cap[77]->LinkCollection               = 0x0002
+pp_data->cap[77]->LinkUsagePage                = 0xFF01
+pp_data->cap[77]->LinkUsage                    = 0x0002
+pp_data->cap[77]->IsMultipleItemsForArray      = 0
+pp_data->cap[77]->IsButtonCap                  = 0
+pp_data->cap[77]->IsPadding                    = 0
+pp_data->cap[77]->IsAbsolute                   = 1
+pp_data->cap[77]->IsRange                      = 0
+pp_data->cap[77]->IsAlias                      = 0
+pp_data->cap[77]->IsStringRange                = 0
+pp_data->cap[77]->IsDesignatorRange            = 0
+pp_data->cap[77]->Reserved1                    = 0x000000
+pp_data->cap[77]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[77]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[77]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[77]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[77]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[77]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[77]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[77]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[77]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[77]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[77]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[77]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[77]->NotRange.Usage                        = 0x0004
+pp_data->cap[77]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[77]->NotRange.StringIndex                  = 0
+pp_data->cap[77]->NotRange.Reserved2                    = 0
+pp_data->cap[77]->NotRange.DesignatorIndex              = 0
+pp_data->cap[77]->NotRange.Reserved3                    = 0
+pp_data->cap[77]->NotRange.DataIndex                    = 77
+pp_data->cap[77]->NotRange.Reserved4                    = 77
+pp_data->cap[77]->NotButton.HasNull                   = 0
+pp_data->cap[77]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[77]->NotButton.LogicalMin                = 0
+pp_data->cap[77]->NotButton.LogicalMax                = 4095
+pp_data->cap[77]->NotButton.PhysicalMin               = 0
+pp_data->cap[77]->NotButton.PhysicalMax               = 0
+pp_data->cap[77]->Units                    = 0
+pp_data->cap[77]->UnitsExp                 = 0
+
+pp_data->cap[78]->UsagePage                    = 0xFF01
+pp_data->cap[78]->ReportID                     = 0x02
+pp_data->cap[78]->BitPosition                  = 0
+pp_data->cap[78]->BitSize                      = 16
+pp_data->cap[78]->ReportCount                  = 1
+pp_data->cap[78]->BytePosition                 = 0x000F
+pp_data->cap[78]->BitCount                     = 16
+pp_data->cap[78]->BitField                     = 0x02
+pp_data->cap[78]->NextBytePosition             = 0x0011
+pp_data->cap[78]->LinkCollection               = 0x0002
+pp_data->cap[78]->LinkUsagePage                = 0xFF01
+pp_data->cap[78]->LinkUsage                    = 0x0002
+pp_data->cap[78]->IsMultipleItemsForArray      = 0
+pp_data->cap[78]->IsButtonCap                  = 0
+pp_data->cap[78]->IsPadding                    = 0
+pp_data->cap[78]->IsAbsolute                   = 1
+pp_data->cap[78]->IsRange                      = 0
+pp_data->cap[78]->IsAlias                      = 0
+pp_data->cap[78]->IsStringRange                = 0
+pp_data->cap[78]->IsDesignatorRange            = 0
+pp_data->cap[78]->Reserved1                    = 0x000000
+pp_data->cap[78]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[78]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[78]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[78]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[78]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[78]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[78]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[78]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[78]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[78]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[78]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[78]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[78]->NotRange.Usage                        = 0x0004
+pp_data->cap[78]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[78]->NotRange.StringIndex                  = 0
+pp_data->cap[78]->NotRange.Reserved2                    = 0
+pp_data->cap[78]->NotRange.DesignatorIndex              = 0
+pp_data->cap[78]->NotRange.Reserved3                    = 0
+pp_data->cap[78]->NotRange.DataIndex                    = 78
+pp_data->cap[78]->NotRange.Reserved4                    = 78
+pp_data->cap[78]->NotButton.HasNull                   = 0
+pp_data->cap[78]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[78]->NotButton.LogicalMin                = 0
+pp_data->cap[78]->NotButton.LogicalMax                = 4095
+pp_data->cap[78]->NotButton.PhysicalMin               = 0
+pp_data->cap[78]->NotButton.PhysicalMax               = 0
+pp_data->cap[78]->Units                    = 0
+pp_data->cap[78]->UnitsExp                 = 0
+
+pp_data->cap[79]->UsagePage                    = 0xFF01
+pp_data->cap[79]->ReportID                     = 0x02
+pp_data->cap[79]->BitPosition                  = 0
+pp_data->cap[79]->BitSize                      = 16
+pp_data->cap[79]->ReportCount                  = 1
+pp_data->cap[79]->BytePosition                 = 0x000D
+pp_data->cap[79]->BitCount                     = 16
+pp_data->cap[79]->BitField                     = 0x02
+pp_data->cap[79]->NextBytePosition             = 0x000F
+pp_data->cap[79]->LinkCollection               = 0x0002
+pp_data->cap[79]->LinkUsagePage                = 0xFF01
+pp_data->cap[79]->LinkUsage                    = 0x0002
+pp_data->cap[79]->IsMultipleItemsForArray      = 0
+pp_data->cap[79]->IsButtonCap                  = 0
+pp_data->cap[79]->IsPadding                    = 0
+pp_data->cap[79]->IsAbsolute                   = 1
+pp_data->cap[79]->IsRange                      = 0
+pp_data->cap[79]->IsAlias                      = 0
+pp_data->cap[79]->IsStringRange                = 0
+pp_data->cap[79]->IsDesignatorRange            = 0
+pp_data->cap[79]->Reserved1                    = 0x000000
+pp_data->cap[79]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[79]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[79]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[79]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[79]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[79]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[79]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[79]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[79]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[79]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[79]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[79]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[79]->NotRange.Usage                        = 0x0004
+pp_data->cap[79]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[79]->NotRange.StringIndex                  = 0
+pp_data->cap[79]->NotRange.Reserved2                    = 0
+pp_data->cap[79]->NotRange.DesignatorIndex              = 0
+pp_data->cap[79]->NotRange.Reserved3                    = 0
+pp_data->cap[79]->NotRange.DataIndex                    = 79
+pp_data->cap[79]->NotRange.Reserved4                    = 79
+pp_data->cap[79]->NotButton.HasNull                   = 0
+pp_data->cap[79]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[79]->NotButton.LogicalMin                = 0
+pp_data->cap[79]->NotButton.LogicalMax                = 4095
+pp_data->cap[79]->NotButton.PhysicalMin               = 0
+pp_data->cap[79]->NotButton.PhysicalMax               = 0
+pp_data->cap[79]->Units                    = 0
+pp_data->cap[79]->UnitsExp                 = 0
+
+pp_data->cap[80]->UsagePage                    = 0xFF01
+pp_data->cap[80]->ReportID                     = 0x02
+pp_data->cap[80]->BitPosition                  = 0
+pp_data->cap[80]->BitSize                      = 16
+pp_data->cap[80]->ReportCount                  = 1
+pp_data->cap[80]->BytePosition                 = 0x000B
+pp_data->cap[80]->BitCount                     = 16
+pp_data->cap[80]->BitField                     = 0x02
+pp_data->cap[80]->NextBytePosition             = 0x000D
+pp_data->cap[80]->LinkCollection               = 0x0002
+pp_data->cap[80]->LinkUsagePage                = 0xFF01
+pp_data->cap[80]->LinkUsage                    = 0x0002
+pp_data->cap[80]->IsMultipleItemsForArray      = 0
+pp_data->cap[80]->IsButtonCap                  = 0
+pp_data->cap[80]->IsPadding                    = 0
+pp_data->cap[80]->IsAbsolute                   = 1
+pp_data->cap[80]->IsRange                      = 0
+pp_data->cap[80]->IsAlias                      = 0
+pp_data->cap[80]->IsStringRange                = 0
+pp_data->cap[80]->IsDesignatorRange            = 0
+pp_data->cap[80]->Reserved1                    = 0x000000
+pp_data->cap[80]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[80]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[80]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[80]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[80]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[80]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[80]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[80]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[80]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[80]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[80]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[80]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[80]->NotRange.Usage                        = 0x0004
+pp_data->cap[80]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[80]->NotRange.StringIndex                  = 0
+pp_data->cap[80]->NotRange.Reserved2                    = 0
+pp_data->cap[80]->NotRange.DesignatorIndex              = 0
+pp_data->cap[80]->NotRange.Reserved3                    = 0
+pp_data->cap[80]->NotRange.DataIndex                    = 80
+pp_data->cap[80]->NotRange.Reserved4                    = 80
+pp_data->cap[80]->NotButton.HasNull                   = 0
+pp_data->cap[80]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[80]->NotButton.LogicalMin                = 0
+pp_data->cap[80]->NotButton.LogicalMax                = 4095
+pp_data->cap[80]->NotButton.PhysicalMin               = 0
+pp_data->cap[80]->NotButton.PhysicalMax               = 0
+pp_data->cap[80]->Units                    = 0
+pp_data->cap[80]->UnitsExp                 = 0
+
+pp_data->cap[81]->UsagePage                    = 0xFF01
+pp_data->cap[81]->ReportID                     = 0x02
+pp_data->cap[81]->BitPosition                  = 0
+pp_data->cap[81]->BitSize                      = 16
+pp_data->cap[81]->ReportCount                  = 1
+pp_data->cap[81]->BytePosition                 = 0x0009
+pp_data->cap[81]->BitCount                     = 16
+pp_data->cap[81]->BitField                     = 0x02
+pp_data->cap[81]->NextBytePosition             = 0x000B
+pp_data->cap[81]->LinkCollection               = 0x0002
+pp_data->cap[81]->LinkUsagePage                = 0xFF01
+pp_data->cap[81]->LinkUsage                    = 0x0002
+pp_data->cap[81]->IsMultipleItemsForArray      = 0
+pp_data->cap[81]->IsButtonCap                  = 0
+pp_data->cap[81]->IsPadding                    = 0
+pp_data->cap[81]->IsAbsolute                   = 1
+pp_data->cap[81]->IsRange                      = 0
+pp_data->cap[81]->IsAlias                      = 0
+pp_data->cap[81]->IsStringRange                = 0
+pp_data->cap[81]->IsDesignatorRange            = 0
+pp_data->cap[81]->Reserved1                    = 0x000000
+pp_data->cap[81]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[81]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[81]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[81]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[81]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[81]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[81]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[81]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[81]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[81]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[81]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[81]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[81]->NotRange.Usage                        = 0x0004
+pp_data->cap[81]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[81]->NotRange.StringIndex                  = 0
+pp_data->cap[81]->NotRange.Reserved2                    = 0
+pp_data->cap[81]->NotRange.DesignatorIndex              = 0
+pp_data->cap[81]->NotRange.Reserved3                    = 0
+pp_data->cap[81]->NotRange.DataIndex                    = 81
+pp_data->cap[81]->NotRange.Reserved4                    = 81
+pp_data->cap[81]->NotButton.HasNull                   = 0
+pp_data->cap[81]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[81]->NotButton.LogicalMin                = 0
+pp_data->cap[81]->NotButton.LogicalMax                = 4095
+pp_data->cap[81]->NotButton.PhysicalMin               = 0
+pp_data->cap[81]->NotButton.PhysicalMax               = 0
+pp_data->cap[81]->Units                    = 0
+pp_data->cap[81]->UnitsExp                 = 0
+
+pp_data->cap[82]->UsagePage                    = 0xFF01
+pp_data->cap[82]->ReportID                     = 0x02
+pp_data->cap[82]->BitPosition                  = 0
+pp_data->cap[82]->BitSize                      = 16
+pp_data->cap[82]->ReportCount                  = 1
+pp_data->cap[82]->BytePosition                 = 0x0007
+pp_data->cap[82]->BitCount                     = 16
+pp_data->cap[82]->BitField                     = 0x02
+pp_data->cap[82]->NextBytePosition             = 0x0009
+pp_data->cap[82]->LinkCollection               = 0x0002
+pp_data->cap[82]->LinkUsagePage                = 0xFF01
+pp_data->cap[82]->LinkUsage                    = 0x0002
+pp_data->cap[82]->IsMultipleItemsForArray      = 0
+pp_data->cap[82]->IsButtonCap                  = 0
+pp_data->cap[82]->IsPadding                    = 0
+pp_data->cap[82]->IsAbsolute                   = 1
+pp_data->cap[82]->IsRange                      = 0
+pp_data->cap[82]->IsAlias                      = 0
+pp_data->cap[82]->IsStringRange                = 0
+pp_data->cap[82]->IsDesignatorRange            = 0
+pp_data->cap[82]->Reserved1                    = 0x000000
+pp_data->cap[82]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[82]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[82]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[82]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[82]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[82]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[82]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[82]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[82]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[82]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[82]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[82]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[82]->NotRange.Usage                        = 0x0004
+pp_data->cap[82]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[82]->NotRange.StringIndex                  = 0
+pp_data->cap[82]->NotRange.Reserved2                    = 0
+pp_data->cap[82]->NotRange.DesignatorIndex              = 0
+pp_data->cap[82]->NotRange.Reserved3                    = 0
+pp_data->cap[82]->NotRange.DataIndex                    = 82
+pp_data->cap[82]->NotRange.Reserved4                    = 82
+pp_data->cap[82]->NotButton.HasNull                   = 0
+pp_data->cap[82]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[82]->NotButton.LogicalMin                = 0
+pp_data->cap[82]->NotButton.LogicalMax                = 4095
+pp_data->cap[82]->NotButton.PhysicalMin               = 0
+pp_data->cap[82]->NotButton.PhysicalMax               = 0
+pp_data->cap[82]->Units                    = 0
+pp_data->cap[82]->UnitsExp                 = 0
+
+pp_data->cap[83]->UsagePage                    = 0xFF01
+pp_data->cap[83]->ReportID                     = 0x02
+pp_data->cap[83]->BitPosition                  = 0
+pp_data->cap[83]->BitSize                      = 16
+pp_data->cap[83]->ReportCount                  = 1
+pp_data->cap[83]->BytePosition                 = 0x0005
+pp_data->cap[83]->BitCount                     = 16
+pp_data->cap[83]->BitField                     = 0x02
+pp_data->cap[83]->NextBytePosition             = 0x0007
+pp_data->cap[83]->LinkCollection               = 0x0002
+pp_data->cap[83]->LinkUsagePage                = 0xFF01
+pp_data->cap[83]->LinkUsage                    = 0x0002
+pp_data->cap[83]->IsMultipleItemsForArray      = 0
+pp_data->cap[83]->IsButtonCap                  = 0
+pp_data->cap[83]->IsPadding                    = 0
+pp_data->cap[83]->IsAbsolute                   = 1
+pp_data->cap[83]->IsRange                      = 0
+pp_data->cap[83]->IsAlias                      = 0
+pp_data->cap[83]->IsStringRange                = 0
+pp_data->cap[83]->IsDesignatorRange            = 0
+pp_data->cap[83]->Reserved1                    = 0x000000
+pp_data->cap[83]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[83]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[83]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[83]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[83]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[83]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[83]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[83]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[83]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[83]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[83]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[83]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[83]->NotRange.Usage                        = 0x0004
+pp_data->cap[83]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[83]->NotRange.StringIndex                  = 0
+pp_data->cap[83]->NotRange.Reserved2                    = 0
+pp_data->cap[83]->NotRange.DesignatorIndex              = 0
+pp_data->cap[83]->NotRange.Reserved3                    = 0
+pp_data->cap[83]->NotRange.DataIndex                    = 83
+pp_data->cap[83]->NotRange.Reserved4                    = 83
+pp_data->cap[83]->NotButton.HasNull                   = 0
+pp_data->cap[83]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[83]->NotButton.LogicalMin                = 0
+pp_data->cap[83]->NotButton.LogicalMax                = 4095
+pp_data->cap[83]->NotButton.PhysicalMin               = 0
+pp_data->cap[83]->NotButton.PhysicalMax               = 0
+pp_data->cap[83]->Units                    = 0
+pp_data->cap[83]->UnitsExp                 = 0
+
+pp_data->cap[84]->UsagePage                    = 0xFF01
+pp_data->cap[84]->ReportID                     = 0x02
+pp_data->cap[84]->BitPosition                  = 0
+pp_data->cap[84]->BitSize                      = 16
+pp_data->cap[84]->ReportCount                  = 1
+pp_data->cap[84]->BytePosition                 = 0x0003
+pp_data->cap[84]->BitCount                     = 16
+pp_data->cap[84]->BitField                     = 0x02
+pp_data->cap[84]->NextBytePosition             = 0x0005
+pp_data->cap[84]->LinkCollection               = 0x0002
+pp_data->cap[84]->LinkUsagePage                = 0xFF01
+pp_data->cap[84]->LinkUsage                    = 0x0002
+pp_data->cap[84]->IsMultipleItemsForArray      = 0
+pp_data->cap[84]->IsButtonCap                  = 0
+pp_data->cap[84]->IsPadding                    = 0
+pp_data->cap[84]->IsAbsolute                   = 1
+pp_data->cap[84]->IsRange                      = 0
+pp_data->cap[84]->IsAlias                      = 0
+pp_data->cap[84]->IsStringRange                = 0
+pp_data->cap[84]->IsDesignatorRange            = 0
+pp_data->cap[84]->Reserved1                    = 0x000000
+pp_data->cap[84]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[84]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[84]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[84]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[84]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[84]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[84]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[84]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[84]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[84]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[84]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[84]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[84]->NotRange.Usage                        = 0x0004
+pp_data->cap[84]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[84]->NotRange.StringIndex                  = 0
+pp_data->cap[84]->NotRange.Reserved2                    = 0
+pp_data->cap[84]->NotRange.DesignatorIndex              = 0
+pp_data->cap[84]->NotRange.Reserved3                    = 0
+pp_data->cap[84]->NotRange.DataIndex                    = 84
+pp_data->cap[84]->NotRange.Reserved4                    = 84
+pp_data->cap[84]->NotButton.HasNull                   = 0
+pp_data->cap[84]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[84]->NotButton.LogicalMin                = 0
+pp_data->cap[84]->NotButton.LogicalMax                = 4095
+pp_data->cap[84]->NotButton.PhysicalMin               = 0
+pp_data->cap[84]->NotButton.PhysicalMax               = 0
+pp_data->cap[84]->Units                    = 0
+pp_data->cap[84]->UnitsExp                 = 0
+
+pp_data->cap[85]->UsagePage                    = 0xFF01
+pp_data->cap[85]->ReportID                     = 0x02
+pp_data->cap[85]->BitPosition                  = 0
+pp_data->cap[85]->BitSize                      = 16
+pp_data->cap[85]->ReportCount                  = 1
+pp_data->cap[85]->BytePosition                 = 0x0001
+pp_data->cap[85]->BitCount                     = 16
+pp_data->cap[85]->BitField                     = 0x02
+pp_data->cap[85]->NextBytePosition             = 0x0003
+pp_data->cap[85]->LinkCollection               = 0x0002
+pp_data->cap[85]->LinkUsagePage                = 0xFF01
+pp_data->cap[85]->LinkUsage                    = 0x0002
+pp_data->cap[85]->IsMultipleItemsForArray      = 0
+pp_data->cap[85]->IsButtonCap                  = 0
+pp_data->cap[85]->IsPadding                    = 0
+pp_data->cap[85]->IsAbsolute                   = 1
+pp_data->cap[85]->IsRange                      = 0
+pp_data->cap[85]->IsAlias                      = 0
+pp_data->cap[85]->IsStringRange                = 0
+pp_data->cap[85]->IsDesignatorRange            = 0
+pp_data->cap[85]->Reserved1                    = 0x000000
+pp_data->cap[85]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[85]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[85]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[85]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[85]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[85]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[85]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[85]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[85]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[85]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[85]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[85]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[85]->NotRange.Usage                        = 0x0004
+pp_data->cap[85]->NotRange.Reserved1                    = 0x0004
+pp_data->cap[85]->NotRange.StringIndex                  = 0
+pp_data->cap[85]->NotRange.Reserved2                    = 0
+pp_data->cap[85]->NotRange.DesignatorIndex              = 0
+pp_data->cap[85]->NotRange.Reserved3                    = 0
+pp_data->cap[85]->NotRange.DataIndex                    = 85
+pp_data->cap[85]->NotRange.Reserved4                    = 85
+pp_data->cap[85]->NotButton.HasNull                   = 0
+pp_data->cap[85]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[85]->NotButton.LogicalMin                = 0
+pp_data->cap[85]->NotButton.LogicalMax                = 4095
+pp_data->cap[85]->NotButton.PhysicalMin               = 0
+pp_data->cap[85]->NotButton.PhysicalMax               = 0
+pp_data->cap[85]->Units                    = 0
+pp_data->cap[85]->UnitsExp                 = 0
+
+# Output hid_pp_cap struct:
+pp_data->cap[87]->UsagePage                    = 0xFF01
+pp_data->cap[87]->ReportID                     = 0x80
+pp_data->cap[87]->BitPosition                  = 0
+pp_data->cap[87]->BitSize                      = 8
+pp_data->cap[87]->ReportCount                  = 1
+pp_data->cap[87]->BytePosition                 = 0x005E
+pp_data->cap[87]->BitCount                     = 8
+pp_data->cap[87]->BitField                     = 0x02
+pp_data->cap[87]->NextBytePosition             = 0x005F
+pp_data->cap[87]->LinkCollection               = 0x0003
+pp_data->cap[87]->LinkUsagePage                = 0xFF01
+pp_data->cap[87]->LinkUsage                    = 0x0080
+pp_data->cap[87]->IsMultipleItemsForArray      = 0
+pp_data->cap[87]->IsButtonCap                  = 0
+pp_data->cap[87]->IsPadding                    = 0
+pp_data->cap[87]->IsAbsolute                   = 1
+pp_data->cap[87]->IsRange                      = 0
+pp_data->cap[87]->IsAlias                      = 0
+pp_data->cap[87]->IsStringRange                = 0
+pp_data->cap[87]->IsDesignatorRange            = 0
+pp_data->cap[87]->Reserved1                    = 0x000000
+pp_data->cap[87]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[87]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[87]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[87]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[87]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[87]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[87]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[87]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[87]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[87]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[87]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[87]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[87]->NotRange.Usage                        = 0x0081
+pp_data->cap[87]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[87]->NotRange.StringIndex                  = 0
+pp_data->cap[87]->NotRange.Reserved2                    = 0
+pp_data->cap[87]->NotRange.DesignatorIndex              = 0
+pp_data->cap[87]->NotRange.Reserved3                    = 0
+pp_data->cap[87]->NotRange.DataIndex                    = 0
+pp_data->cap[87]->NotRange.Reserved4                    = 0
+pp_data->cap[87]->NotButton.HasNull                   = 0
+pp_data->cap[87]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[87]->NotButton.LogicalMin                = 0
+pp_data->cap[87]->NotButton.LogicalMax                = 127
+pp_data->cap[87]->NotButton.PhysicalMin               = 0
+pp_data->cap[87]->NotButton.PhysicalMax               = 0
+pp_data->cap[87]->Units                    = 0
+pp_data->cap[87]->UnitsExp                 = 0
+
+pp_data->cap[88]->UsagePage                    = 0xFF01
+pp_data->cap[88]->ReportID                     = 0x80
+pp_data->cap[88]->BitPosition                  = 0
+pp_data->cap[88]->BitSize                      = 8
+pp_data->cap[88]->ReportCount                  = 1
+pp_data->cap[88]->BytePosition                 = 0x005D
+pp_data->cap[88]->BitCount                     = 8
+pp_data->cap[88]->BitField                     = 0x02
+pp_data->cap[88]->NextBytePosition             = 0x005E
+pp_data->cap[88]->LinkCollection               = 0x0003
+pp_data->cap[88]->LinkUsagePage                = 0xFF01
+pp_data->cap[88]->LinkUsage                    = 0x0080
+pp_data->cap[88]->IsMultipleItemsForArray      = 0
+pp_data->cap[88]->IsButtonCap                  = 0
+pp_data->cap[88]->IsPadding                    = 0
+pp_data->cap[88]->IsAbsolute                   = 1
+pp_data->cap[88]->IsRange                      = 0
+pp_data->cap[88]->IsAlias                      = 0
+pp_data->cap[88]->IsStringRange                = 0
+pp_data->cap[88]->IsDesignatorRange            = 0
+pp_data->cap[88]->Reserved1                    = 0x000000
+pp_data->cap[88]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[88]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[88]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[88]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[88]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[88]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[88]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[88]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[88]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[88]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[88]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[88]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[88]->NotRange.Usage                        = 0x0081
+pp_data->cap[88]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[88]->NotRange.StringIndex                  = 0
+pp_data->cap[88]->NotRange.Reserved2                    = 0
+pp_data->cap[88]->NotRange.DesignatorIndex              = 0
+pp_data->cap[88]->NotRange.Reserved3                    = 0
+pp_data->cap[88]->NotRange.DataIndex                    = 1
+pp_data->cap[88]->NotRange.Reserved4                    = 1
+pp_data->cap[88]->NotButton.HasNull                   = 0
+pp_data->cap[88]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[88]->NotButton.LogicalMin                = 0
+pp_data->cap[88]->NotButton.LogicalMax                = 127
+pp_data->cap[88]->NotButton.PhysicalMin               = 0
+pp_data->cap[88]->NotButton.PhysicalMax               = 0
+pp_data->cap[88]->Units                    = 0
+pp_data->cap[88]->UnitsExp                 = 0
+
+pp_data->cap[89]->UsagePage                    = 0xFF01
+pp_data->cap[89]->ReportID                     = 0x80
+pp_data->cap[89]->BitPosition                  = 0
+pp_data->cap[89]->BitSize                      = 8
+pp_data->cap[89]->ReportCount                  = 1
+pp_data->cap[89]->BytePosition                 = 0x005C
+pp_data->cap[89]->BitCount                     = 8
+pp_data->cap[89]->BitField                     = 0x02
+pp_data->cap[89]->NextBytePosition             = 0x005D
+pp_data->cap[89]->LinkCollection               = 0x0003
+pp_data->cap[89]->LinkUsagePage                = 0xFF01
+pp_data->cap[89]->LinkUsage                    = 0x0080
+pp_data->cap[89]->IsMultipleItemsForArray      = 0
+pp_data->cap[89]->IsButtonCap                  = 0
+pp_data->cap[89]->IsPadding                    = 0
+pp_data->cap[89]->IsAbsolute                   = 1
+pp_data->cap[89]->IsRange                      = 0
+pp_data->cap[89]->IsAlias                      = 0
+pp_data->cap[89]->IsStringRange                = 0
+pp_data->cap[89]->IsDesignatorRange            = 0
+pp_data->cap[89]->Reserved1                    = 0x000000
+pp_data->cap[89]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[89]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[89]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[89]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[89]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[89]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[89]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[89]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[89]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[89]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[89]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[89]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[89]->NotRange.Usage                        = 0x0081
+pp_data->cap[89]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[89]->NotRange.StringIndex                  = 0
+pp_data->cap[89]->NotRange.Reserved2                    = 0
+pp_data->cap[89]->NotRange.DesignatorIndex              = 0
+pp_data->cap[89]->NotRange.Reserved3                    = 0
+pp_data->cap[89]->NotRange.DataIndex                    = 2
+pp_data->cap[89]->NotRange.Reserved4                    = 2
+pp_data->cap[89]->NotButton.HasNull                   = 0
+pp_data->cap[89]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[89]->NotButton.LogicalMin                = 0
+pp_data->cap[89]->NotButton.LogicalMax                = 127
+pp_data->cap[89]->NotButton.PhysicalMin               = 0
+pp_data->cap[89]->NotButton.PhysicalMax               = 0
+pp_data->cap[89]->Units                    = 0
+pp_data->cap[89]->UnitsExp                 = 0
+
+pp_data->cap[90]->UsagePage                    = 0xFF01
+pp_data->cap[90]->ReportID                     = 0x80
+pp_data->cap[90]->BitPosition                  = 0
+pp_data->cap[90]->BitSize                      = 8
+pp_data->cap[90]->ReportCount                  = 1
+pp_data->cap[90]->BytePosition                 = 0x005B
+pp_data->cap[90]->BitCount                     = 8
+pp_data->cap[90]->BitField                     = 0x02
+pp_data->cap[90]->NextBytePosition             = 0x005C
+pp_data->cap[90]->LinkCollection               = 0x0003
+pp_data->cap[90]->LinkUsagePage                = 0xFF01
+pp_data->cap[90]->LinkUsage                    = 0x0080
+pp_data->cap[90]->IsMultipleItemsForArray      = 0
+pp_data->cap[90]->IsButtonCap                  = 0
+pp_data->cap[90]->IsPadding                    = 0
+pp_data->cap[90]->IsAbsolute                   = 1
+pp_data->cap[90]->IsRange                      = 0
+pp_data->cap[90]->IsAlias                      = 0
+pp_data->cap[90]->IsStringRange                = 0
+pp_data->cap[90]->IsDesignatorRange            = 0
+pp_data->cap[90]->Reserved1                    = 0x000000
+pp_data->cap[90]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[90]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[90]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[90]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[90]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[90]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[90]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[90]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[90]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[90]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[90]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[90]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[90]->NotRange.Usage                        = 0x0081
+pp_data->cap[90]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[90]->NotRange.StringIndex                  = 0
+pp_data->cap[90]->NotRange.Reserved2                    = 0
+pp_data->cap[90]->NotRange.DesignatorIndex              = 0
+pp_data->cap[90]->NotRange.Reserved3                    = 0
+pp_data->cap[90]->NotRange.DataIndex                    = 3
+pp_data->cap[90]->NotRange.Reserved4                    = 3
+pp_data->cap[90]->NotButton.HasNull                   = 0
+pp_data->cap[90]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[90]->NotButton.LogicalMin                = 0
+pp_data->cap[90]->NotButton.LogicalMax                = 127
+pp_data->cap[90]->NotButton.PhysicalMin               = 0
+pp_data->cap[90]->NotButton.PhysicalMax               = 0
+pp_data->cap[90]->Units                    = 0
+pp_data->cap[90]->UnitsExp                 = 0
+
+pp_data->cap[91]->UsagePage                    = 0xFF01
+pp_data->cap[91]->ReportID                     = 0x80
+pp_data->cap[91]->BitPosition                  = 0
+pp_data->cap[91]->BitSize                      = 8
+pp_data->cap[91]->ReportCount                  = 1
+pp_data->cap[91]->BytePosition                 = 0x005A
+pp_data->cap[91]->BitCount                     = 8
+pp_data->cap[91]->BitField                     = 0x02
+pp_data->cap[91]->NextBytePosition             = 0x005B
+pp_data->cap[91]->LinkCollection               = 0x0003
+pp_data->cap[91]->LinkUsagePage                = 0xFF01
+pp_data->cap[91]->LinkUsage                    = 0x0080
+pp_data->cap[91]->IsMultipleItemsForArray      = 0
+pp_data->cap[91]->IsButtonCap                  = 0
+pp_data->cap[91]->IsPadding                    = 0
+pp_data->cap[91]->IsAbsolute                   = 1
+pp_data->cap[91]->IsRange                      = 0
+pp_data->cap[91]->IsAlias                      = 0
+pp_data->cap[91]->IsStringRange                = 0
+pp_data->cap[91]->IsDesignatorRange            = 0
+pp_data->cap[91]->Reserved1                    = 0x000000
+pp_data->cap[91]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[91]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[91]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[91]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[91]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[91]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[91]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[91]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[91]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[91]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[91]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[91]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[91]->NotRange.Usage                        = 0x0081
+pp_data->cap[91]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[91]->NotRange.StringIndex                  = 0
+pp_data->cap[91]->NotRange.Reserved2                    = 0
+pp_data->cap[91]->NotRange.DesignatorIndex              = 0
+pp_data->cap[91]->NotRange.Reserved3                    = 0
+pp_data->cap[91]->NotRange.DataIndex                    = 4
+pp_data->cap[91]->NotRange.Reserved4                    = 4
+pp_data->cap[91]->NotButton.HasNull                   = 0
+pp_data->cap[91]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[91]->NotButton.LogicalMin                = 0
+pp_data->cap[91]->NotButton.LogicalMax                = 127
+pp_data->cap[91]->NotButton.PhysicalMin               = 0
+pp_data->cap[91]->NotButton.PhysicalMax               = 0
+pp_data->cap[91]->Units                    = 0
+pp_data->cap[91]->UnitsExp                 = 0
+
+pp_data->cap[92]->UsagePage                    = 0xFF01
+pp_data->cap[92]->ReportID                     = 0x80
+pp_data->cap[92]->BitPosition                  = 0
+pp_data->cap[92]->BitSize                      = 8
+pp_data->cap[92]->ReportCount                  = 1
+pp_data->cap[92]->BytePosition                 = 0x0059
+pp_data->cap[92]->BitCount                     = 8
+pp_data->cap[92]->BitField                     = 0x02
+pp_data->cap[92]->NextBytePosition             = 0x005A
+pp_data->cap[92]->LinkCollection               = 0x0003
+pp_data->cap[92]->LinkUsagePage                = 0xFF01
+pp_data->cap[92]->LinkUsage                    = 0x0080
+pp_data->cap[92]->IsMultipleItemsForArray      = 0
+pp_data->cap[92]->IsButtonCap                  = 0
+pp_data->cap[92]->IsPadding                    = 0
+pp_data->cap[92]->IsAbsolute                   = 1
+pp_data->cap[92]->IsRange                      = 0
+pp_data->cap[92]->IsAlias                      = 0
+pp_data->cap[92]->IsStringRange                = 0
+pp_data->cap[92]->IsDesignatorRange            = 0
+pp_data->cap[92]->Reserved1                    = 0x000000
+pp_data->cap[92]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[92]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[92]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[92]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[92]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[92]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[92]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[92]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[92]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[92]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[92]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[92]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[92]->NotRange.Usage                        = 0x0081
+pp_data->cap[92]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[92]->NotRange.StringIndex                  = 0
+pp_data->cap[92]->NotRange.Reserved2                    = 0
+pp_data->cap[92]->NotRange.DesignatorIndex              = 0
+pp_data->cap[92]->NotRange.Reserved3                    = 0
+pp_data->cap[92]->NotRange.DataIndex                    = 5
+pp_data->cap[92]->NotRange.Reserved4                    = 5
+pp_data->cap[92]->NotButton.HasNull                   = 0
+pp_data->cap[92]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[92]->NotButton.LogicalMin                = 0
+pp_data->cap[92]->NotButton.LogicalMax                = 127
+pp_data->cap[92]->NotButton.PhysicalMin               = 0
+pp_data->cap[92]->NotButton.PhysicalMax               = 0
+pp_data->cap[92]->Units                    = 0
+pp_data->cap[92]->UnitsExp                 = 0
+
+pp_data->cap[93]->UsagePage                    = 0xFF01
+pp_data->cap[93]->ReportID                     = 0x80
+pp_data->cap[93]->BitPosition                  = 0
+pp_data->cap[93]->BitSize                      = 8
+pp_data->cap[93]->ReportCount                  = 1
+pp_data->cap[93]->BytePosition                 = 0x0058
+pp_data->cap[93]->BitCount                     = 8
+pp_data->cap[93]->BitField                     = 0x02
+pp_data->cap[93]->NextBytePosition             = 0x0059
+pp_data->cap[93]->LinkCollection               = 0x0003
+pp_data->cap[93]->LinkUsagePage                = 0xFF01
+pp_data->cap[93]->LinkUsage                    = 0x0080
+pp_data->cap[93]->IsMultipleItemsForArray      = 0
+pp_data->cap[93]->IsButtonCap                  = 0
+pp_data->cap[93]->IsPadding                    = 0
+pp_data->cap[93]->IsAbsolute                   = 1
+pp_data->cap[93]->IsRange                      = 0
+pp_data->cap[93]->IsAlias                      = 0
+pp_data->cap[93]->IsStringRange                = 0
+pp_data->cap[93]->IsDesignatorRange            = 0
+pp_data->cap[93]->Reserved1                    = 0x000000
+pp_data->cap[93]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[93]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[93]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[93]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[93]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[93]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[93]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[93]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[93]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[93]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[93]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[93]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[93]->NotRange.Usage                        = 0x0081
+pp_data->cap[93]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[93]->NotRange.StringIndex                  = 0
+pp_data->cap[93]->NotRange.Reserved2                    = 0
+pp_data->cap[93]->NotRange.DesignatorIndex              = 0
+pp_data->cap[93]->NotRange.Reserved3                    = 0
+pp_data->cap[93]->NotRange.DataIndex                    = 6
+pp_data->cap[93]->NotRange.Reserved4                    = 6
+pp_data->cap[93]->NotButton.HasNull                   = 0
+pp_data->cap[93]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[93]->NotButton.LogicalMin                = 0
+pp_data->cap[93]->NotButton.LogicalMax                = 127
+pp_data->cap[93]->NotButton.PhysicalMin               = 0
+pp_data->cap[93]->NotButton.PhysicalMax               = 0
+pp_data->cap[93]->Units                    = 0
+pp_data->cap[93]->UnitsExp                 = 0
+
+pp_data->cap[94]->UsagePage                    = 0xFF01
+pp_data->cap[94]->ReportID                     = 0x80
+pp_data->cap[94]->BitPosition                  = 0
+pp_data->cap[94]->BitSize                      = 8
+pp_data->cap[94]->ReportCount                  = 1
+pp_data->cap[94]->BytePosition                 = 0x0057
+pp_data->cap[94]->BitCount                     = 8
+pp_data->cap[94]->BitField                     = 0x02
+pp_data->cap[94]->NextBytePosition             = 0x0058
+pp_data->cap[94]->LinkCollection               = 0x0003
+pp_data->cap[94]->LinkUsagePage                = 0xFF01
+pp_data->cap[94]->LinkUsage                    = 0x0080
+pp_data->cap[94]->IsMultipleItemsForArray      = 0
+pp_data->cap[94]->IsButtonCap                  = 0
+pp_data->cap[94]->IsPadding                    = 0
+pp_data->cap[94]->IsAbsolute                   = 1
+pp_data->cap[94]->IsRange                      = 0
+pp_data->cap[94]->IsAlias                      = 0
+pp_data->cap[94]->IsStringRange                = 0
+pp_data->cap[94]->IsDesignatorRange            = 0
+pp_data->cap[94]->Reserved1                    = 0x000000
+pp_data->cap[94]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[94]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[94]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[94]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[94]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[94]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[94]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[94]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[94]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[94]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[94]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[94]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[94]->NotRange.Usage                        = 0x0081
+pp_data->cap[94]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[94]->NotRange.StringIndex                  = 0
+pp_data->cap[94]->NotRange.Reserved2                    = 0
+pp_data->cap[94]->NotRange.DesignatorIndex              = 0
+pp_data->cap[94]->NotRange.Reserved3                    = 0
+pp_data->cap[94]->NotRange.DataIndex                    = 7
+pp_data->cap[94]->NotRange.Reserved4                    = 7
+pp_data->cap[94]->NotButton.HasNull                   = 0
+pp_data->cap[94]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[94]->NotButton.LogicalMin                = 0
+pp_data->cap[94]->NotButton.LogicalMax                = 127
+pp_data->cap[94]->NotButton.PhysicalMin               = 0
+pp_data->cap[94]->NotButton.PhysicalMax               = 0
+pp_data->cap[94]->Units                    = 0
+pp_data->cap[94]->UnitsExp                 = 0
+
+pp_data->cap[95]->UsagePage                    = 0xFF01
+pp_data->cap[95]->ReportID                     = 0x80
+pp_data->cap[95]->BitPosition                  = 0
+pp_data->cap[95]->BitSize                      = 8
+pp_data->cap[95]->ReportCount                  = 1
+pp_data->cap[95]->BytePosition                 = 0x0056
+pp_data->cap[95]->BitCount                     = 8
+pp_data->cap[95]->BitField                     = 0x02
+pp_data->cap[95]->NextBytePosition             = 0x0057
+pp_data->cap[95]->LinkCollection               = 0x0003
+pp_data->cap[95]->LinkUsagePage                = 0xFF01
+pp_data->cap[95]->LinkUsage                    = 0x0080
+pp_data->cap[95]->IsMultipleItemsForArray      = 0
+pp_data->cap[95]->IsButtonCap                  = 0
+pp_data->cap[95]->IsPadding                    = 0
+pp_data->cap[95]->IsAbsolute                   = 1
+pp_data->cap[95]->IsRange                      = 0
+pp_data->cap[95]->IsAlias                      = 0
+pp_data->cap[95]->IsStringRange                = 0
+pp_data->cap[95]->IsDesignatorRange            = 0
+pp_data->cap[95]->Reserved1                    = 0x000000
+pp_data->cap[95]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[95]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[95]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[95]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[95]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[95]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[95]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[95]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[95]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[95]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[95]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[95]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[95]->NotRange.Usage                        = 0x0081
+pp_data->cap[95]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[95]->NotRange.StringIndex                  = 0
+pp_data->cap[95]->NotRange.Reserved2                    = 0
+pp_data->cap[95]->NotRange.DesignatorIndex              = 0
+pp_data->cap[95]->NotRange.Reserved3                    = 0
+pp_data->cap[95]->NotRange.DataIndex                    = 8
+pp_data->cap[95]->NotRange.Reserved4                    = 8
+pp_data->cap[95]->NotButton.HasNull                   = 0
+pp_data->cap[95]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[95]->NotButton.LogicalMin                = 0
+pp_data->cap[95]->NotButton.LogicalMax                = 127
+pp_data->cap[95]->NotButton.PhysicalMin               = 0
+pp_data->cap[95]->NotButton.PhysicalMax               = 0
+pp_data->cap[95]->Units                    = 0
+pp_data->cap[95]->UnitsExp                 = 0
+
+pp_data->cap[96]->UsagePage                    = 0xFF01
+pp_data->cap[96]->ReportID                     = 0x80
+pp_data->cap[96]->BitPosition                  = 0
+pp_data->cap[96]->BitSize                      = 8
+pp_data->cap[96]->ReportCount                  = 1
+pp_data->cap[96]->BytePosition                 = 0x0055
+pp_data->cap[96]->BitCount                     = 8
+pp_data->cap[96]->BitField                     = 0x02
+pp_data->cap[96]->NextBytePosition             = 0x0056
+pp_data->cap[96]->LinkCollection               = 0x0003
+pp_data->cap[96]->LinkUsagePage                = 0xFF01
+pp_data->cap[96]->LinkUsage                    = 0x0080
+pp_data->cap[96]->IsMultipleItemsForArray      = 0
+pp_data->cap[96]->IsButtonCap                  = 0
+pp_data->cap[96]->IsPadding                    = 0
+pp_data->cap[96]->IsAbsolute                   = 1
+pp_data->cap[96]->IsRange                      = 0
+pp_data->cap[96]->IsAlias                      = 0
+pp_data->cap[96]->IsStringRange                = 0
+pp_data->cap[96]->IsDesignatorRange            = 0
+pp_data->cap[96]->Reserved1                    = 0x000000
+pp_data->cap[96]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[96]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[96]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[96]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[96]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[96]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[96]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[96]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[96]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[96]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[96]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[96]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[96]->NotRange.Usage                        = 0x0081
+pp_data->cap[96]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[96]->NotRange.StringIndex                  = 0
+pp_data->cap[96]->NotRange.Reserved2                    = 0
+pp_data->cap[96]->NotRange.DesignatorIndex              = 0
+pp_data->cap[96]->NotRange.Reserved3                    = 0
+pp_data->cap[96]->NotRange.DataIndex                    = 9
+pp_data->cap[96]->NotRange.Reserved4                    = 9
+pp_data->cap[96]->NotButton.HasNull                   = 0
+pp_data->cap[96]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[96]->NotButton.LogicalMin                = 0
+pp_data->cap[96]->NotButton.LogicalMax                = 127
+pp_data->cap[96]->NotButton.PhysicalMin               = 0
+pp_data->cap[96]->NotButton.PhysicalMax               = 0
+pp_data->cap[96]->Units                    = 0
+pp_data->cap[96]->UnitsExp                 = 0
+
+pp_data->cap[97]->UsagePage                    = 0xFF01
+pp_data->cap[97]->ReportID                     = 0x80
+pp_data->cap[97]->BitPosition                  = 0
+pp_data->cap[97]->BitSize                      = 8
+pp_data->cap[97]->ReportCount                  = 1
+pp_data->cap[97]->BytePosition                 = 0x0054
+pp_data->cap[97]->BitCount                     = 8
+pp_data->cap[97]->BitField                     = 0x02
+pp_data->cap[97]->NextBytePosition             = 0x0055
+pp_data->cap[97]->LinkCollection               = 0x0003
+pp_data->cap[97]->LinkUsagePage                = 0xFF01
+pp_data->cap[97]->LinkUsage                    = 0x0080
+pp_data->cap[97]->IsMultipleItemsForArray      = 0
+pp_data->cap[97]->IsButtonCap                  = 0
+pp_data->cap[97]->IsPadding                    = 0
+pp_data->cap[97]->IsAbsolute                   = 1
+pp_data->cap[97]->IsRange                      = 0
+pp_data->cap[97]->IsAlias                      = 0
+pp_data->cap[97]->IsStringRange                = 0
+pp_data->cap[97]->IsDesignatorRange            = 0
+pp_data->cap[97]->Reserved1                    = 0x000000
+pp_data->cap[97]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[97]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[97]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[97]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[97]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[97]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[97]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[97]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[97]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[97]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[97]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[97]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[97]->NotRange.Usage                        = 0x0081
+pp_data->cap[97]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[97]->NotRange.StringIndex                  = 0
+pp_data->cap[97]->NotRange.Reserved2                    = 0
+pp_data->cap[97]->NotRange.DesignatorIndex              = 0
+pp_data->cap[97]->NotRange.Reserved3                    = 0
+pp_data->cap[97]->NotRange.DataIndex                    = 10
+pp_data->cap[97]->NotRange.Reserved4                    = 10
+pp_data->cap[97]->NotButton.HasNull                   = 0
+pp_data->cap[97]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[97]->NotButton.LogicalMin                = 0
+pp_data->cap[97]->NotButton.LogicalMax                = 127
+pp_data->cap[97]->NotButton.PhysicalMin               = 0
+pp_data->cap[97]->NotButton.PhysicalMax               = 0
+pp_data->cap[97]->Units                    = 0
+pp_data->cap[97]->UnitsExp                 = 0
+
+pp_data->cap[98]->UsagePage                    = 0xFF01
+pp_data->cap[98]->ReportID                     = 0x80
+pp_data->cap[98]->BitPosition                  = 0
+pp_data->cap[98]->BitSize                      = 8
+pp_data->cap[98]->ReportCount                  = 1
+pp_data->cap[98]->BytePosition                 = 0x0053
+pp_data->cap[98]->BitCount                     = 8
+pp_data->cap[98]->BitField                     = 0x02
+pp_data->cap[98]->NextBytePosition             = 0x0054
+pp_data->cap[98]->LinkCollection               = 0x0003
+pp_data->cap[98]->LinkUsagePage                = 0xFF01
+pp_data->cap[98]->LinkUsage                    = 0x0080
+pp_data->cap[98]->IsMultipleItemsForArray      = 0
+pp_data->cap[98]->IsButtonCap                  = 0
+pp_data->cap[98]->IsPadding                    = 0
+pp_data->cap[98]->IsAbsolute                   = 1
+pp_data->cap[98]->IsRange                      = 0
+pp_data->cap[98]->IsAlias                      = 0
+pp_data->cap[98]->IsStringRange                = 0
+pp_data->cap[98]->IsDesignatorRange            = 0
+pp_data->cap[98]->Reserved1                    = 0x000000
+pp_data->cap[98]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[98]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[98]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[98]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[98]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[98]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[98]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[98]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[98]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[98]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[98]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[98]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[98]->NotRange.Usage                        = 0x0081
+pp_data->cap[98]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[98]->NotRange.StringIndex                  = 0
+pp_data->cap[98]->NotRange.Reserved2                    = 0
+pp_data->cap[98]->NotRange.DesignatorIndex              = 0
+pp_data->cap[98]->NotRange.Reserved3                    = 0
+pp_data->cap[98]->NotRange.DataIndex                    = 11
+pp_data->cap[98]->NotRange.Reserved4                    = 11
+pp_data->cap[98]->NotButton.HasNull                   = 0
+pp_data->cap[98]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[98]->NotButton.LogicalMin                = 0
+pp_data->cap[98]->NotButton.LogicalMax                = 127
+pp_data->cap[98]->NotButton.PhysicalMin               = 0
+pp_data->cap[98]->NotButton.PhysicalMax               = 0
+pp_data->cap[98]->Units                    = 0
+pp_data->cap[98]->UnitsExp                 = 0
+
+pp_data->cap[99]->UsagePage                    = 0xFF01
+pp_data->cap[99]->ReportID                     = 0x80
+pp_data->cap[99]->BitPosition                  = 0
+pp_data->cap[99]->BitSize                      = 8
+pp_data->cap[99]->ReportCount                  = 1
+pp_data->cap[99]->BytePosition                 = 0x0052
+pp_data->cap[99]->BitCount                     = 8
+pp_data->cap[99]->BitField                     = 0x02
+pp_data->cap[99]->NextBytePosition             = 0x0053
+pp_data->cap[99]->LinkCollection               = 0x0003
+pp_data->cap[99]->LinkUsagePage                = 0xFF01
+pp_data->cap[99]->LinkUsage                    = 0x0080
+pp_data->cap[99]->IsMultipleItemsForArray      = 0
+pp_data->cap[99]->IsButtonCap                  = 0
+pp_data->cap[99]->IsPadding                    = 0
+pp_data->cap[99]->IsAbsolute                   = 1
+pp_data->cap[99]->IsRange                      = 0
+pp_data->cap[99]->IsAlias                      = 0
+pp_data->cap[99]->IsStringRange                = 0
+pp_data->cap[99]->IsDesignatorRange            = 0
+pp_data->cap[99]->Reserved1                    = 0x000000
+pp_data->cap[99]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[99]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[99]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[99]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[99]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[99]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[99]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[99]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[99]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[99]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[99]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[99]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[99]->NotRange.Usage                        = 0x0081
+pp_data->cap[99]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[99]->NotRange.StringIndex                  = 0
+pp_data->cap[99]->NotRange.Reserved2                    = 0
+pp_data->cap[99]->NotRange.DesignatorIndex              = 0
+pp_data->cap[99]->NotRange.Reserved3                    = 0
+pp_data->cap[99]->NotRange.DataIndex                    = 12
+pp_data->cap[99]->NotRange.Reserved4                    = 12
+pp_data->cap[99]->NotButton.HasNull                   = 0
+pp_data->cap[99]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[99]->NotButton.LogicalMin                = 0
+pp_data->cap[99]->NotButton.LogicalMax                = 127
+pp_data->cap[99]->NotButton.PhysicalMin               = 0
+pp_data->cap[99]->NotButton.PhysicalMax               = 0
+pp_data->cap[99]->Units                    = 0
+pp_data->cap[99]->UnitsExp                 = 0
+
+pp_data->cap[100]->UsagePage                    = 0xFF01
+pp_data->cap[100]->ReportID                     = 0x80
+pp_data->cap[100]->BitPosition                  = 0
+pp_data->cap[100]->BitSize                      = 8
+pp_data->cap[100]->ReportCount                  = 1
+pp_data->cap[100]->BytePosition                 = 0x0051
+pp_data->cap[100]->BitCount                     = 8
+pp_data->cap[100]->BitField                     = 0x02
+pp_data->cap[100]->NextBytePosition             = 0x0052
+pp_data->cap[100]->LinkCollection               = 0x0003
+pp_data->cap[100]->LinkUsagePage                = 0xFF01
+pp_data->cap[100]->LinkUsage                    = 0x0080
+pp_data->cap[100]->IsMultipleItemsForArray      = 0
+pp_data->cap[100]->IsButtonCap                  = 0
+pp_data->cap[100]->IsPadding                    = 0
+pp_data->cap[100]->IsAbsolute                   = 1
+pp_data->cap[100]->IsRange                      = 0
+pp_data->cap[100]->IsAlias                      = 0
+pp_data->cap[100]->IsStringRange                = 0
+pp_data->cap[100]->IsDesignatorRange            = 0
+pp_data->cap[100]->Reserved1                    = 0x000000
+pp_data->cap[100]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[100]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[100]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[100]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[100]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[100]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[100]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[100]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[100]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[100]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[100]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[100]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[100]->NotRange.Usage                        = 0x0081
+pp_data->cap[100]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[100]->NotRange.StringIndex                  = 0
+pp_data->cap[100]->NotRange.Reserved2                    = 0
+pp_data->cap[100]->NotRange.DesignatorIndex              = 0
+pp_data->cap[100]->NotRange.Reserved3                    = 0
+pp_data->cap[100]->NotRange.DataIndex                    = 13
+pp_data->cap[100]->NotRange.Reserved4                    = 13
+pp_data->cap[100]->NotButton.HasNull                   = 0
+pp_data->cap[100]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[100]->NotButton.LogicalMin                = 0
+pp_data->cap[100]->NotButton.LogicalMax                = 127
+pp_data->cap[100]->NotButton.PhysicalMin               = 0
+pp_data->cap[100]->NotButton.PhysicalMax               = 0
+pp_data->cap[100]->Units                    = 0
+pp_data->cap[100]->UnitsExp                 = 0
+
+pp_data->cap[101]->UsagePage                    = 0xFF01
+pp_data->cap[101]->ReportID                     = 0x80
+pp_data->cap[101]->BitPosition                  = 0
+pp_data->cap[101]->BitSize                      = 8
+pp_data->cap[101]->ReportCount                  = 1
+pp_data->cap[101]->BytePosition                 = 0x0050
+pp_data->cap[101]->BitCount                     = 8
+pp_data->cap[101]->BitField                     = 0x02
+pp_data->cap[101]->NextBytePosition             = 0x0051
+pp_data->cap[101]->LinkCollection               = 0x0003
+pp_data->cap[101]->LinkUsagePage                = 0xFF01
+pp_data->cap[101]->LinkUsage                    = 0x0080
+pp_data->cap[101]->IsMultipleItemsForArray      = 0
+pp_data->cap[101]->IsButtonCap                  = 0
+pp_data->cap[101]->IsPadding                    = 0
+pp_data->cap[101]->IsAbsolute                   = 1
+pp_data->cap[101]->IsRange                      = 0
+pp_data->cap[101]->IsAlias                      = 0
+pp_data->cap[101]->IsStringRange                = 0
+pp_data->cap[101]->IsDesignatorRange            = 0
+pp_data->cap[101]->Reserved1                    = 0x000000
+pp_data->cap[101]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[101]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[101]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[101]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[101]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[101]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[101]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[101]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[101]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[101]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[101]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[101]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[101]->NotRange.Usage                        = 0x0081
+pp_data->cap[101]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[101]->NotRange.StringIndex                  = 0
+pp_data->cap[101]->NotRange.Reserved2                    = 0
+pp_data->cap[101]->NotRange.DesignatorIndex              = 0
+pp_data->cap[101]->NotRange.Reserved3                    = 0
+pp_data->cap[101]->NotRange.DataIndex                    = 14
+pp_data->cap[101]->NotRange.Reserved4                    = 14
+pp_data->cap[101]->NotButton.HasNull                   = 0
+pp_data->cap[101]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[101]->NotButton.LogicalMin                = 0
+pp_data->cap[101]->NotButton.LogicalMax                = 127
+pp_data->cap[101]->NotButton.PhysicalMin               = 0
+pp_data->cap[101]->NotButton.PhysicalMax               = 0
+pp_data->cap[101]->Units                    = 0
+pp_data->cap[101]->UnitsExp                 = 0
+
+pp_data->cap[102]->UsagePage                    = 0xFF01
+pp_data->cap[102]->ReportID                     = 0x80
+pp_data->cap[102]->BitPosition                  = 0
+pp_data->cap[102]->BitSize                      = 8
+pp_data->cap[102]->ReportCount                  = 1
+pp_data->cap[102]->BytePosition                 = 0x004F
+pp_data->cap[102]->BitCount                     = 8
+pp_data->cap[102]->BitField                     = 0x02
+pp_data->cap[102]->NextBytePosition             = 0x0050
+pp_data->cap[102]->LinkCollection               = 0x0003
+pp_data->cap[102]->LinkUsagePage                = 0xFF01
+pp_data->cap[102]->LinkUsage                    = 0x0080
+pp_data->cap[102]->IsMultipleItemsForArray      = 0
+pp_data->cap[102]->IsButtonCap                  = 0
+pp_data->cap[102]->IsPadding                    = 0
+pp_data->cap[102]->IsAbsolute                   = 1
+pp_data->cap[102]->IsRange                      = 0
+pp_data->cap[102]->IsAlias                      = 0
+pp_data->cap[102]->IsStringRange                = 0
+pp_data->cap[102]->IsDesignatorRange            = 0
+pp_data->cap[102]->Reserved1                    = 0x000000
+pp_data->cap[102]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[102]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[102]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[102]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[102]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[102]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[102]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[102]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[102]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[102]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[102]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[102]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[102]->NotRange.Usage                        = 0x0081
+pp_data->cap[102]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[102]->NotRange.StringIndex                  = 0
+pp_data->cap[102]->NotRange.Reserved2                    = 0
+pp_data->cap[102]->NotRange.DesignatorIndex              = 0
+pp_data->cap[102]->NotRange.Reserved3                    = 0
+pp_data->cap[102]->NotRange.DataIndex                    = 15
+pp_data->cap[102]->NotRange.Reserved4                    = 15
+pp_data->cap[102]->NotButton.HasNull                   = 0
+pp_data->cap[102]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[102]->NotButton.LogicalMin                = 0
+pp_data->cap[102]->NotButton.LogicalMax                = 127
+pp_data->cap[102]->NotButton.PhysicalMin               = 0
+pp_data->cap[102]->NotButton.PhysicalMax               = 0
+pp_data->cap[102]->Units                    = 0
+pp_data->cap[102]->UnitsExp                 = 0
+
+pp_data->cap[103]->UsagePage                    = 0xFF01
+pp_data->cap[103]->ReportID                     = 0x80
+pp_data->cap[103]->BitPosition                  = 0
+pp_data->cap[103]->BitSize                      = 8
+pp_data->cap[103]->ReportCount                  = 1
+pp_data->cap[103]->BytePosition                 = 0x004E
+pp_data->cap[103]->BitCount                     = 8
+pp_data->cap[103]->BitField                     = 0x02
+pp_data->cap[103]->NextBytePosition             = 0x004F
+pp_data->cap[103]->LinkCollection               = 0x0003
+pp_data->cap[103]->LinkUsagePage                = 0xFF01
+pp_data->cap[103]->LinkUsage                    = 0x0080
+pp_data->cap[103]->IsMultipleItemsForArray      = 0
+pp_data->cap[103]->IsButtonCap                  = 0
+pp_data->cap[103]->IsPadding                    = 0
+pp_data->cap[103]->IsAbsolute                   = 1
+pp_data->cap[103]->IsRange                      = 0
+pp_data->cap[103]->IsAlias                      = 0
+pp_data->cap[103]->IsStringRange                = 0
+pp_data->cap[103]->IsDesignatorRange            = 0
+pp_data->cap[103]->Reserved1                    = 0x000000
+pp_data->cap[103]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[103]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[103]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[103]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[103]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[103]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[103]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[103]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[103]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[103]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[103]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[103]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[103]->NotRange.Usage                        = 0x0081
+pp_data->cap[103]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[103]->NotRange.StringIndex                  = 0
+pp_data->cap[103]->NotRange.Reserved2                    = 0
+pp_data->cap[103]->NotRange.DesignatorIndex              = 0
+pp_data->cap[103]->NotRange.Reserved3                    = 0
+pp_data->cap[103]->NotRange.DataIndex                    = 16
+pp_data->cap[103]->NotRange.Reserved4                    = 16
+pp_data->cap[103]->NotButton.HasNull                   = 0
+pp_data->cap[103]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[103]->NotButton.LogicalMin                = 0
+pp_data->cap[103]->NotButton.LogicalMax                = 127
+pp_data->cap[103]->NotButton.PhysicalMin               = 0
+pp_data->cap[103]->NotButton.PhysicalMax               = 0
+pp_data->cap[103]->Units                    = 0
+pp_data->cap[103]->UnitsExp                 = 0
+
+pp_data->cap[104]->UsagePage                    = 0xFF01
+pp_data->cap[104]->ReportID                     = 0x80
+pp_data->cap[104]->BitPosition                  = 0
+pp_data->cap[104]->BitSize                      = 8
+pp_data->cap[104]->ReportCount                  = 1
+pp_data->cap[104]->BytePosition                 = 0x004D
+pp_data->cap[104]->BitCount                     = 8
+pp_data->cap[104]->BitField                     = 0x02
+pp_data->cap[104]->NextBytePosition             = 0x004E
+pp_data->cap[104]->LinkCollection               = 0x0003
+pp_data->cap[104]->LinkUsagePage                = 0xFF01
+pp_data->cap[104]->LinkUsage                    = 0x0080
+pp_data->cap[104]->IsMultipleItemsForArray      = 0
+pp_data->cap[104]->IsButtonCap                  = 0
+pp_data->cap[104]->IsPadding                    = 0
+pp_data->cap[104]->IsAbsolute                   = 1
+pp_data->cap[104]->IsRange                      = 0
+pp_data->cap[104]->IsAlias                      = 0
+pp_data->cap[104]->IsStringRange                = 0
+pp_data->cap[104]->IsDesignatorRange            = 0
+pp_data->cap[104]->Reserved1                    = 0x000000
+pp_data->cap[104]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[104]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[104]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[104]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[104]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[104]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[104]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[104]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[104]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[104]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[104]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[104]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[104]->NotRange.Usage                        = 0x0081
+pp_data->cap[104]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[104]->NotRange.StringIndex                  = 0
+pp_data->cap[104]->NotRange.Reserved2                    = 0
+pp_data->cap[104]->NotRange.DesignatorIndex              = 0
+pp_data->cap[104]->NotRange.Reserved3                    = 0
+pp_data->cap[104]->NotRange.DataIndex                    = 17
+pp_data->cap[104]->NotRange.Reserved4                    = 17
+pp_data->cap[104]->NotButton.HasNull                   = 0
+pp_data->cap[104]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[104]->NotButton.LogicalMin                = 0
+pp_data->cap[104]->NotButton.LogicalMax                = 127
+pp_data->cap[104]->NotButton.PhysicalMin               = 0
+pp_data->cap[104]->NotButton.PhysicalMax               = 0
+pp_data->cap[104]->Units                    = 0
+pp_data->cap[104]->UnitsExp                 = 0
+
+pp_data->cap[105]->UsagePage                    = 0xFF01
+pp_data->cap[105]->ReportID                     = 0x80
+pp_data->cap[105]->BitPosition                  = 0
+pp_data->cap[105]->BitSize                      = 8
+pp_data->cap[105]->ReportCount                  = 1
+pp_data->cap[105]->BytePosition                 = 0x004C
+pp_data->cap[105]->BitCount                     = 8
+pp_data->cap[105]->BitField                     = 0x02
+pp_data->cap[105]->NextBytePosition             = 0x004D
+pp_data->cap[105]->LinkCollection               = 0x0003
+pp_data->cap[105]->LinkUsagePage                = 0xFF01
+pp_data->cap[105]->LinkUsage                    = 0x0080
+pp_data->cap[105]->IsMultipleItemsForArray      = 0
+pp_data->cap[105]->IsButtonCap                  = 0
+pp_data->cap[105]->IsPadding                    = 0
+pp_data->cap[105]->IsAbsolute                   = 1
+pp_data->cap[105]->IsRange                      = 0
+pp_data->cap[105]->IsAlias                      = 0
+pp_data->cap[105]->IsStringRange                = 0
+pp_data->cap[105]->IsDesignatorRange            = 0
+pp_data->cap[105]->Reserved1                    = 0x000000
+pp_data->cap[105]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[105]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[105]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[105]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[105]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[105]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[105]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[105]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[105]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[105]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[105]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[105]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[105]->NotRange.Usage                        = 0x0081
+pp_data->cap[105]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[105]->NotRange.StringIndex                  = 0
+pp_data->cap[105]->NotRange.Reserved2                    = 0
+pp_data->cap[105]->NotRange.DesignatorIndex              = 0
+pp_data->cap[105]->NotRange.Reserved3                    = 0
+pp_data->cap[105]->NotRange.DataIndex                    = 18
+pp_data->cap[105]->NotRange.Reserved4                    = 18
+pp_data->cap[105]->NotButton.HasNull                   = 0
+pp_data->cap[105]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[105]->NotButton.LogicalMin                = 0
+pp_data->cap[105]->NotButton.LogicalMax                = 127
+pp_data->cap[105]->NotButton.PhysicalMin               = 0
+pp_data->cap[105]->NotButton.PhysicalMax               = 0
+pp_data->cap[105]->Units                    = 0
+pp_data->cap[105]->UnitsExp                 = 0
+
+pp_data->cap[106]->UsagePage                    = 0xFF01
+pp_data->cap[106]->ReportID                     = 0x80
+pp_data->cap[106]->BitPosition                  = 0
+pp_data->cap[106]->BitSize                      = 8
+pp_data->cap[106]->ReportCount                  = 1
+pp_data->cap[106]->BytePosition                 = 0x004B
+pp_data->cap[106]->BitCount                     = 8
+pp_data->cap[106]->BitField                     = 0x02
+pp_data->cap[106]->NextBytePosition             = 0x004C
+pp_data->cap[106]->LinkCollection               = 0x0003
+pp_data->cap[106]->LinkUsagePage                = 0xFF01
+pp_data->cap[106]->LinkUsage                    = 0x0080
+pp_data->cap[106]->IsMultipleItemsForArray      = 0
+pp_data->cap[106]->IsButtonCap                  = 0
+pp_data->cap[106]->IsPadding                    = 0
+pp_data->cap[106]->IsAbsolute                   = 1
+pp_data->cap[106]->IsRange                      = 0
+pp_data->cap[106]->IsAlias                      = 0
+pp_data->cap[106]->IsStringRange                = 0
+pp_data->cap[106]->IsDesignatorRange            = 0
+pp_data->cap[106]->Reserved1                    = 0x000000
+pp_data->cap[106]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[106]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[106]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[106]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[106]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[106]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[106]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[106]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[106]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[106]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[106]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[106]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[106]->NotRange.Usage                        = 0x0081
+pp_data->cap[106]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[106]->NotRange.StringIndex                  = 0
+pp_data->cap[106]->NotRange.Reserved2                    = 0
+pp_data->cap[106]->NotRange.DesignatorIndex              = 0
+pp_data->cap[106]->NotRange.Reserved3                    = 0
+pp_data->cap[106]->NotRange.DataIndex                    = 19
+pp_data->cap[106]->NotRange.Reserved4                    = 19
+pp_data->cap[106]->NotButton.HasNull                   = 0
+pp_data->cap[106]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[106]->NotButton.LogicalMin                = 0
+pp_data->cap[106]->NotButton.LogicalMax                = 127
+pp_data->cap[106]->NotButton.PhysicalMin               = 0
+pp_data->cap[106]->NotButton.PhysicalMax               = 0
+pp_data->cap[106]->Units                    = 0
+pp_data->cap[106]->UnitsExp                 = 0
+
+pp_data->cap[107]->UsagePage                    = 0xFF01
+pp_data->cap[107]->ReportID                     = 0x80
+pp_data->cap[107]->BitPosition                  = 0
+pp_data->cap[107]->BitSize                      = 8
+pp_data->cap[107]->ReportCount                  = 1
+pp_data->cap[107]->BytePosition                 = 0x004A
+pp_data->cap[107]->BitCount                     = 8
+pp_data->cap[107]->BitField                     = 0x02
+pp_data->cap[107]->NextBytePosition             = 0x004B
+pp_data->cap[107]->LinkCollection               = 0x0003
+pp_data->cap[107]->LinkUsagePage                = 0xFF01
+pp_data->cap[107]->LinkUsage                    = 0x0080
+pp_data->cap[107]->IsMultipleItemsForArray      = 0
+pp_data->cap[107]->IsButtonCap                  = 0
+pp_data->cap[107]->IsPadding                    = 0
+pp_data->cap[107]->IsAbsolute                   = 1
+pp_data->cap[107]->IsRange                      = 0
+pp_data->cap[107]->IsAlias                      = 0
+pp_data->cap[107]->IsStringRange                = 0
+pp_data->cap[107]->IsDesignatorRange            = 0
+pp_data->cap[107]->Reserved1                    = 0x000000
+pp_data->cap[107]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[107]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[107]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[107]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[107]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[107]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[107]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[107]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[107]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[107]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[107]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[107]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[107]->NotRange.Usage                        = 0x0081
+pp_data->cap[107]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[107]->NotRange.StringIndex                  = 0
+pp_data->cap[107]->NotRange.Reserved2                    = 0
+pp_data->cap[107]->NotRange.DesignatorIndex              = 0
+pp_data->cap[107]->NotRange.Reserved3                    = 0
+pp_data->cap[107]->NotRange.DataIndex                    = 20
+pp_data->cap[107]->NotRange.Reserved4                    = 20
+pp_data->cap[107]->NotButton.HasNull                   = 0
+pp_data->cap[107]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[107]->NotButton.LogicalMin                = 0
+pp_data->cap[107]->NotButton.LogicalMax                = 127
+pp_data->cap[107]->NotButton.PhysicalMin               = 0
+pp_data->cap[107]->NotButton.PhysicalMax               = 0
+pp_data->cap[107]->Units                    = 0
+pp_data->cap[107]->UnitsExp                 = 0
+
+pp_data->cap[108]->UsagePage                    = 0xFF01
+pp_data->cap[108]->ReportID                     = 0x80
+pp_data->cap[108]->BitPosition                  = 0
+pp_data->cap[108]->BitSize                      = 8
+pp_data->cap[108]->ReportCount                  = 1
+pp_data->cap[108]->BytePosition                 = 0x0049
+pp_data->cap[108]->BitCount                     = 8
+pp_data->cap[108]->BitField                     = 0x02
+pp_data->cap[108]->NextBytePosition             = 0x004A
+pp_data->cap[108]->LinkCollection               = 0x0003
+pp_data->cap[108]->LinkUsagePage                = 0xFF01
+pp_data->cap[108]->LinkUsage                    = 0x0080
+pp_data->cap[108]->IsMultipleItemsForArray      = 0
+pp_data->cap[108]->IsButtonCap                  = 0
+pp_data->cap[108]->IsPadding                    = 0
+pp_data->cap[108]->IsAbsolute                   = 1
+pp_data->cap[108]->IsRange                      = 0
+pp_data->cap[108]->IsAlias                      = 0
+pp_data->cap[108]->IsStringRange                = 0
+pp_data->cap[108]->IsDesignatorRange            = 0
+pp_data->cap[108]->Reserved1                    = 0x000000
+pp_data->cap[108]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[108]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[108]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[108]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[108]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[108]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[108]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[108]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[108]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[108]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[108]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[108]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[108]->NotRange.Usage                        = 0x0081
+pp_data->cap[108]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[108]->NotRange.StringIndex                  = 0
+pp_data->cap[108]->NotRange.Reserved2                    = 0
+pp_data->cap[108]->NotRange.DesignatorIndex              = 0
+pp_data->cap[108]->NotRange.Reserved3                    = 0
+pp_data->cap[108]->NotRange.DataIndex                    = 21
+pp_data->cap[108]->NotRange.Reserved4                    = 21
+pp_data->cap[108]->NotButton.HasNull                   = 0
+pp_data->cap[108]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[108]->NotButton.LogicalMin                = 0
+pp_data->cap[108]->NotButton.LogicalMax                = 127
+pp_data->cap[108]->NotButton.PhysicalMin               = 0
+pp_data->cap[108]->NotButton.PhysicalMax               = 0
+pp_data->cap[108]->Units                    = 0
+pp_data->cap[108]->UnitsExp                 = 0
+
+pp_data->cap[109]->UsagePage                    = 0xFF01
+pp_data->cap[109]->ReportID                     = 0x80
+pp_data->cap[109]->BitPosition                  = 0
+pp_data->cap[109]->BitSize                      = 8
+pp_data->cap[109]->ReportCount                  = 1
+pp_data->cap[109]->BytePosition                 = 0x0048
+pp_data->cap[109]->BitCount                     = 8
+pp_data->cap[109]->BitField                     = 0x02
+pp_data->cap[109]->NextBytePosition             = 0x0049
+pp_data->cap[109]->LinkCollection               = 0x0003
+pp_data->cap[109]->LinkUsagePage                = 0xFF01
+pp_data->cap[109]->LinkUsage                    = 0x0080
+pp_data->cap[109]->IsMultipleItemsForArray      = 0
+pp_data->cap[109]->IsButtonCap                  = 0
+pp_data->cap[109]->IsPadding                    = 0
+pp_data->cap[109]->IsAbsolute                   = 1
+pp_data->cap[109]->IsRange                      = 0
+pp_data->cap[109]->IsAlias                      = 0
+pp_data->cap[109]->IsStringRange                = 0
+pp_data->cap[109]->IsDesignatorRange            = 0
+pp_data->cap[109]->Reserved1                    = 0x000000
+pp_data->cap[109]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[109]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[109]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[109]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[109]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[109]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[109]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[109]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[109]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[109]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[109]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[109]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[109]->NotRange.Usage                        = 0x0081
+pp_data->cap[109]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[109]->NotRange.StringIndex                  = 0
+pp_data->cap[109]->NotRange.Reserved2                    = 0
+pp_data->cap[109]->NotRange.DesignatorIndex              = 0
+pp_data->cap[109]->NotRange.Reserved3                    = 0
+pp_data->cap[109]->NotRange.DataIndex                    = 22
+pp_data->cap[109]->NotRange.Reserved4                    = 22
+pp_data->cap[109]->NotButton.HasNull                   = 0
+pp_data->cap[109]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[109]->NotButton.LogicalMin                = 0
+pp_data->cap[109]->NotButton.LogicalMax                = 127
+pp_data->cap[109]->NotButton.PhysicalMin               = 0
+pp_data->cap[109]->NotButton.PhysicalMax               = 0
+pp_data->cap[109]->Units                    = 0
+pp_data->cap[109]->UnitsExp                 = 0
+
+pp_data->cap[110]->UsagePage                    = 0xFF01
+pp_data->cap[110]->ReportID                     = 0x80
+pp_data->cap[110]->BitPosition                  = 0
+pp_data->cap[110]->BitSize                      = 8
+pp_data->cap[110]->ReportCount                  = 1
+pp_data->cap[110]->BytePosition                 = 0x0047
+pp_data->cap[110]->BitCount                     = 8
+pp_data->cap[110]->BitField                     = 0x02
+pp_data->cap[110]->NextBytePosition             = 0x0048
+pp_data->cap[110]->LinkCollection               = 0x0003
+pp_data->cap[110]->LinkUsagePage                = 0xFF01
+pp_data->cap[110]->LinkUsage                    = 0x0080
+pp_data->cap[110]->IsMultipleItemsForArray      = 0
+pp_data->cap[110]->IsButtonCap                  = 0
+pp_data->cap[110]->IsPadding                    = 0
+pp_data->cap[110]->IsAbsolute                   = 1
+pp_data->cap[110]->IsRange                      = 0
+pp_data->cap[110]->IsAlias                      = 0
+pp_data->cap[110]->IsStringRange                = 0
+pp_data->cap[110]->IsDesignatorRange            = 0
+pp_data->cap[110]->Reserved1                    = 0x000000
+pp_data->cap[110]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[110]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[110]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[110]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[110]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[110]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[110]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[110]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[110]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[110]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[110]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[110]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[110]->NotRange.Usage                        = 0x0081
+pp_data->cap[110]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[110]->NotRange.StringIndex                  = 0
+pp_data->cap[110]->NotRange.Reserved2                    = 0
+pp_data->cap[110]->NotRange.DesignatorIndex              = 0
+pp_data->cap[110]->NotRange.Reserved3                    = 0
+pp_data->cap[110]->NotRange.DataIndex                    = 23
+pp_data->cap[110]->NotRange.Reserved4                    = 23
+pp_data->cap[110]->NotButton.HasNull                   = 0
+pp_data->cap[110]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[110]->NotButton.LogicalMin                = 0
+pp_data->cap[110]->NotButton.LogicalMax                = 127
+pp_data->cap[110]->NotButton.PhysicalMin               = 0
+pp_data->cap[110]->NotButton.PhysicalMax               = 0
+pp_data->cap[110]->Units                    = 0
+pp_data->cap[110]->UnitsExp                 = 0
+
+pp_data->cap[111]->UsagePage                    = 0xFF01
+pp_data->cap[111]->ReportID                     = 0x80
+pp_data->cap[111]->BitPosition                  = 0
+pp_data->cap[111]->BitSize                      = 8
+pp_data->cap[111]->ReportCount                  = 1
+pp_data->cap[111]->BytePosition                 = 0x0046
+pp_data->cap[111]->BitCount                     = 8
+pp_data->cap[111]->BitField                     = 0x02
+pp_data->cap[111]->NextBytePosition             = 0x0047
+pp_data->cap[111]->LinkCollection               = 0x0003
+pp_data->cap[111]->LinkUsagePage                = 0xFF01
+pp_data->cap[111]->LinkUsage                    = 0x0080
+pp_data->cap[111]->IsMultipleItemsForArray      = 0
+pp_data->cap[111]->IsButtonCap                  = 0
+pp_data->cap[111]->IsPadding                    = 0
+pp_data->cap[111]->IsAbsolute                   = 1
+pp_data->cap[111]->IsRange                      = 0
+pp_data->cap[111]->IsAlias                      = 0
+pp_data->cap[111]->IsStringRange                = 0
+pp_data->cap[111]->IsDesignatorRange            = 0
+pp_data->cap[111]->Reserved1                    = 0x000000
+pp_data->cap[111]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[111]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[111]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[111]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[111]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[111]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[111]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[111]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[111]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[111]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[111]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[111]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[111]->NotRange.Usage                        = 0x0081
+pp_data->cap[111]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[111]->NotRange.StringIndex                  = 0
+pp_data->cap[111]->NotRange.Reserved2                    = 0
+pp_data->cap[111]->NotRange.DesignatorIndex              = 0
+pp_data->cap[111]->NotRange.Reserved3                    = 0
+pp_data->cap[111]->NotRange.DataIndex                    = 24
+pp_data->cap[111]->NotRange.Reserved4                    = 24
+pp_data->cap[111]->NotButton.HasNull                   = 0
+pp_data->cap[111]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[111]->NotButton.LogicalMin                = 0
+pp_data->cap[111]->NotButton.LogicalMax                = 127
+pp_data->cap[111]->NotButton.PhysicalMin               = 0
+pp_data->cap[111]->NotButton.PhysicalMax               = 0
+pp_data->cap[111]->Units                    = 0
+pp_data->cap[111]->UnitsExp                 = 0
+
+pp_data->cap[112]->UsagePage                    = 0xFF01
+pp_data->cap[112]->ReportID                     = 0x80
+pp_data->cap[112]->BitPosition                  = 0
+pp_data->cap[112]->BitSize                      = 8
+pp_data->cap[112]->ReportCount                  = 1
+pp_data->cap[112]->BytePosition                 = 0x0045
+pp_data->cap[112]->BitCount                     = 8
+pp_data->cap[112]->BitField                     = 0x02
+pp_data->cap[112]->NextBytePosition             = 0x0046
+pp_data->cap[112]->LinkCollection               = 0x0003
+pp_data->cap[112]->LinkUsagePage                = 0xFF01
+pp_data->cap[112]->LinkUsage                    = 0x0080
+pp_data->cap[112]->IsMultipleItemsForArray      = 0
+pp_data->cap[112]->IsButtonCap                  = 0
+pp_data->cap[112]->IsPadding                    = 0
+pp_data->cap[112]->IsAbsolute                   = 1
+pp_data->cap[112]->IsRange                      = 0
+pp_data->cap[112]->IsAlias                      = 0
+pp_data->cap[112]->IsStringRange                = 0
+pp_data->cap[112]->IsDesignatorRange            = 0
+pp_data->cap[112]->Reserved1                    = 0x000000
+pp_data->cap[112]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[112]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[112]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[112]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[112]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[112]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[112]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[112]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[112]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[112]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[112]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[112]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[112]->NotRange.Usage                        = 0x0081
+pp_data->cap[112]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[112]->NotRange.StringIndex                  = 0
+pp_data->cap[112]->NotRange.Reserved2                    = 0
+pp_data->cap[112]->NotRange.DesignatorIndex              = 0
+pp_data->cap[112]->NotRange.Reserved3                    = 0
+pp_data->cap[112]->NotRange.DataIndex                    = 25
+pp_data->cap[112]->NotRange.Reserved4                    = 25
+pp_data->cap[112]->NotButton.HasNull                   = 0
+pp_data->cap[112]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[112]->NotButton.LogicalMin                = 0
+pp_data->cap[112]->NotButton.LogicalMax                = 127
+pp_data->cap[112]->NotButton.PhysicalMin               = 0
+pp_data->cap[112]->NotButton.PhysicalMax               = 0
+pp_data->cap[112]->Units                    = 0
+pp_data->cap[112]->UnitsExp                 = 0
+
+pp_data->cap[113]->UsagePage                    = 0xFF01
+pp_data->cap[113]->ReportID                     = 0x80
+pp_data->cap[113]->BitPosition                  = 0
+pp_data->cap[113]->BitSize                      = 8
+pp_data->cap[113]->ReportCount                  = 1
+pp_data->cap[113]->BytePosition                 = 0x0044
+pp_data->cap[113]->BitCount                     = 8
+pp_data->cap[113]->BitField                     = 0x02
+pp_data->cap[113]->NextBytePosition             = 0x0045
+pp_data->cap[113]->LinkCollection               = 0x0003
+pp_data->cap[113]->LinkUsagePage                = 0xFF01
+pp_data->cap[113]->LinkUsage                    = 0x0080
+pp_data->cap[113]->IsMultipleItemsForArray      = 0
+pp_data->cap[113]->IsButtonCap                  = 0
+pp_data->cap[113]->IsPadding                    = 0
+pp_data->cap[113]->IsAbsolute                   = 1
+pp_data->cap[113]->IsRange                      = 0
+pp_data->cap[113]->IsAlias                      = 0
+pp_data->cap[113]->IsStringRange                = 0
+pp_data->cap[113]->IsDesignatorRange            = 0
+pp_data->cap[113]->Reserved1                    = 0x000000
+pp_data->cap[113]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[113]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[113]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[113]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[113]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[113]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[113]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[113]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[113]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[113]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[113]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[113]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[113]->NotRange.Usage                        = 0x0081
+pp_data->cap[113]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[113]->NotRange.StringIndex                  = 0
+pp_data->cap[113]->NotRange.Reserved2                    = 0
+pp_data->cap[113]->NotRange.DesignatorIndex              = 0
+pp_data->cap[113]->NotRange.Reserved3                    = 0
+pp_data->cap[113]->NotRange.DataIndex                    = 26
+pp_data->cap[113]->NotRange.Reserved4                    = 26
+pp_data->cap[113]->NotButton.HasNull                   = 0
+pp_data->cap[113]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[113]->NotButton.LogicalMin                = 0
+pp_data->cap[113]->NotButton.LogicalMax                = 127
+pp_data->cap[113]->NotButton.PhysicalMin               = 0
+pp_data->cap[113]->NotButton.PhysicalMax               = 0
+pp_data->cap[113]->Units                    = 0
+pp_data->cap[113]->UnitsExp                 = 0
+
+pp_data->cap[114]->UsagePage                    = 0xFF01
+pp_data->cap[114]->ReportID                     = 0x80
+pp_data->cap[114]->BitPosition                  = 0
+pp_data->cap[114]->BitSize                      = 8
+pp_data->cap[114]->ReportCount                  = 1
+pp_data->cap[114]->BytePosition                 = 0x0043
+pp_data->cap[114]->BitCount                     = 8
+pp_data->cap[114]->BitField                     = 0x02
+pp_data->cap[114]->NextBytePosition             = 0x0044
+pp_data->cap[114]->LinkCollection               = 0x0003
+pp_data->cap[114]->LinkUsagePage                = 0xFF01
+pp_data->cap[114]->LinkUsage                    = 0x0080
+pp_data->cap[114]->IsMultipleItemsForArray      = 0
+pp_data->cap[114]->IsButtonCap                  = 0
+pp_data->cap[114]->IsPadding                    = 0
+pp_data->cap[114]->IsAbsolute                   = 1
+pp_data->cap[114]->IsRange                      = 0
+pp_data->cap[114]->IsAlias                      = 0
+pp_data->cap[114]->IsStringRange                = 0
+pp_data->cap[114]->IsDesignatorRange            = 0
+pp_data->cap[114]->Reserved1                    = 0x000000
+pp_data->cap[114]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[114]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[114]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[114]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[114]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[114]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[114]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[114]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[114]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[114]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[114]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[114]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[114]->NotRange.Usage                        = 0x0081
+pp_data->cap[114]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[114]->NotRange.StringIndex                  = 0
+pp_data->cap[114]->NotRange.Reserved2                    = 0
+pp_data->cap[114]->NotRange.DesignatorIndex              = 0
+pp_data->cap[114]->NotRange.Reserved3                    = 0
+pp_data->cap[114]->NotRange.DataIndex                    = 27
+pp_data->cap[114]->NotRange.Reserved4                    = 27
+pp_data->cap[114]->NotButton.HasNull                   = 0
+pp_data->cap[114]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[114]->NotButton.LogicalMin                = 0
+pp_data->cap[114]->NotButton.LogicalMax                = 127
+pp_data->cap[114]->NotButton.PhysicalMin               = 0
+pp_data->cap[114]->NotButton.PhysicalMax               = 0
+pp_data->cap[114]->Units                    = 0
+pp_data->cap[114]->UnitsExp                 = 0
+
+pp_data->cap[115]->UsagePage                    = 0xFF01
+pp_data->cap[115]->ReportID                     = 0x80
+pp_data->cap[115]->BitPosition                  = 0
+pp_data->cap[115]->BitSize                      = 8
+pp_data->cap[115]->ReportCount                  = 1
+pp_data->cap[115]->BytePosition                 = 0x0042
+pp_data->cap[115]->BitCount                     = 8
+pp_data->cap[115]->BitField                     = 0x02
+pp_data->cap[115]->NextBytePosition             = 0x0043
+pp_data->cap[115]->LinkCollection               = 0x0003
+pp_data->cap[115]->LinkUsagePage                = 0xFF01
+pp_data->cap[115]->LinkUsage                    = 0x0080
+pp_data->cap[115]->IsMultipleItemsForArray      = 0
+pp_data->cap[115]->IsButtonCap                  = 0
+pp_data->cap[115]->IsPadding                    = 0
+pp_data->cap[115]->IsAbsolute                   = 1
+pp_data->cap[115]->IsRange                      = 0
+pp_data->cap[115]->IsAlias                      = 0
+pp_data->cap[115]->IsStringRange                = 0
+pp_data->cap[115]->IsDesignatorRange            = 0
+pp_data->cap[115]->Reserved1                    = 0x000000
+pp_data->cap[115]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[115]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[115]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[115]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[115]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[115]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[115]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[115]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[115]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[115]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[115]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[115]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[115]->NotRange.Usage                        = 0x0081
+pp_data->cap[115]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[115]->NotRange.StringIndex                  = 0
+pp_data->cap[115]->NotRange.Reserved2                    = 0
+pp_data->cap[115]->NotRange.DesignatorIndex              = 0
+pp_data->cap[115]->NotRange.Reserved3                    = 0
+pp_data->cap[115]->NotRange.DataIndex                    = 28
+pp_data->cap[115]->NotRange.Reserved4                    = 28
+pp_data->cap[115]->NotButton.HasNull                   = 0
+pp_data->cap[115]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[115]->NotButton.LogicalMin                = 0
+pp_data->cap[115]->NotButton.LogicalMax                = 127
+pp_data->cap[115]->NotButton.PhysicalMin               = 0
+pp_data->cap[115]->NotButton.PhysicalMax               = 0
+pp_data->cap[115]->Units                    = 0
+pp_data->cap[115]->UnitsExp                 = 0
+
+pp_data->cap[116]->UsagePage                    = 0xFF01
+pp_data->cap[116]->ReportID                     = 0x80
+pp_data->cap[116]->BitPosition                  = 0
+pp_data->cap[116]->BitSize                      = 8
+pp_data->cap[116]->ReportCount                  = 1
+pp_data->cap[116]->BytePosition                 = 0x0041
+pp_data->cap[116]->BitCount                     = 8
+pp_data->cap[116]->BitField                     = 0x02
+pp_data->cap[116]->NextBytePosition             = 0x0042
+pp_data->cap[116]->LinkCollection               = 0x0003
+pp_data->cap[116]->LinkUsagePage                = 0xFF01
+pp_data->cap[116]->LinkUsage                    = 0x0080
+pp_data->cap[116]->IsMultipleItemsForArray      = 0
+pp_data->cap[116]->IsButtonCap                  = 0
+pp_data->cap[116]->IsPadding                    = 0
+pp_data->cap[116]->IsAbsolute                   = 1
+pp_data->cap[116]->IsRange                      = 0
+pp_data->cap[116]->IsAlias                      = 0
+pp_data->cap[116]->IsStringRange                = 0
+pp_data->cap[116]->IsDesignatorRange            = 0
+pp_data->cap[116]->Reserved1                    = 0x000000
+pp_data->cap[116]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[116]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[116]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[116]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[116]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[116]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[116]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[116]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[116]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[116]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[116]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[116]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[116]->NotRange.Usage                        = 0x0081
+pp_data->cap[116]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[116]->NotRange.StringIndex                  = 0
+pp_data->cap[116]->NotRange.Reserved2                    = 0
+pp_data->cap[116]->NotRange.DesignatorIndex              = 0
+pp_data->cap[116]->NotRange.Reserved3                    = 0
+pp_data->cap[116]->NotRange.DataIndex                    = 29
+pp_data->cap[116]->NotRange.Reserved4                    = 29
+pp_data->cap[116]->NotButton.HasNull                   = 0
+pp_data->cap[116]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[116]->NotButton.LogicalMin                = 0
+pp_data->cap[116]->NotButton.LogicalMax                = 127
+pp_data->cap[116]->NotButton.PhysicalMin               = 0
+pp_data->cap[116]->NotButton.PhysicalMax               = 0
+pp_data->cap[116]->Units                    = 0
+pp_data->cap[116]->UnitsExp                 = 0
+
+pp_data->cap[117]->UsagePage                    = 0xFF01
+pp_data->cap[117]->ReportID                     = 0x80
+pp_data->cap[117]->BitPosition                  = 0
+pp_data->cap[117]->BitSize                      = 8
+pp_data->cap[117]->ReportCount                  = 1
+pp_data->cap[117]->BytePosition                 = 0x0040
+pp_data->cap[117]->BitCount                     = 8
+pp_data->cap[117]->BitField                     = 0x02
+pp_data->cap[117]->NextBytePosition             = 0x0041
+pp_data->cap[117]->LinkCollection               = 0x0003
+pp_data->cap[117]->LinkUsagePage                = 0xFF01
+pp_data->cap[117]->LinkUsage                    = 0x0080
+pp_data->cap[117]->IsMultipleItemsForArray      = 0
+pp_data->cap[117]->IsButtonCap                  = 0
+pp_data->cap[117]->IsPadding                    = 0
+pp_data->cap[117]->IsAbsolute                   = 1
+pp_data->cap[117]->IsRange                      = 0
+pp_data->cap[117]->IsAlias                      = 0
+pp_data->cap[117]->IsStringRange                = 0
+pp_data->cap[117]->IsDesignatorRange            = 0
+pp_data->cap[117]->Reserved1                    = 0x000000
+pp_data->cap[117]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[117]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[117]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[117]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[117]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[117]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[117]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[117]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[117]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[117]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[117]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[117]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[117]->NotRange.Usage                        = 0x0081
+pp_data->cap[117]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[117]->NotRange.StringIndex                  = 0
+pp_data->cap[117]->NotRange.Reserved2                    = 0
+pp_data->cap[117]->NotRange.DesignatorIndex              = 0
+pp_data->cap[117]->NotRange.Reserved3                    = 0
+pp_data->cap[117]->NotRange.DataIndex                    = 30
+pp_data->cap[117]->NotRange.Reserved4                    = 30
+pp_data->cap[117]->NotButton.HasNull                   = 0
+pp_data->cap[117]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[117]->NotButton.LogicalMin                = 0
+pp_data->cap[117]->NotButton.LogicalMax                = 127
+pp_data->cap[117]->NotButton.PhysicalMin               = 0
+pp_data->cap[117]->NotButton.PhysicalMax               = 0
+pp_data->cap[117]->Units                    = 0
+pp_data->cap[117]->UnitsExp                 = 0
+
+pp_data->cap[118]->UsagePage                    = 0xFF01
+pp_data->cap[118]->ReportID                     = 0x80
+pp_data->cap[118]->BitPosition                  = 0
+pp_data->cap[118]->BitSize                      = 8
+pp_data->cap[118]->ReportCount                  = 1
+pp_data->cap[118]->BytePosition                 = 0x003F
+pp_data->cap[118]->BitCount                     = 8
+pp_data->cap[118]->BitField                     = 0x02
+pp_data->cap[118]->NextBytePosition             = 0x0040
+pp_data->cap[118]->LinkCollection               = 0x0003
+pp_data->cap[118]->LinkUsagePage                = 0xFF01
+pp_data->cap[118]->LinkUsage                    = 0x0080
+pp_data->cap[118]->IsMultipleItemsForArray      = 0
+pp_data->cap[118]->IsButtonCap                  = 0
+pp_data->cap[118]->IsPadding                    = 0
+pp_data->cap[118]->IsAbsolute                   = 1
+pp_data->cap[118]->IsRange                      = 0
+pp_data->cap[118]->IsAlias                      = 0
+pp_data->cap[118]->IsStringRange                = 0
+pp_data->cap[118]->IsDesignatorRange            = 0
+pp_data->cap[118]->Reserved1                    = 0x000000
+pp_data->cap[118]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[118]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[118]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[118]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[118]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[118]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[118]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[118]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[118]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[118]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[118]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[118]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[118]->NotRange.Usage                        = 0x0081
+pp_data->cap[118]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[118]->NotRange.StringIndex                  = 0
+pp_data->cap[118]->NotRange.Reserved2                    = 0
+pp_data->cap[118]->NotRange.DesignatorIndex              = 0
+pp_data->cap[118]->NotRange.Reserved3                    = 0
+pp_data->cap[118]->NotRange.DataIndex                    = 31
+pp_data->cap[118]->NotRange.Reserved4                    = 31
+pp_data->cap[118]->NotButton.HasNull                   = 0
+pp_data->cap[118]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[118]->NotButton.LogicalMin                = 0
+pp_data->cap[118]->NotButton.LogicalMax                = 127
+pp_data->cap[118]->NotButton.PhysicalMin               = 0
+pp_data->cap[118]->NotButton.PhysicalMax               = 0
+pp_data->cap[118]->Units                    = 0
+pp_data->cap[118]->UnitsExp                 = 0
+
+pp_data->cap[119]->UsagePage                    = 0xFF01
+pp_data->cap[119]->ReportID                     = 0x80
+pp_data->cap[119]->BitPosition                  = 0
+pp_data->cap[119]->BitSize                      = 8
+pp_data->cap[119]->ReportCount                  = 1
+pp_data->cap[119]->BytePosition                 = 0x003E
+pp_data->cap[119]->BitCount                     = 8
+pp_data->cap[119]->BitField                     = 0x02
+pp_data->cap[119]->NextBytePosition             = 0x003F
+pp_data->cap[119]->LinkCollection               = 0x0003
+pp_data->cap[119]->LinkUsagePage                = 0xFF01
+pp_data->cap[119]->LinkUsage                    = 0x0080
+pp_data->cap[119]->IsMultipleItemsForArray      = 0
+pp_data->cap[119]->IsButtonCap                  = 0
+pp_data->cap[119]->IsPadding                    = 0
+pp_data->cap[119]->IsAbsolute                   = 1
+pp_data->cap[119]->IsRange                      = 0
+pp_data->cap[119]->IsAlias                      = 0
+pp_data->cap[119]->IsStringRange                = 0
+pp_data->cap[119]->IsDesignatorRange            = 0
+pp_data->cap[119]->Reserved1                    = 0x000000
+pp_data->cap[119]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[119]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[119]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[119]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[119]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[119]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[119]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[119]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[119]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[119]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[119]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[119]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[119]->NotRange.Usage                        = 0x0081
+pp_data->cap[119]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[119]->NotRange.StringIndex                  = 0
+pp_data->cap[119]->NotRange.Reserved2                    = 0
+pp_data->cap[119]->NotRange.DesignatorIndex              = 0
+pp_data->cap[119]->NotRange.Reserved3                    = 0
+pp_data->cap[119]->NotRange.DataIndex                    = 32
+pp_data->cap[119]->NotRange.Reserved4                    = 32
+pp_data->cap[119]->NotButton.HasNull                   = 0
+pp_data->cap[119]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[119]->NotButton.LogicalMin                = 0
+pp_data->cap[119]->NotButton.LogicalMax                = 127
+pp_data->cap[119]->NotButton.PhysicalMin               = 0
+pp_data->cap[119]->NotButton.PhysicalMax               = 0
+pp_data->cap[119]->Units                    = 0
+pp_data->cap[119]->UnitsExp                 = 0
+
+pp_data->cap[120]->UsagePage                    = 0xFF01
+pp_data->cap[120]->ReportID                     = 0x80
+pp_data->cap[120]->BitPosition                  = 0
+pp_data->cap[120]->BitSize                      = 8
+pp_data->cap[120]->ReportCount                  = 1
+pp_data->cap[120]->BytePosition                 = 0x003D
+pp_data->cap[120]->BitCount                     = 8
+pp_data->cap[120]->BitField                     = 0x02
+pp_data->cap[120]->NextBytePosition             = 0x003E
+pp_data->cap[120]->LinkCollection               = 0x0003
+pp_data->cap[120]->LinkUsagePage                = 0xFF01
+pp_data->cap[120]->LinkUsage                    = 0x0080
+pp_data->cap[120]->IsMultipleItemsForArray      = 0
+pp_data->cap[120]->IsButtonCap                  = 0
+pp_data->cap[120]->IsPadding                    = 0
+pp_data->cap[120]->IsAbsolute                   = 1
+pp_data->cap[120]->IsRange                      = 0
+pp_data->cap[120]->IsAlias                      = 0
+pp_data->cap[120]->IsStringRange                = 0
+pp_data->cap[120]->IsDesignatorRange            = 0
+pp_data->cap[120]->Reserved1                    = 0x000000
+pp_data->cap[120]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[120]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[120]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[120]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[120]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[120]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[120]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[120]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[120]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[120]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[120]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[120]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[120]->NotRange.Usage                        = 0x0081
+pp_data->cap[120]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[120]->NotRange.StringIndex                  = 0
+pp_data->cap[120]->NotRange.Reserved2                    = 0
+pp_data->cap[120]->NotRange.DesignatorIndex              = 0
+pp_data->cap[120]->NotRange.Reserved3                    = 0
+pp_data->cap[120]->NotRange.DataIndex                    = 33
+pp_data->cap[120]->NotRange.Reserved4                    = 33
+pp_data->cap[120]->NotButton.HasNull                   = 0
+pp_data->cap[120]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[120]->NotButton.LogicalMin                = 0
+pp_data->cap[120]->NotButton.LogicalMax                = 127
+pp_data->cap[120]->NotButton.PhysicalMin               = 0
+pp_data->cap[120]->NotButton.PhysicalMax               = 0
+pp_data->cap[120]->Units                    = 0
+pp_data->cap[120]->UnitsExp                 = 0
+
+pp_data->cap[121]->UsagePage                    = 0xFF01
+pp_data->cap[121]->ReportID                     = 0x80
+pp_data->cap[121]->BitPosition                  = 0
+pp_data->cap[121]->BitSize                      = 8
+pp_data->cap[121]->ReportCount                  = 1
+pp_data->cap[121]->BytePosition                 = 0x003C
+pp_data->cap[121]->BitCount                     = 8
+pp_data->cap[121]->BitField                     = 0x02
+pp_data->cap[121]->NextBytePosition             = 0x003D
+pp_data->cap[121]->LinkCollection               = 0x0003
+pp_data->cap[121]->LinkUsagePage                = 0xFF01
+pp_data->cap[121]->LinkUsage                    = 0x0080
+pp_data->cap[121]->IsMultipleItemsForArray      = 0
+pp_data->cap[121]->IsButtonCap                  = 0
+pp_data->cap[121]->IsPadding                    = 0
+pp_data->cap[121]->IsAbsolute                   = 1
+pp_data->cap[121]->IsRange                      = 0
+pp_data->cap[121]->IsAlias                      = 0
+pp_data->cap[121]->IsStringRange                = 0
+pp_data->cap[121]->IsDesignatorRange            = 0
+pp_data->cap[121]->Reserved1                    = 0x000000
+pp_data->cap[121]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[121]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[121]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[121]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[121]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[121]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[121]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[121]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[121]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[121]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[121]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[121]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[121]->NotRange.Usage                        = 0x0081
+pp_data->cap[121]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[121]->NotRange.StringIndex                  = 0
+pp_data->cap[121]->NotRange.Reserved2                    = 0
+pp_data->cap[121]->NotRange.DesignatorIndex              = 0
+pp_data->cap[121]->NotRange.Reserved3                    = 0
+pp_data->cap[121]->NotRange.DataIndex                    = 34
+pp_data->cap[121]->NotRange.Reserved4                    = 34
+pp_data->cap[121]->NotButton.HasNull                   = 0
+pp_data->cap[121]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[121]->NotButton.LogicalMin                = 0
+pp_data->cap[121]->NotButton.LogicalMax                = 127
+pp_data->cap[121]->NotButton.PhysicalMin               = 0
+pp_data->cap[121]->NotButton.PhysicalMax               = 0
+pp_data->cap[121]->Units                    = 0
+pp_data->cap[121]->UnitsExp                 = 0
+
+pp_data->cap[122]->UsagePage                    = 0xFF01
+pp_data->cap[122]->ReportID                     = 0x80
+pp_data->cap[122]->BitPosition                  = 0
+pp_data->cap[122]->BitSize                      = 8
+pp_data->cap[122]->ReportCount                  = 1
+pp_data->cap[122]->BytePosition                 = 0x003B
+pp_data->cap[122]->BitCount                     = 8
+pp_data->cap[122]->BitField                     = 0x02
+pp_data->cap[122]->NextBytePosition             = 0x003C
+pp_data->cap[122]->LinkCollection               = 0x0003
+pp_data->cap[122]->LinkUsagePage                = 0xFF01
+pp_data->cap[122]->LinkUsage                    = 0x0080
+pp_data->cap[122]->IsMultipleItemsForArray      = 0
+pp_data->cap[122]->IsButtonCap                  = 0
+pp_data->cap[122]->IsPadding                    = 0
+pp_data->cap[122]->IsAbsolute                   = 1
+pp_data->cap[122]->IsRange                      = 0
+pp_data->cap[122]->IsAlias                      = 0
+pp_data->cap[122]->IsStringRange                = 0
+pp_data->cap[122]->IsDesignatorRange            = 0
+pp_data->cap[122]->Reserved1                    = 0x000000
+pp_data->cap[122]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[122]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[122]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[122]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[122]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[122]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[122]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[122]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[122]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[122]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[122]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[122]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[122]->NotRange.Usage                        = 0x0081
+pp_data->cap[122]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[122]->NotRange.StringIndex                  = 0
+pp_data->cap[122]->NotRange.Reserved2                    = 0
+pp_data->cap[122]->NotRange.DesignatorIndex              = 0
+pp_data->cap[122]->NotRange.Reserved3                    = 0
+pp_data->cap[122]->NotRange.DataIndex                    = 35
+pp_data->cap[122]->NotRange.Reserved4                    = 35
+pp_data->cap[122]->NotButton.HasNull                   = 0
+pp_data->cap[122]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[122]->NotButton.LogicalMin                = 0
+pp_data->cap[122]->NotButton.LogicalMax                = 127
+pp_data->cap[122]->NotButton.PhysicalMin               = 0
+pp_data->cap[122]->NotButton.PhysicalMax               = 0
+pp_data->cap[122]->Units                    = 0
+pp_data->cap[122]->UnitsExp                 = 0
+
+pp_data->cap[123]->UsagePage                    = 0xFF01
+pp_data->cap[123]->ReportID                     = 0x80
+pp_data->cap[123]->BitPosition                  = 0
+pp_data->cap[123]->BitSize                      = 8
+pp_data->cap[123]->ReportCount                  = 1
+pp_data->cap[123]->BytePosition                 = 0x003A
+pp_data->cap[123]->BitCount                     = 8
+pp_data->cap[123]->BitField                     = 0x02
+pp_data->cap[123]->NextBytePosition             = 0x003B
+pp_data->cap[123]->LinkCollection               = 0x0003
+pp_data->cap[123]->LinkUsagePage                = 0xFF01
+pp_data->cap[123]->LinkUsage                    = 0x0080
+pp_data->cap[123]->IsMultipleItemsForArray      = 0
+pp_data->cap[123]->IsButtonCap                  = 0
+pp_data->cap[123]->IsPadding                    = 0
+pp_data->cap[123]->IsAbsolute                   = 1
+pp_data->cap[123]->IsRange                      = 0
+pp_data->cap[123]->IsAlias                      = 0
+pp_data->cap[123]->IsStringRange                = 0
+pp_data->cap[123]->IsDesignatorRange            = 0
+pp_data->cap[123]->Reserved1                    = 0x000000
+pp_data->cap[123]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[123]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[123]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[123]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[123]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[123]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[123]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[123]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[123]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[123]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[123]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[123]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[123]->NotRange.Usage                        = 0x0081
+pp_data->cap[123]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[123]->NotRange.StringIndex                  = 0
+pp_data->cap[123]->NotRange.Reserved2                    = 0
+pp_data->cap[123]->NotRange.DesignatorIndex              = 0
+pp_data->cap[123]->NotRange.Reserved3                    = 0
+pp_data->cap[123]->NotRange.DataIndex                    = 36
+pp_data->cap[123]->NotRange.Reserved4                    = 36
+pp_data->cap[123]->NotButton.HasNull                   = 0
+pp_data->cap[123]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[123]->NotButton.LogicalMin                = 0
+pp_data->cap[123]->NotButton.LogicalMax                = 127
+pp_data->cap[123]->NotButton.PhysicalMin               = 0
+pp_data->cap[123]->NotButton.PhysicalMax               = 0
+pp_data->cap[123]->Units                    = 0
+pp_data->cap[123]->UnitsExp                 = 0
+
+pp_data->cap[124]->UsagePage                    = 0xFF01
+pp_data->cap[124]->ReportID                     = 0x80
+pp_data->cap[124]->BitPosition                  = 0
+pp_data->cap[124]->BitSize                      = 8
+pp_data->cap[124]->ReportCount                  = 1
+pp_data->cap[124]->BytePosition                 = 0x0039
+pp_data->cap[124]->BitCount                     = 8
+pp_data->cap[124]->BitField                     = 0x02
+pp_data->cap[124]->NextBytePosition             = 0x003A
+pp_data->cap[124]->LinkCollection               = 0x0003
+pp_data->cap[124]->LinkUsagePage                = 0xFF01
+pp_data->cap[124]->LinkUsage                    = 0x0080
+pp_data->cap[124]->IsMultipleItemsForArray      = 0
+pp_data->cap[124]->IsButtonCap                  = 0
+pp_data->cap[124]->IsPadding                    = 0
+pp_data->cap[124]->IsAbsolute                   = 1
+pp_data->cap[124]->IsRange                      = 0
+pp_data->cap[124]->IsAlias                      = 0
+pp_data->cap[124]->IsStringRange                = 0
+pp_data->cap[124]->IsDesignatorRange            = 0
+pp_data->cap[124]->Reserved1                    = 0x000000
+pp_data->cap[124]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[124]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[124]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[124]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[124]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[124]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[124]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[124]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[124]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[124]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[124]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[124]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[124]->NotRange.Usage                        = 0x0081
+pp_data->cap[124]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[124]->NotRange.StringIndex                  = 0
+pp_data->cap[124]->NotRange.Reserved2                    = 0
+pp_data->cap[124]->NotRange.DesignatorIndex              = 0
+pp_data->cap[124]->NotRange.Reserved3                    = 0
+pp_data->cap[124]->NotRange.DataIndex                    = 37
+pp_data->cap[124]->NotRange.Reserved4                    = 37
+pp_data->cap[124]->NotButton.HasNull                   = 0
+pp_data->cap[124]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[124]->NotButton.LogicalMin                = 0
+pp_data->cap[124]->NotButton.LogicalMax                = 127
+pp_data->cap[124]->NotButton.PhysicalMin               = 0
+pp_data->cap[124]->NotButton.PhysicalMax               = 0
+pp_data->cap[124]->Units                    = 0
+pp_data->cap[124]->UnitsExp                 = 0
+
+pp_data->cap[125]->UsagePage                    = 0xFF01
+pp_data->cap[125]->ReportID                     = 0x80
+pp_data->cap[125]->BitPosition                  = 0
+pp_data->cap[125]->BitSize                      = 8
+pp_data->cap[125]->ReportCount                  = 1
+pp_data->cap[125]->BytePosition                 = 0x0038
+pp_data->cap[125]->BitCount                     = 8
+pp_data->cap[125]->BitField                     = 0x02
+pp_data->cap[125]->NextBytePosition             = 0x0039
+pp_data->cap[125]->LinkCollection               = 0x0003
+pp_data->cap[125]->LinkUsagePage                = 0xFF01
+pp_data->cap[125]->LinkUsage                    = 0x0080
+pp_data->cap[125]->IsMultipleItemsForArray      = 0
+pp_data->cap[125]->IsButtonCap                  = 0
+pp_data->cap[125]->IsPadding                    = 0
+pp_data->cap[125]->IsAbsolute                   = 1
+pp_data->cap[125]->IsRange                      = 0
+pp_data->cap[125]->IsAlias                      = 0
+pp_data->cap[125]->IsStringRange                = 0
+pp_data->cap[125]->IsDesignatorRange            = 0
+pp_data->cap[125]->Reserved1                    = 0x000000
+pp_data->cap[125]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[125]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[125]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[125]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[125]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[125]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[125]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[125]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[125]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[125]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[125]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[125]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[125]->NotRange.Usage                        = 0x0081
+pp_data->cap[125]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[125]->NotRange.StringIndex                  = 0
+pp_data->cap[125]->NotRange.Reserved2                    = 0
+pp_data->cap[125]->NotRange.DesignatorIndex              = 0
+pp_data->cap[125]->NotRange.Reserved3                    = 0
+pp_data->cap[125]->NotRange.DataIndex                    = 38
+pp_data->cap[125]->NotRange.Reserved4                    = 38
+pp_data->cap[125]->NotButton.HasNull                   = 0
+pp_data->cap[125]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[125]->NotButton.LogicalMin                = 0
+pp_data->cap[125]->NotButton.LogicalMax                = 127
+pp_data->cap[125]->NotButton.PhysicalMin               = 0
+pp_data->cap[125]->NotButton.PhysicalMax               = 0
+pp_data->cap[125]->Units                    = 0
+pp_data->cap[125]->UnitsExp                 = 0
+
+pp_data->cap[126]->UsagePage                    = 0xFF01
+pp_data->cap[126]->ReportID                     = 0x80
+pp_data->cap[126]->BitPosition                  = 0
+pp_data->cap[126]->BitSize                      = 8
+pp_data->cap[126]->ReportCount                  = 1
+pp_data->cap[126]->BytePosition                 = 0x0037
+pp_data->cap[126]->BitCount                     = 8
+pp_data->cap[126]->BitField                     = 0x02
+pp_data->cap[126]->NextBytePosition             = 0x0038
+pp_data->cap[126]->LinkCollection               = 0x0003
+pp_data->cap[126]->LinkUsagePage                = 0xFF01
+pp_data->cap[126]->LinkUsage                    = 0x0080
+pp_data->cap[126]->IsMultipleItemsForArray      = 0
+pp_data->cap[126]->IsButtonCap                  = 0
+pp_data->cap[126]->IsPadding                    = 0
+pp_data->cap[126]->IsAbsolute                   = 1
+pp_data->cap[126]->IsRange                      = 0
+pp_data->cap[126]->IsAlias                      = 0
+pp_data->cap[126]->IsStringRange                = 0
+pp_data->cap[126]->IsDesignatorRange            = 0
+pp_data->cap[126]->Reserved1                    = 0x000000
+pp_data->cap[126]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[126]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[126]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[126]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[126]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[126]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[126]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[126]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[126]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[126]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[126]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[126]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[126]->NotRange.Usage                        = 0x0081
+pp_data->cap[126]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[126]->NotRange.StringIndex                  = 0
+pp_data->cap[126]->NotRange.Reserved2                    = 0
+pp_data->cap[126]->NotRange.DesignatorIndex              = 0
+pp_data->cap[126]->NotRange.Reserved3                    = 0
+pp_data->cap[126]->NotRange.DataIndex                    = 39
+pp_data->cap[126]->NotRange.Reserved4                    = 39
+pp_data->cap[126]->NotButton.HasNull                   = 0
+pp_data->cap[126]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[126]->NotButton.LogicalMin                = 0
+pp_data->cap[126]->NotButton.LogicalMax                = 127
+pp_data->cap[126]->NotButton.PhysicalMin               = 0
+pp_data->cap[126]->NotButton.PhysicalMax               = 0
+pp_data->cap[126]->Units                    = 0
+pp_data->cap[126]->UnitsExp                 = 0
+
+pp_data->cap[127]->UsagePage                    = 0xFF01
+pp_data->cap[127]->ReportID                     = 0x80
+pp_data->cap[127]->BitPosition                  = 0
+pp_data->cap[127]->BitSize                      = 8
+pp_data->cap[127]->ReportCount                  = 1
+pp_data->cap[127]->BytePosition                 = 0x0036
+pp_data->cap[127]->BitCount                     = 8
+pp_data->cap[127]->BitField                     = 0x02
+pp_data->cap[127]->NextBytePosition             = 0x0037
+pp_data->cap[127]->LinkCollection               = 0x0003
+pp_data->cap[127]->LinkUsagePage                = 0xFF01
+pp_data->cap[127]->LinkUsage                    = 0x0080
+pp_data->cap[127]->IsMultipleItemsForArray      = 0
+pp_data->cap[127]->IsButtonCap                  = 0
+pp_data->cap[127]->IsPadding                    = 0
+pp_data->cap[127]->IsAbsolute                   = 1
+pp_data->cap[127]->IsRange                      = 0
+pp_data->cap[127]->IsAlias                      = 0
+pp_data->cap[127]->IsStringRange                = 0
+pp_data->cap[127]->IsDesignatorRange            = 0
+pp_data->cap[127]->Reserved1                    = 0x000000
+pp_data->cap[127]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[127]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[127]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[127]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[127]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[127]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[127]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[127]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[127]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[127]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[127]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[127]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[127]->NotRange.Usage                        = 0x0081
+pp_data->cap[127]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[127]->NotRange.StringIndex                  = 0
+pp_data->cap[127]->NotRange.Reserved2                    = 0
+pp_data->cap[127]->NotRange.DesignatorIndex              = 0
+pp_data->cap[127]->NotRange.Reserved3                    = 0
+pp_data->cap[127]->NotRange.DataIndex                    = 40
+pp_data->cap[127]->NotRange.Reserved4                    = 40
+pp_data->cap[127]->NotButton.HasNull                   = 0
+pp_data->cap[127]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[127]->NotButton.LogicalMin                = 0
+pp_data->cap[127]->NotButton.LogicalMax                = 127
+pp_data->cap[127]->NotButton.PhysicalMin               = 0
+pp_data->cap[127]->NotButton.PhysicalMax               = 0
+pp_data->cap[127]->Units                    = 0
+pp_data->cap[127]->UnitsExp                 = 0
+
+pp_data->cap[128]->UsagePage                    = 0xFF01
+pp_data->cap[128]->ReportID                     = 0x80
+pp_data->cap[128]->BitPosition                  = 0
+pp_data->cap[128]->BitSize                      = 8
+pp_data->cap[128]->ReportCount                  = 1
+pp_data->cap[128]->BytePosition                 = 0x0035
+pp_data->cap[128]->BitCount                     = 8
+pp_data->cap[128]->BitField                     = 0x02
+pp_data->cap[128]->NextBytePosition             = 0x0036
+pp_data->cap[128]->LinkCollection               = 0x0003
+pp_data->cap[128]->LinkUsagePage                = 0xFF01
+pp_data->cap[128]->LinkUsage                    = 0x0080
+pp_data->cap[128]->IsMultipleItemsForArray      = 0
+pp_data->cap[128]->IsButtonCap                  = 0
+pp_data->cap[128]->IsPadding                    = 0
+pp_data->cap[128]->IsAbsolute                   = 1
+pp_data->cap[128]->IsRange                      = 0
+pp_data->cap[128]->IsAlias                      = 0
+pp_data->cap[128]->IsStringRange                = 0
+pp_data->cap[128]->IsDesignatorRange            = 0
+pp_data->cap[128]->Reserved1                    = 0x000000
+pp_data->cap[128]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[128]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[128]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[128]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[128]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[128]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[128]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[128]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[128]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[128]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[128]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[128]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[128]->NotRange.Usage                        = 0x0081
+pp_data->cap[128]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[128]->NotRange.StringIndex                  = 0
+pp_data->cap[128]->NotRange.Reserved2                    = 0
+pp_data->cap[128]->NotRange.DesignatorIndex              = 0
+pp_data->cap[128]->NotRange.Reserved3                    = 0
+pp_data->cap[128]->NotRange.DataIndex                    = 41
+pp_data->cap[128]->NotRange.Reserved4                    = 41
+pp_data->cap[128]->NotButton.HasNull                   = 0
+pp_data->cap[128]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[128]->NotButton.LogicalMin                = 0
+pp_data->cap[128]->NotButton.LogicalMax                = 127
+pp_data->cap[128]->NotButton.PhysicalMin               = 0
+pp_data->cap[128]->NotButton.PhysicalMax               = 0
+pp_data->cap[128]->Units                    = 0
+pp_data->cap[128]->UnitsExp                 = 0
+
+pp_data->cap[129]->UsagePage                    = 0xFF01
+pp_data->cap[129]->ReportID                     = 0x80
+pp_data->cap[129]->BitPosition                  = 0
+pp_data->cap[129]->BitSize                      = 8
+pp_data->cap[129]->ReportCount                  = 1
+pp_data->cap[129]->BytePosition                 = 0x0034
+pp_data->cap[129]->BitCount                     = 8
+pp_data->cap[129]->BitField                     = 0x02
+pp_data->cap[129]->NextBytePosition             = 0x0035
+pp_data->cap[129]->LinkCollection               = 0x0003
+pp_data->cap[129]->LinkUsagePage                = 0xFF01
+pp_data->cap[129]->LinkUsage                    = 0x0080
+pp_data->cap[129]->IsMultipleItemsForArray      = 0
+pp_data->cap[129]->IsButtonCap                  = 0
+pp_data->cap[129]->IsPadding                    = 0
+pp_data->cap[129]->IsAbsolute                   = 1
+pp_data->cap[129]->IsRange                      = 0
+pp_data->cap[129]->IsAlias                      = 0
+pp_data->cap[129]->IsStringRange                = 0
+pp_data->cap[129]->IsDesignatorRange            = 0
+pp_data->cap[129]->Reserved1                    = 0x000000
+pp_data->cap[129]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[129]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[129]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[129]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[129]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[129]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[129]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[129]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[129]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[129]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[129]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[129]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[129]->NotRange.Usage                        = 0x0081
+pp_data->cap[129]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[129]->NotRange.StringIndex                  = 0
+pp_data->cap[129]->NotRange.Reserved2                    = 0
+pp_data->cap[129]->NotRange.DesignatorIndex              = 0
+pp_data->cap[129]->NotRange.Reserved3                    = 0
+pp_data->cap[129]->NotRange.DataIndex                    = 42
+pp_data->cap[129]->NotRange.Reserved4                    = 42
+pp_data->cap[129]->NotButton.HasNull                   = 0
+pp_data->cap[129]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[129]->NotButton.LogicalMin                = 0
+pp_data->cap[129]->NotButton.LogicalMax                = 127
+pp_data->cap[129]->NotButton.PhysicalMin               = 0
+pp_data->cap[129]->NotButton.PhysicalMax               = 0
+pp_data->cap[129]->Units                    = 0
+pp_data->cap[129]->UnitsExp                 = 0
+
+pp_data->cap[130]->UsagePage                    = 0xFF01
+pp_data->cap[130]->ReportID                     = 0x80
+pp_data->cap[130]->BitPosition                  = 0
+pp_data->cap[130]->BitSize                      = 8
+pp_data->cap[130]->ReportCount                  = 1
+pp_data->cap[130]->BytePosition                 = 0x0033
+pp_data->cap[130]->BitCount                     = 8
+pp_data->cap[130]->BitField                     = 0x02
+pp_data->cap[130]->NextBytePosition             = 0x0034
+pp_data->cap[130]->LinkCollection               = 0x0003
+pp_data->cap[130]->LinkUsagePage                = 0xFF01
+pp_data->cap[130]->LinkUsage                    = 0x0080
+pp_data->cap[130]->IsMultipleItemsForArray      = 0
+pp_data->cap[130]->IsButtonCap                  = 0
+pp_data->cap[130]->IsPadding                    = 0
+pp_data->cap[130]->IsAbsolute                   = 1
+pp_data->cap[130]->IsRange                      = 0
+pp_data->cap[130]->IsAlias                      = 0
+pp_data->cap[130]->IsStringRange                = 0
+pp_data->cap[130]->IsDesignatorRange            = 0
+pp_data->cap[130]->Reserved1                    = 0x000000
+pp_data->cap[130]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[130]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[130]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[130]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[130]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[130]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[130]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[130]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[130]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[130]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[130]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[130]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[130]->NotRange.Usage                        = 0x0081
+pp_data->cap[130]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[130]->NotRange.StringIndex                  = 0
+pp_data->cap[130]->NotRange.Reserved2                    = 0
+pp_data->cap[130]->NotRange.DesignatorIndex              = 0
+pp_data->cap[130]->NotRange.Reserved3                    = 0
+pp_data->cap[130]->NotRange.DataIndex                    = 43
+pp_data->cap[130]->NotRange.Reserved4                    = 43
+pp_data->cap[130]->NotButton.HasNull                   = 0
+pp_data->cap[130]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[130]->NotButton.LogicalMin                = 0
+pp_data->cap[130]->NotButton.LogicalMax                = 127
+pp_data->cap[130]->NotButton.PhysicalMin               = 0
+pp_data->cap[130]->NotButton.PhysicalMax               = 0
+pp_data->cap[130]->Units                    = 0
+pp_data->cap[130]->UnitsExp                 = 0
+
+pp_data->cap[131]->UsagePage                    = 0xFF01
+pp_data->cap[131]->ReportID                     = 0x80
+pp_data->cap[131]->BitPosition                  = 0
+pp_data->cap[131]->BitSize                      = 8
+pp_data->cap[131]->ReportCount                  = 1
+pp_data->cap[131]->BytePosition                 = 0x0032
+pp_data->cap[131]->BitCount                     = 8
+pp_data->cap[131]->BitField                     = 0x02
+pp_data->cap[131]->NextBytePosition             = 0x0033
+pp_data->cap[131]->LinkCollection               = 0x0003
+pp_data->cap[131]->LinkUsagePage                = 0xFF01
+pp_data->cap[131]->LinkUsage                    = 0x0080
+pp_data->cap[131]->IsMultipleItemsForArray      = 0
+pp_data->cap[131]->IsButtonCap                  = 0
+pp_data->cap[131]->IsPadding                    = 0
+pp_data->cap[131]->IsAbsolute                   = 1
+pp_data->cap[131]->IsRange                      = 0
+pp_data->cap[131]->IsAlias                      = 0
+pp_data->cap[131]->IsStringRange                = 0
+pp_data->cap[131]->IsDesignatorRange            = 0
+pp_data->cap[131]->Reserved1                    = 0x000000
+pp_data->cap[131]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[131]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[131]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[131]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[131]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[131]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[131]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[131]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[131]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[131]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[131]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[131]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[131]->NotRange.Usage                        = 0x0081
+pp_data->cap[131]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[131]->NotRange.StringIndex                  = 0
+pp_data->cap[131]->NotRange.Reserved2                    = 0
+pp_data->cap[131]->NotRange.DesignatorIndex              = 0
+pp_data->cap[131]->NotRange.Reserved3                    = 0
+pp_data->cap[131]->NotRange.DataIndex                    = 44
+pp_data->cap[131]->NotRange.Reserved4                    = 44
+pp_data->cap[131]->NotButton.HasNull                   = 0
+pp_data->cap[131]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[131]->NotButton.LogicalMin                = 0
+pp_data->cap[131]->NotButton.LogicalMax                = 127
+pp_data->cap[131]->NotButton.PhysicalMin               = 0
+pp_data->cap[131]->NotButton.PhysicalMax               = 0
+pp_data->cap[131]->Units                    = 0
+pp_data->cap[131]->UnitsExp                 = 0
+
+pp_data->cap[132]->UsagePage                    = 0xFF01
+pp_data->cap[132]->ReportID                     = 0x80
+pp_data->cap[132]->BitPosition                  = 0
+pp_data->cap[132]->BitSize                      = 8
+pp_data->cap[132]->ReportCount                  = 1
+pp_data->cap[132]->BytePosition                 = 0x0031
+pp_data->cap[132]->BitCount                     = 8
+pp_data->cap[132]->BitField                     = 0x02
+pp_data->cap[132]->NextBytePosition             = 0x0032
+pp_data->cap[132]->LinkCollection               = 0x0003
+pp_data->cap[132]->LinkUsagePage                = 0xFF01
+pp_data->cap[132]->LinkUsage                    = 0x0080
+pp_data->cap[132]->IsMultipleItemsForArray      = 0
+pp_data->cap[132]->IsButtonCap                  = 0
+pp_data->cap[132]->IsPadding                    = 0
+pp_data->cap[132]->IsAbsolute                   = 1
+pp_data->cap[132]->IsRange                      = 0
+pp_data->cap[132]->IsAlias                      = 0
+pp_data->cap[132]->IsStringRange                = 0
+pp_data->cap[132]->IsDesignatorRange            = 0
+pp_data->cap[132]->Reserved1                    = 0x000000
+pp_data->cap[132]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[132]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[132]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[132]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[132]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[132]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[132]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[132]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[132]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[132]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[132]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[132]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[132]->NotRange.Usage                        = 0x0081
+pp_data->cap[132]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[132]->NotRange.StringIndex                  = 0
+pp_data->cap[132]->NotRange.Reserved2                    = 0
+pp_data->cap[132]->NotRange.DesignatorIndex              = 0
+pp_data->cap[132]->NotRange.Reserved3                    = 0
+pp_data->cap[132]->NotRange.DataIndex                    = 45
+pp_data->cap[132]->NotRange.Reserved4                    = 45
+pp_data->cap[132]->NotButton.HasNull                   = 0
+pp_data->cap[132]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[132]->NotButton.LogicalMin                = 0
+pp_data->cap[132]->NotButton.LogicalMax                = 127
+pp_data->cap[132]->NotButton.PhysicalMin               = 0
+pp_data->cap[132]->NotButton.PhysicalMax               = 0
+pp_data->cap[132]->Units                    = 0
+pp_data->cap[132]->UnitsExp                 = 0
+
+pp_data->cap[133]->UsagePage                    = 0xFF01
+pp_data->cap[133]->ReportID                     = 0x80
+pp_data->cap[133]->BitPosition                  = 0
+pp_data->cap[133]->BitSize                      = 8
+pp_data->cap[133]->ReportCount                  = 1
+pp_data->cap[133]->BytePosition                 = 0x0030
+pp_data->cap[133]->BitCount                     = 8
+pp_data->cap[133]->BitField                     = 0x02
+pp_data->cap[133]->NextBytePosition             = 0x0031
+pp_data->cap[133]->LinkCollection               = 0x0003
+pp_data->cap[133]->LinkUsagePage                = 0xFF01
+pp_data->cap[133]->LinkUsage                    = 0x0080
+pp_data->cap[133]->IsMultipleItemsForArray      = 0
+pp_data->cap[133]->IsButtonCap                  = 0
+pp_data->cap[133]->IsPadding                    = 0
+pp_data->cap[133]->IsAbsolute                   = 1
+pp_data->cap[133]->IsRange                      = 0
+pp_data->cap[133]->IsAlias                      = 0
+pp_data->cap[133]->IsStringRange                = 0
+pp_data->cap[133]->IsDesignatorRange            = 0
+pp_data->cap[133]->Reserved1                    = 0x000000
+pp_data->cap[133]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[133]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[133]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[133]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[133]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[133]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[133]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[133]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[133]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[133]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[133]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[133]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[133]->NotRange.Usage                        = 0x0081
+pp_data->cap[133]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[133]->NotRange.StringIndex                  = 0
+pp_data->cap[133]->NotRange.Reserved2                    = 0
+pp_data->cap[133]->NotRange.DesignatorIndex              = 0
+pp_data->cap[133]->NotRange.Reserved3                    = 0
+pp_data->cap[133]->NotRange.DataIndex                    = 46
+pp_data->cap[133]->NotRange.Reserved4                    = 46
+pp_data->cap[133]->NotButton.HasNull                   = 0
+pp_data->cap[133]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[133]->NotButton.LogicalMin                = 0
+pp_data->cap[133]->NotButton.LogicalMax                = 127
+pp_data->cap[133]->NotButton.PhysicalMin               = 0
+pp_data->cap[133]->NotButton.PhysicalMax               = 0
+pp_data->cap[133]->Units                    = 0
+pp_data->cap[133]->UnitsExp                 = 0
+
+pp_data->cap[134]->UsagePage                    = 0xFF01
+pp_data->cap[134]->ReportID                     = 0x80
+pp_data->cap[134]->BitPosition                  = 0
+pp_data->cap[134]->BitSize                      = 8
+pp_data->cap[134]->ReportCount                  = 1
+pp_data->cap[134]->BytePosition                 = 0x002F
+pp_data->cap[134]->BitCount                     = 8
+pp_data->cap[134]->BitField                     = 0x02
+pp_data->cap[134]->NextBytePosition             = 0x0030
+pp_data->cap[134]->LinkCollection               = 0x0003
+pp_data->cap[134]->LinkUsagePage                = 0xFF01
+pp_data->cap[134]->LinkUsage                    = 0x0080
+pp_data->cap[134]->IsMultipleItemsForArray      = 0
+pp_data->cap[134]->IsButtonCap                  = 0
+pp_data->cap[134]->IsPadding                    = 0
+pp_data->cap[134]->IsAbsolute                   = 1
+pp_data->cap[134]->IsRange                      = 0
+pp_data->cap[134]->IsAlias                      = 0
+pp_data->cap[134]->IsStringRange                = 0
+pp_data->cap[134]->IsDesignatorRange            = 0
+pp_data->cap[134]->Reserved1                    = 0x000000
+pp_data->cap[134]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[134]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[134]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[134]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[134]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[134]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[134]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[134]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[134]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[134]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[134]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[134]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[134]->NotRange.Usage                        = 0x0081
+pp_data->cap[134]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[134]->NotRange.StringIndex                  = 0
+pp_data->cap[134]->NotRange.Reserved2                    = 0
+pp_data->cap[134]->NotRange.DesignatorIndex              = 0
+pp_data->cap[134]->NotRange.Reserved3                    = 0
+pp_data->cap[134]->NotRange.DataIndex                    = 47
+pp_data->cap[134]->NotRange.Reserved4                    = 47
+pp_data->cap[134]->NotButton.HasNull                   = 0
+pp_data->cap[134]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[134]->NotButton.LogicalMin                = 0
+pp_data->cap[134]->NotButton.LogicalMax                = 127
+pp_data->cap[134]->NotButton.PhysicalMin               = 0
+pp_data->cap[134]->NotButton.PhysicalMax               = 0
+pp_data->cap[134]->Units                    = 0
+pp_data->cap[134]->UnitsExp                 = 0
+
+pp_data->cap[135]->UsagePage                    = 0xFF01
+pp_data->cap[135]->ReportID                     = 0x80
+pp_data->cap[135]->BitPosition                  = 0
+pp_data->cap[135]->BitSize                      = 8
+pp_data->cap[135]->ReportCount                  = 1
+pp_data->cap[135]->BytePosition                 = 0x002E
+pp_data->cap[135]->BitCount                     = 8
+pp_data->cap[135]->BitField                     = 0x02
+pp_data->cap[135]->NextBytePosition             = 0x002F
+pp_data->cap[135]->LinkCollection               = 0x0003
+pp_data->cap[135]->LinkUsagePage                = 0xFF01
+pp_data->cap[135]->LinkUsage                    = 0x0080
+pp_data->cap[135]->IsMultipleItemsForArray      = 0
+pp_data->cap[135]->IsButtonCap                  = 0
+pp_data->cap[135]->IsPadding                    = 0
+pp_data->cap[135]->IsAbsolute                   = 1
+pp_data->cap[135]->IsRange                      = 0
+pp_data->cap[135]->IsAlias                      = 0
+pp_data->cap[135]->IsStringRange                = 0
+pp_data->cap[135]->IsDesignatorRange            = 0
+pp_data->cap[135]->Reserved1                    = 0x000000
+pp_data->cap[135]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[135]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[135]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[135]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[135]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[135]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[135]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[135]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[135]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[135]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[135]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[135]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[135]->NotRange.Usage                        = 0x0081
+pp_data->cap[135]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[135]->NotRange.StringIndex                  = 0
+pp_data->cap[135]->NotRange.Reserved2                    = 0
+pp_data->cap[135]->NotRange.DesignatorIndex              = 0
+pp_data->cap[135]->NotRange.Reserved3                    = 0
+pp_data->cap[135]->NotRange.DataIndex                    = 48
+pp_data->cap[135]->NotRange.Reserved4                    = 48
+pp_data->cap[135]->NotButton.HasNull                   = 0
+pp_data->cap[135]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[135]->NotButton.LogicalMin                = 0
+pp_data->cap[135]->NotButton.LogicalMax                = 127
+pp_data->cap[135]->NotButton.PhysicalMin               = 0
+pp_data->cap[135]->NotButton.PhysicalMax               = 0
+pp_data->cap[135]->Units                    = 0
+pp_data->cap[135]->UnitsExp                 = 0
+
+pp_data->cap[136]->UsagePage                    = 0xFF01
+pp_data->cap[136]->ReportID                     = 0x80
+pp_data->cap[136]->BitPosition                  = 0
+pp_data->cap[136]->BitSize                      = 8
+pp_data->cap[136]->ReportCount                  = 1
+pp_data->cap[136]->BytePosition                 = 0x002D
+pp_data->cap[136]->BitCount                     = 8
+pp_data->cap[136]->BitField                     = 0x02
+pp_data->cap[136]->NextBytePosition             = 0x002E
+pp_data->cap[136]->LinkCollection               = 0x0003
+pp_data->cap[136]->LinkUsagePage                = 0xFF01
+pp_data->cap[136]->LinkUsage                    = 0x0080
+pp_data->cap[136]->IsMultipleItemsForArray      = 0
+pp_data->cap[136]->IsButtonCap                  = 0
+pp_data->cap[136]->IsPadding                    = 0
+pp_data->cap[136]->IsAbsolute                   = 1
+pp_data->cap[136]->IsRange                      = 0
+pp_data->cap[136]->IsAlias                      = 0
+pp_data->cap[136]->IsStringRange                = 0
+pp_data->cap[136]->IsDesignatorRange            = 0
+pp_data->cap[136]->Reserved1                    = 0x000000
+pp_data->cap[136]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[136]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[136]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[136]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[136]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[136]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[136]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[136]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[136]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[136]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[136]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[136]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[136]->NotRange.Usage                        = 0x0081
+pp_data->cap[136]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[136]->NotRange.StringIndex                  = 0
+pp_data->cap[136]->NotRange.Reserved2                    = 0
+pp_data->cap[136]->NotRange.DesignatorIndex              = 0
+pp_data->cap[136]->NotRange.Reserved3                    = 0
+pp_data->cap[136]->NotRange.DataIndex                    = 49
+pp_data->cap[136]->NotRange.Reserved4                    = 49
+pp_data->cap[136]->NotButton.HasNull                   = 0
+pp_data->cap[136]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[136]->NotButton.LogicalMin                = 0
+pp_data->cap[136]->NotButton.LogicalMax                = 127
+pp_data->cap[136]->NotButton.PhysicalMin               = 0
+pp_data->cap[136]->NotButton.PhysicalMax               = 0
+pp_data->cap[136]->Units                    = 0
+pp_data->cap[136]->UnitsExp                 = 0
+
+pp_data->cap[137]->UsagePage                    = 0xFF01
+pp_data->cap[137]->ReportID                     = 0x80
+pp_data->cap[137]->BitPosition                  = 0
+pp_data->cap[137]->BitSize                      = 8
+pp_data->cap[137]->ReportCount                  = 1
+pp_data->cap[137]->BytePosition                 = 0x002C
+pp_data->cap[137]->BitCount                     = 8
+pp_data->cap[137]->BitField                     = 0x02
+pp_data->cap[137]->NextBytePosition             = 0x002D
+pp_data->cap[137]->LinkCollection               = 0x0003
+pp_data->cap[137]->LinkUsagePage                = 0xFF01
+pp_data->cap[137]->LinkUsage                    = 0x0080
+pp_data->cap[137]->IsMultipleItemsForArray      = 0
+pp_data->cap[137]->IsButtonCap                  = 0
+pp_data->cap[137]->IsPadding                    = 0
+pp_data->cap[137]->IsAbsolute                   = 1
+pp_data->cap[137]->IsRange                      = 0
+pp_data->cap[137]->IsAlias                      = 0
+pp_data->cap[137]->IsStringRange                = 0
+pp_data->cap[137]->IsDesignatorRange            = 0
+pp_data->cap[137]->Reserved1                    = 0x000000
+pp_data->cap[137]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[137]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[137]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[137]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[137]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[137]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[137]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[137]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[137]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[137]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[137]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[137]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[137]->NotRange.Usage                        = 0x0081
+pp_data->cap[137]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[137]->NotRange.StringIndex                  = 0
+pp_data->cap[137]->NotRange.Reserved2                    = 0
+pp_data->cap[137]->NotRange.DesignatorIndex              = 0
+pp_data->cap[137]->NotRange.Reserved3                    = 0
+pp_data->cap[137]->NotRange.DataIndex                    = 50
+pp_data->cap[137]->NotRange.Reserved4                    = 50
+pp_data->cap[137]->NotButton.HasNull                   = 0
+pp_data->cap[137]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[137]->NotButton.LogicalMin                = 0
+pp_data->cap[137]->NotButton.LogicalMax                = 127
+pp_data->cap[137]->NotButton.PhysicalMin               = 0
+pp_data->cap[137]->NotButton.PhysicalMax               = 0
+pp_data->cap[137]->Units                    = 0
+pp_data->cap[137]->UnitsExp                 = 0
+
+pp_data->cap[138]->UsagePage                    = 0xFF01
+pp_data->cap[138]->ReportID                     = 0x80
+pp_data->cap[138]->BitPosition                  = 0
+pp_data->cap[138]->BitSize                      = 8
+pp_data->cap[138]->ReportCount                  = 1
+pp_data->cap[138]->BytePosition                 = 0x002B
+pp_data->cap[138]->BitCount                     = 8
+pp_data->cap[138]->BitField                     = 0x02
+pp_data->cap[138]->NextBytePosition             = 0x002C
+pp_data->cap[138]->LinkCollection               = 0x0003
+pp_data->cap[138]->LinkUsagePage                = 0xFF01
+pp_data->cap[138]->LinkUsage                    = 0x0080
+pp_data->cap[138]->IsMultipleItemsForArray      = 0
+pp_data->cap[138]->IsButtonCap                  = 0
+pp_data->cap[138]->IsPadding                    = 0
+pp_data->cap[138]->IsAbsolute                   = 1
+pp_data->cap[138]->IsRange                      = 0
+pp_data->cap[138]->IsAlias                      = 0
+pp_data->cap[138]->IsStringRange                = 0
+pp_data->cap[138]->IsDesignatorRange            = 0
+pp_data->cap[138]->Reserved1                    = 0x000000
+pp_data->cap[138]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[138]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[138]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[138]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[138]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[138]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[138]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[138]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[138]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[138]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[138]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[138]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[138]->NotRange.Usage                        = 0x0081
+pp_data->cap[138]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[138]->NotRange.StringIndex                  = 0
+pp_data->cap[138]->NotRange.Reserved2                    = 0
+pp_data->cap[138]->NotRange.DesignatorIndex              = 0
+pp_data->cap[138]->NotRange.Reserved3                    = 0
+pp_data->cap[138]->NotRange.DataIndex                    = 51
+pp_data->cap[138]->NotRange.Reserved4                    = 51
+pp_data->cap[138]->NotButton.HasNull                   = 0
+pp_data->cap[138]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[138]->NotButton.LogicalMin                = 0
+pp_data->cap[138]->NotButton.LogicalMax                = 127
+pp_data->cap[138]->NotButton.PhysicalMin               = 0
+pp_data->cap[138]->NotButton.PhysicalMax               = 0
+pp_data->cap[138]->Units                    = 0
+pp_data->cap[138]->UnitsExp                 = 0
+
+pp_data->cap[139]->UsagePage                    = 0xFF01
+pp_data->cap[139]->ReportID                     = 0x80
+pp_data->cap[139]->BitPosition                  = 0
+pp_data->cap[139]->BitSize                      = 8
+pp_data->cap[139]->ReportCount                  = 1
+pp_data->cap[139]->BytePosition                 = 0x002A
+pp_data->cap[139]->BitCount                     = 8
+pp_data->cap[139]->BitField                     = 0x02
+pp_data->cap[139]->NextBytePosition             = 0x002B
+pp_data->cap[139]->LinkCollection               = 0x0003
+pp_data->cap[139]->LinkUsagePage                = 0xFF01
+pp_data->cap[139]->LinkUsage                    = 0x0080
+pp_data->cap[139]->IsMultipleItemsForArray      = 0
+pp_data->cap[139]->IsButtonCap                  = 0
+pp_data->cap[139]->IsPadding                    = 0
+pp_data->cap[139]->IsAbsolute                   = 1
+pp_data->cap[139]->IsRange                      = 0
+pp_data->cap[139]->IsAlias                      = 0
+pp_data->cap[139]->IsStringRange                = 0
+pp_data->cap[139]->IsDesignatorRange            = 0
+pp_data->cap[139]->Reserved1                    = 0x000000
+pp_data->cap[139]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[139]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[139]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[139]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[139]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[139]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[139]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[139]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[139]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[139]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[139]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[139]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[139]->NotRange.Usage                        = 0x0081
+pp_data->cap[139]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[139]->NotRange.StringIndex                  = 0
+pp_data->cap[139]->NotRange.Reserved2                    = 0
+pp_data->cap[139]->NotRange.DesignatorIndex              = 0
+pp_data->cap[139]->NotRange.Reserved3                    = 0
+pp_data->cap[139]->NotRange.DataIndex                    = 52
+pp_data->cap[139]->NotRange.Reserved4                    = 52
+pp_data->cap[139]->NotButton.HasNull                   = 0
+pp_data->cap[139]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[139]->NotButton.LogicalMin                = 0
+pp_data->cap[139]->NotButton.LogicalMax                = 127
+pp_data->cap[139]->NotButton.PhysicalMin               = 0
+pp_data->cap[139]->NotButton.PhysicalMax               = 0
+pp_data->cap[139]->Units                    = 0
+pp_data->cap[139]->UnitsExp                 = 0
+
+pp_data->cap[140]->UsagePage                    = 0xFF01
+pp_data->cap[140]->ReportID                     = 0x80
+pp_data->cap[140]->BitPosition                  = 0
+pp_data->cap[140]->BitSize                      = 8
+pp_data->cap[140]->ReportCount                  = 1
+pp_data->cap[140]->BytePosition                 = 0x0029
+pp_data->cap[140]->BitCount                     = 8
+pp_data->cap[140]->BitField                     = 0x02
+pp_data->cap[140]->NextBytePosition             = 0x002A
+pp_data->cap[140]->LinkCollection               = 0x0003
+pp_data->cap[140]->LinkUsagePage                = 0xFF01
+pp_data->cap[140]->LinkUsage                    = 0x0080
+pp_data->cap[140]->IsMultipleItemsForArray      = 0
+pp_data->cap[140]->IsButtonCap                  = 0
+pp_data->cap[140]->IsPadding                    = 0
+pp_data->cap[140]->IsAbsolute                   = 1
+pp_data->cap[140]->IsRange                      = 0
+pp_data->cap[140]->IsAlias                      = 0
+pp_data->cap[140]->IsStringRange                = 0
+pp_data->cap[140]->IsDesignatorRange            = 0
+pp_data->cap[140]->Reserved1                    = 0x000000
+pp_data->cap[140]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[140]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[140]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[140]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[140]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[140]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[140]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[140]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[140]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[140]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[140]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[140]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[140]->NotRange.Usage                        = 0x0081
+pp_data->cap[140]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[140]->NotRange.StringIndex                  = 0
+pp_data->cap[140]->NotRange.Reserved2                    = 0
+pp_data->cap[140]->NotRange.DesignatorIndex              = 0
+pp_data->cap[140]->NotRange.Reserved3                    = 0
+pp_data->cap[140]->NotRange.DataIndex                    = 53
+pp_data->cap[140]->NotRange.Reserved4                    = 53
+pp_data->cap[140]->NotButton.HasNull                   = 0
+pp_data->cap[140]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[140]->NotButton.LogicalMin                = 0
+pp_data->cap[140]->NotButton.LogicalMax                = 127
+pp_data->cap[140]->NotButton.PhysicalMin               = 0
+pp_data->cap[140]->NotButton.PhysicalMax               = 0
+pp_data->cap[140]->Units                    = 0
+pp_data->cap[140]->UnitsExp                 = 0
+
+pp_data->cap[141]->UsagePage                    = 0xFF01
+pp_data->cap[141]->ReportID                     = 0x80
+pp_data->cap[141]->BitPosition                  = 0
+pp_data->cap[141]->BitSize                      = 8
+pp_data->cap[141]->ReportCount                  = 1
+pp_data->cap[141]->BytePosition                 = 0x0028
+pp_data->cap[141]->BitCount                     = 8
+pp_data->cap[141]->BitField                     = 0x02
+pp_data->cap[141]->NextBytePosition             = 0x0029
+pp_data->cap[141]->LinkCollection               = 0x0003
+pp_data->cap[141]->LinkUsagePage                = 0xFF01
+pp_data->cap[141]->LinkUsage                    = 0x0080
+pp_data->cap[141]->IsMultipleItemsForArray      = 0
+pp_data->cap[141]->IsButtonCap                  = 0
+pp_data->cap[141]->IsPadding                    = 0
+pp_data->cap[141]->IsAbsolute                   = 1
+pp_data->cap[141]->IsRange                      = 0
+pp_data->cap[141]->IsAlias                      = 0
+pp_data->cap[141]->IsStringRange                = 0
+pp_data->cap[141]->IsDesignatorRange            = 0
+pp_data->cap[141]->Reserved1                    = 0x000000
+pp_data->cap[141]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[141]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[141]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[141]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[141]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[141]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[141]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[141]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[141]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[141]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[141]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[141]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[141]->NotRange.Usage                        = 0x0081
+pp_data->cap[141]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[141]->NotRange.StringIndex                  = 0
+pp_data->cap[141]->NotRange.Reserved2                    = 0
+pp_data->cap[141]->NotRange.DesignatorIndex              = 0
+pp_data->cap[141]->NotRange.Reserved3                    = 0
+pp_data->cap[141]->NotRange.DataIndex                    = 54
+pp_data->cap[141]->NotRange.Reserved4                    = 54
+pp_data->cap[141]->NotButton.HasNull                   = 0
+pp_data->cap[141]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[141]->NotButton.LogicalMin                = 0
+pp_data->cap[141]->NotButton.LogicalMax                = 127
+pp_data->cap[141]->NotButton.PhysicalMin               = 0
+pp_data->cap[141]->NotButton.PhysicalMax               = 0
+pp_data->cap[141]->Units                    = 0
+pp_data->cap[141]->UnitsExp                 = 0
+
+pp_data->cap[142]->UsagePage                    = 0xFF01
+pp_data->cap[142]->ReportID                     = 0x80
+pp_data->cap[142]->BitPosition                  = 0
+pp_data->cap[142]->BitSize                      = 8
+pp_data->cap[142]->ReportCount                  = 1
+pp_data->cap[142]->BytePosition                 = 0x0027
+pp_data->cap[142]->BitCount                     = 8
+pp_data->cap[142]->BitField                     = 0x02
+pp_data->cap[142]->NextBytePosition             = 0x0028
+pp_data->cap[142]->LinkCollection               = 0x0003
+pp_data->cap[142]->LinkUsagePage                = 0xFF01
+pp_data->cap[142]->LinkUsage                    = 0x0080
+pp_data->cap[142]->IsMultipleItemsForArray      = 0
+pp_data->cap[142]->IsButtonCap                  = 0
+pp_data->cap[142]->IsPadding                    = 0
+pp_data->cap[142]->IsAbsolute                   = 1
+pp_data->cap[142]->IsRange                      = 0
+pp_data->cap[142]->IsAlias                      = 0
+pp_data->cap[142]->IsStringRange                = 0
+pp_data->cap[142]->IsDesignatorRange            = 0
+pp_data->cap[142]->Reserved1                    = 0x000000
+pp_data->cap[142]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[142]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[142]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[142]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[142]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[142]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[142]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[142]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[142]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[142]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[142]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[142]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[142]->NotRange.Usage                        = 0x0081
+pp_data->cap[142]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[142]->NotRange.StringIndex                  = 0
+pp_data->cap[142]->NotRange.Reserved2                    = 0
+pp_data->cap[142]->NotRange.DesignatorIndex              = 0
+pp_data->cap[142]->NotRange.Reserved3                    = 0
+pp_data->cap[142]->NotRange.DataIndex                    = 55
+pp_data->cap[142]->NotRange.Reserved4                    = 55
+pp_data->cap[142]->NotButton.HasNull                   = 0
+pp_data->cap[142]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[142]->NotButton.LogicalMin                = 0
+pp_data->cap[142]->NotButton.LogicalMax                = 127
+pp_data->cap[142]->NotButton.PhysicalMin               = 0
+pp_data->cap[142]->NotButton.PhysicalMax               = 0
+pp_data->cap[142]->Units                    = 0
+pp_data->cap[142]->UnitsExp                 = 0
+
+pp_data->cap[143]->UsagePage                    = 0xFF01
+pp_data->cap[143]->ReportID                     = 0x80
+pp_data->cap[143]->BitPosition                  = 0
+pp_data->cap[143]->BitSize                      = 8
+pp_data->cap[143]->ReportCount                  = 1
+pp_data->cap[143]->BytePosition                 = 0x0026
+pp_data->cap[143]->BitCount                     = 8
+pp_data->cap[143]->BitField                     = 0x02
+pp_data->cap[143]->NextBytePosition             = 0x0027
+pp_data->cap[143]->LinkCollection               = 0x0003
+pp_data->cap[143]->LinkUsagePage                = 0xFF01
+pp_data->cap[143]->LinkUsage                    = 0x0080
+pp_data->cap[143]->IsMultipleItemsForArray      = 0
+pp_data->cap[143]->IsButtonCap                  = 0
+pp_data->cap[143]->IsPadding                    = 0
+pp_data->cap[143]->IsAbsolute                   = 1
+pp_data->cap[143]->IsRange                      = 0
+pp_data->cap[143]->IsAlias                      = 0
+pp_data->cap[143]->IsStringRange                = 0
+pp_data->cap[143]->IsDesignatorRange            = 0
+pp_data->cap[143]->Reserved1                    = 0x000000
+pp_data->cap[143]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[143]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[143]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[143]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[143]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[143]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[143]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[143]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[143]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[143]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[143]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[143]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[143]->NotRange.Usage                        = 0x0081
+pp_data->cap[143]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[143]->NotRange.StringIndex                  = 0
+pp_data->cap[143]->NotRange.Reserved2                    = 0
+pp_data->cap[143]->NotRange.DesignatorIndex              = 0
+pp_data->cap[143]->NotRange.Reserved3                    = 0
+pp_data->cap[143]->NotRange.DataIndex                    = 56
+pp_data->cap[143]->NotRange.Reserved4                    = 56
+pp_data->cap[143]->NotButton.HasNull                   = 0
+pp_data->cap[143]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[143]->NotButton.LogicalMin                = 0
+pp_data->cap[143]->NotButton.LogicalMax                = 127
+pp_data->cap[143]->NotButton.PhysicalMin               = 0
+pp_data->cap[143]->NotButton.PhysicalMax               = 0
+pp_data->cap[143]->Units                    = 0
+pp_data->cap[143]->UnitsExp                 = 0
+
+pp_data->cap[144]->UsagePage                    = 0xFF01
+pp_data->cap[144]->ReportID                     = 0x80
+pp_data->cap[144]->BitPosition                  = 0
+pp_data->cap[144]->BitSize                      = 8
+pp_data->cap[144]->ReportCount                  = 1
+pp_data->cap[144]->BytePosition                 = 0x0025
+pp_data->cap[144]->BitCount                     = 8
+pp_data->cap[144]->BitField                     = 0x02
+pp_data->cap[144]->NextBytePosition             = 0x0026
+pp_data->cap[144]->LinkCollection               = 0x0003
+pp_data->cap[144]->LinkUsagePage                = 0xFF01
+pp_data->cap[144]->LinkUsage                    = 0x0080
+pp_data->cap[144]->IsMultipleItemsForArray      = 0
+pp_data->cap[144]->IsButtonCap                  = 0
+pp_data->cap[144]->IsPadding                    = 0
+pp_data->cap[144]->IsAbsolute                   = 1
+pp_data->cap[144]->IsRange                      = 0
+pp_data->cap[144]->IsAlias                      = 0
+pp_data->cap[144]->IsStringRange                = 0
+pp_data->cap[144]->IsDesignatorRange            = 0
+pp_data->cap[144]->Reserved1                    = 0x000000
+pp_data->cap[144]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[144]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[144]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[144]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[144]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[144]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[144]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[144]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[144]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[144]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[144]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[144]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[144]->NotRange.Usage                        = 0x0081
+pp_data->cap[144]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[144]->NotRange.StringIndex                  = 0
+pp_data->cap[144]->NotRange.Reserved2                    = 0
+pp_data->cap[144]->NotRange.DesignatorIndex              = 0
+pp_data->cap[144]->NotRange.Reserved3                    = 0
+pp_data->cap[144]->NotRange.DataIndex                    = 57
+pp_data->cap[144]->NotRange.Reserved4                    = 57
+pp_data->cap[144]->NotButton.HasNull                   = 0
+pp_data->cap[144]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[144]->NotButton.LogicalMin                = 0
+pp_data->cap[144]->NotButton.LogicalMax                = 127
+pp_data->cap[144]->NotButton.PhysicalMin               = 0
+pp_data->cap[144]->NotButton.PhysicalMax               = 0
+pp_data->cap[144]->Units                    = 0
+pp_data->cap[144]->UnitsExp                 = 0
+
+pp_data->cap[145]->UsagePage                    = 0xFF01
+pp_data->cap[145]->ReportID                     = 0x80
+pp_data->cap[145]->BitPosition                  = 0
+pp_data->cap[145]->BitSize                      = 8
+pp_data->cap[145]->ReportCount                  = 1
+pp_data->cap[145]->BytePosition                 = 0x0024
+pp_data->cap[145]->BitCount                     = 8
+pp_data->cap[145]->BitField                     = 0x02
+pp_data->cap[145]->NextBytePosition             = 0x0025
+pp_data->cap[145]->LinkCollection               = 0x0003
+pp_data->cap[145]->LinkUsagePage                = 0xFF01
+pp_data->cap[145]->LinkUsage                    = 0x0080
+pp_data->cap[145]->IsMultipleItemsForArray      = 0
+pp_data->cap[145]->IsButtonCap                  = 0
+pp_data->cap[145]->IsPadding                    = 0
+pp_data->cap[145]->IsAbsolute                   = 1
+pp_data->cap[145]->IsRange                      = 0
+pp_data->cap[145]->IsAlias                      = 0
+pp_data->cap[145]->IsStringRange                = 0
+pp_data->cap[145]->IsDesignatorRange            = 0
+pp_data->cap[145]->Reserved1                    = 0x000000
+pp_data->cap[145]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[145]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[145]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[145]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[145]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[145]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[145]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[145]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[145]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[145]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[145]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[145]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[145]->NotRange.Usage                        = 0x0081
+pp_data->cap[145]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[145]->NotRange.StringIndex                  = 0
+pp_data->cap[145]->NotRange.Reserved2                    = 0
+pp_data->cap[145]->NotRange.DesignatorIndex              = 0
+pp_data->cap[145]->NotRange.Reserved3                    = 0
+pp_data->cap[145]->NotRange.DataIndex                    = 58
+pp_data->cap[145]->NotRange.Reserved4                    = 58
+pp_data->cap[145]->NotButton.HasNull                   = 0
+pp_data->cap[145]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[145]->NotButton.LogicalMin                = 0
+pp_data->cap[145]->NotButton.LogicalMax                = 127
+pp_data->cap[145]->NotButton.PhysicalMin               = 0
+pp_data->cap[145]->NotButton.PhysicalMax               = 0
+pp_data->cap[145]->Units                    = 0
+pp_data->cap[145]->UnitsExp                 = 0
+
+pp_data->cap[146]->UsagePage                    = 0xFF01
+pp_data->cap[146]->ReportID                     = 0x80
+pp_data->cap[146]->BitPosition                  = 0
+pp_data->cap[146]->BitSize                      = 8
+pp_data->cap[146]->ReportCount                  = 1
+pp_data->cap[146]->BytePosition                 = 0x0023
+pp_data->cap[146]->BitCount                     = 8
+pp_data->cap[146]->BitField                     = 0x02
+pp_data->cap[146]->NextBytePosition             = 0x0024
+pp_data->cap[146]->LinkCollection               = 0x0003
+pp_data->cap[146]->LinkUsagePage                = 0xFF01
+pp_data->cap[146]->LinkUsage                    = 0x0080
+pp_data->cap[146]->IsMultipleItemsForArray      = 0
+pp_data->cap[146]->IsButtonCap                  = 0
+pp_data->cap[146]->IsPadding                    = 0
+pp_data->cap[146]->IsAbsolute                   = 1
+pp_data->cap[146]->IsRange                      = 0
+pp_data->cap[146]->IsAlias                      = 0
+pp_data->cap[146]->IsStringRange                = 0
+pp_data->cap[146]->IsDesignatorRange            = 0
+pp_data->cap[146]->Reserved1                    = 0x000000
+pp_data->cap[146]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[146]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[146]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[146]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[146]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[146]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[146]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[146]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[146]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[146]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[146]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[146]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[146]->NotRange.Usage                        = 0x0081
+pp_data->cap[146]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[146]->NotRange.StringIndex                  = 0
+pp_data->cap[146]->NotRange.Reserved2                    = 0
+pp_data->cap[146]->NotRange.DesignatorIndex              = 0
+pp_data->cap[146]->NotRange.Reserved3                    = 0
+pp_data->cap[146]->NotRange.DataIndex                    = 59
+pp_data->cap[146]->NotRange.Reserved4                    = 59
+pp_data->cap[146]->NotButton.HasNull                   = 0
+pp_data->cap[146]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[146]->NotButton.LogicalMin                = 0
+pp_data->cap[146]->NotButton.LogicalMax                = 127
+pp_data->cap[146]->NotButton.PhysicalMin               = 0
+pp_data->cap[146]->NotButton.PhysicalMax               = 0
+pp_data->cap[146]->Units                    = 0
+pp_data->cap[146]->UnitsExp                 = 0
+
+pp_data->cap[147]->UsagePage                    = 0xFF01
+pp_data->cap[147]->ReportID                     = 0x80
+pp_data->cap[147]->BitPosition                  = 0
+pp_data->cap[147]->BitSize                      = 8
+pp_data->cap[147]->ReportCount                  = 1
+pp_data->cap[147]->BytePosition                 = 0x0022
+pp_data->cap[147]->BitCount                     = 8
+pp_data->cap[147]->BitField                     = 0x02
+pp_data->cap[147]->NextBytePosition             = 0x0023
+pp_data->cap[147]->LinkCollection               = 0x0003
+pp_data->cap[147]->LinkUsagePage                = 0xFF01
+pp_data->cap[147]->LinkUsage                    = 0x0080
+pp_data->cap[147]->IsMultipleItemsForArray      = 0
+pp_data->cap[147]->IsButtonCap                  = 0
+pp_data->cap[147]->IsPadding                    = 0
+pp_data->cap[147]->IsAbsolute                   = 1
+pp_data->cap[147]->IsRange                      = 0
+pp_data->cap[147]->IsAlias                      = 0
+pp_data->cap[147]->IsStringRange                = 0
+pp_data->cap[147]->IsDesignatorRange            = 0
+pp_data->cap[147]->Reserved1                    = 0x000000
+pp_data->cap[147]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[147]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[147]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[147]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[147]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[147]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[147]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[147]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[147]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[147]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[147]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[147]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[147]->NotRange.Usage                        = 0x0081
+pp_data->cap[147]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[147]->NotRange.StringIndex                  = 0
+pp_data->cap[147]->NotRange.Reserved2                    = 0
+pp_data->cap[147]->NotRange.DesignatorIndex              = 0
+pp_data->cap[147]->NotRange.Reserved3                    = 0
+pp_data->cap[147]->NotRange.DataIndex                    = 60
+pp_data->cap[147]->NotRange.Reserved4                    = 60
+pp_data->cap[147]->NotButton.HasNull                   = 0
+pp_data->cap[147]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[147]->NotButton.LogicalMin                = 0
+pp_data->cap[147]->NotButton.LogicalMax                = 127
+pp_data->cap[147]->NotButton.PhysicalMin               = 0
+pp_data->cap[147]->NotButton.PhysicalMax               = 0
+pp_data->cap[147]->Units                    = 0
+pp_data->cap[147]->UnitsExp                 = 0
+
+pp_data->cap[148]->UsagePage                    = 0xFF01
+pp_data->cap[148]->ReportID                     = 0x80
+pp_data->cap[148]->BitPosition                  = 0
+pp_data->cap[148]->BitSize                      = 8
+pp_data->cap[148]->ReportCount                  = 1
+pp_data->cap[148]->BytePosition                 = 0x0021
+pp_data->cap[148]->BitCount                     = 8
+pp_data->cap[148]->BitField                     = 0x02
+pp_data->cap[148]->NextBytePosition             = 0x0022
+pp_data->cap[148]->LinkCollection               = 0x0003
+pp_data->cap[148]->LinkUsagePage                = 0xFF01
+pp_data->cap[148]->LinkUsage                    = 0x0080
+pp_data->cap[148]->IsMultipleItemsForArray      = 0
+pp_data->cap[148]->IsButtonCap                  = 0
+pp_data->cap[148]->IsPadding                    = 0
+pp_data->cap[148]->IsAbsolute                   = 1
+pp_data->cap[148]->IsRange                      = 0
+pp_data->cap[148]->IsAlias                      = 0
+pp_data->cap[148]->IsStringRange                = 0
+pp_data->cap[148]->IsDesignatorRange            = 0
+pp_data->cap[148]->Reserved1                    = 0x000000
+pp_data->cap[148]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[148]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[148]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[148]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[148]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[148]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[148]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[148]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[148]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[148]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[148]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[148]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[148]->NotRange.Usage                        = 0x0081
+pp_data->cap[148]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[148]->NotRange.StringIndex                  = 0
+pp_data->cap[148]->NotRange.Reserved2                    = 0
+pp_data->cap[148]->NotRange.DesignatorIndex              = 0
+pp_data->cap[148]->NotRange.Reserved3                    = 0
+pp_data->cap[148]->NotRange.DataIndex                    = 61
+pp_data->cap[148]->NotRange.Reserved4                    = 61
+pp_data->cap[148]->NotButton.HasNull                   = 0
+pp_data->cap[148]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[148]->NotButton.LogicalMin                = 0
+pp_data->cap[148]->NotButton.LogicalMax                = 127
+pp_data->cap[148]->NotButton.PhysicalMin               = 0
+pp_data->cap[148]->NotButton.PhysicalMax               = 0
+pp_data->cap[148]->Units                    = 0
+pp_data->cap[148]->UnitsExp                 = 0
+
+pp_data->cap[149]->UsagePage                    = 0xFF01
+pp_data->cap[149]->ReportID                     = 0x80
+pp_data->cap[149]->BitPosition                  = 0
+pp_data->cap[149]->BitSize                      = 8
+pp_data->cap[149]->ReportCount                  = 1
+pp_data->cap[149]->BytePosition                 = 0x0020
+pp_data->cap[149]->BitCount                     = 8
+pp_data->cap[149]->BitField                     = 0x02
+pp_data->cap[149]->NextBytePosition             = 0x0021
+pp_data->cap[149]->LinkCollection               = 0x0003
+pp_data->cap[149]->LinkUsagePage                = 0xFF01
+pp_data->cap[149]->LinkUsage                    = 0x0080
+pp_data->cap[149]->IsMultipleItemsForArray      = 0
+pp_data->cap[149]->IsButtonCap                  = 0
+pp_data->cap[149]->IsPadding                    = 0
+pp_data->cap[149]->IsAbsolute                   = 1
+pp_data->cap[149]->IsRange                      = 0
+pp_data->cap[149]->IsAlias                      = 0
+pp_data->cap[149]->IsStringRange                = 0
+pp_data->cap[149]->IsDesignatorRange            = 0
+pp_data->cap[149]->Reserved1                    = 0x000000
+pp_data->cap[149]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[149]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[149]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[149]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[149]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[149]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[149]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[149]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[149]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[149]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[149]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[149]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[149]->NotRange.Usage                        = 0x0081
+pp_data->cap[149]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[149]->NotRange.StringIndex                  = 0
+pp_data->cap[149]->NotRange.Reserved2                    = 0
+pp_data->cap[149]->NotRange.DesignatorIndex              = 0
+pp_data->cap[149]->NotRange.Reserved3                    = 0
+pp_data->cap[149]->NotRange.DataIndex                    = 62
+pp_data->cap[149]->NotRange.Reserved4                    = 62
+pp_data->cap[149]->NotButton.HasNull                   = 0
+pp_data->cap[149]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[149]->NotButton.LogicalMin                = 0
+pp_data->cap[149]->NotButton.LogicalMax                = 127
+pp_data->cap[149]->NotButton.PhysicalMin               = 0
+pp_data->cap[149]->NotButton.PhysicalMax               = 0
+pp_data->cap[149]->Units                    = 0
+pp_data->cap[149]->UnitsExp                 = 0
+
+pp_data->cap[150]->UsagePage                    = 0xFF01
+pp_data->cap[150]->ReportID                     = 0x80
+pp_data->cap[150]->BitPosition                  = 0
+pp_data->cap[150]->BitSize                      = 8
+pp_data->cap[150]->ReportCount                  = 1
+pp_data->cap[150]->BytePosition                 = 0x001F
+pp_data->cap[150]->BitCount                     = 8
+pp_data->cap[150]->BitField                     = 0x02
+pp_data->cap[150]->NextBytePosition             = 0x0020
+pp_data->cap[150]->LinkCollection               = 0x0003
+pp_data->cap[150]->LinkUsagePage                = 0xFF01
+pp_data->cap[150]->LinkUsage                    = 0x0080
+pp_data->cap[150]->IsMultipleItemsForArray      = 0
+pp_data->cap[150]->IsButtonCap                  = 0
+pp_data->cap[150]->IsPadding                    = 0
+pp_data->cap[150]->IsAbsolute                   = 1
+pp_data->cap[150]->IsRange                      = 0
+pp_data->cap[150]->IsAlias                      = 0
+pp_data->cap[150]->IsStringRange                = 0
+pp_data->cap[150]->IsDesignatorRange            = 0
+pp_data->cap[150]->Reserved1                    = 0x000000
+pp_data->cap[150]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[150]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[150]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[150]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[150]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[150]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[150]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[150]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[150]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[150]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[150]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[150]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[150]->NotRange.Usage                        = 0x0081
+pp_data->cap[150]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[150]->NotRange.StringIndex                  = 0
+pp_data->cap[150]->NotRange.Reserved2                    = 0
+pp_data->cap[150]->NotRange.DesignatorIndex              = 0
+pp_data->cap[150]->NotRange.Reserved3                    = 0
+pp_data->cap[150]->NotRange.DataIndex                    = 63
+pp_data->cap[150]->NotRange.Reserved4                    = 63
+pp_data->cap[150]->NotButton.HasNull                   = 0
+pp_data->cap[150]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[150]->NotButton.LogicalMin                = 0
+pp_data->cap[150]->NotButton.LogicalMax                = 127
+pp_data->cap[150]->NotButton.PhysicalMin               = 0
+pp_data->cap[150]->NotButton.PhysicalMax               = 0
+pp_data->cap[150]->Units                    = 0
+pp_data->cap[150]->UnitsExp                 = 0
+
+pp_data->cap[151]->UsagePage                    = 0xFF01
+pp_data->cap[151]->ReportID                     = 0x80
+pp_data->cap[151]->BitPosition                  = 0
+pp_data->cap[151]->BitSize                      = 8
+pp_data->cap[151]->ReportCount                  = 1
+pp_data->cap[151]->BytePosition                 = 0x001E
+pp_data->cap[151]->BitCount                     = 8
+pp_data->cap[151]->BitField                     = 0x02
+pp_data->cap[151]->NextBytePosition             = 0x001F
+pp_data->cap[151]->LinkCollection               = 0x0003
+pp_data->cap[151]->LinkUsagePage                = 0xFF01
+pp_data->cap[151]->LinkUsage                    = 0x0080
+pp_data->cap[151]->IsMultipleItemsForArray      = 0
+pp_data->cap[151]->IsButtonCap                  = 0
+pp_data->cap[151]->IsPadding                    = 0
+pp_data->cap[151]->IsAbsolute                   = 1
+pp_data->cap[151]->IsRange                      = 0
+pp_data->cap[151]->IsAlias                      = 0
+pp_data->cap[151]->IsStringRange                = 0
+pp_data->cap[151]->IsDesignatorRange            = 0
+pp_data->cap[151]->Reserved1                    = 0x000000
+pp_data->cap[151]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[151]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[151]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[151]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[151]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[151]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[151]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[151]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[151]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[151]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[151]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[151]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[151]->NotRange.Usage                        = 0x0081
+pp_data->cap[151]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[151]->NotRange.StringIndex                  = 0
+pp_data->cap[151]->NotRange.Reserved2                    = 0
+pp_data->cap[151]->NotRange.DesignatorIndex              = 0
+pp_data->cap[151]->NotRange.Reserved3                    = 0
+pp_data->cap[151]->NotRange.DataIndex                    = 64
+pp_data->cap[151]->NotRange.Reserved4                    = 64
+pp_data->cap[151]->NotButton.HasNull                   = 0
+pp_data->cap[151]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[151]->NotButton.LogicalMin                = 0
+pp_data->cap[151]->NotButton.LogicalMax                = 127
+pp_data->cap[151]->NotButton.PhysicalMin               = 0
+pp_data->cap[151]->NotButton.PhysicalMax               = 0
+pp_data->cap[151]->Units                    = 0
+pp_data->cap[151]->UnitsExp                 = 0
+
+pp_data->cap[152]->UsagePage                    = 0xFF01
+pp_data->cap[152]->ReportID                     = 0x80
+pp_data->cap[152]->BitPosition                  = 0
+pp_data->cap[152]->BitSize                      = 8
+pp_data->cap[152]->ReportCount                  = 1
+pp_data->cap[152]->BytePosition                 = 0x001D
+pp_data->cap[152]->BitCount                     = 8
+pp_data->cap[152]->BitField                     = 0x02
+pp_data->cap[152]->NextBytePosition             = 0x001E
+pp_data->cap[152]->LinkCollection               = 0x0003
+pp_data->cap[152]->LinkUsagePage                = 0xFF01
+pp_data->cap[152]->LinkUsage                    = 0x0080
+pp_data->cap[152]->IsMultipleItemsForArray      = 0
+pp_data->cap[152]->IsButtonCap                  = 0
+pp_data->cap[152]->IsPadding                    = 0
+pp_data->cap[152]->IsAbsolute                   = 1
+pp_data->cap[152]->IsRange                      = 0
+pp_data->cap[152]->IsAlias                      = 0
+pp_data->cap[152]->IsStringRange                = 0
+pp_data->cap[152]->IsDesignatorRange            = 0
+pp_data->cap[152]->Reserved1                    = 0x000000
+pp_data->cap[152]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[152]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[152]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[152]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[152]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[152]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[152]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[152]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[152]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[152]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[152]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[152]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[152]->NotRange.Usage                        = 0x0081
+pp_data->cap[152]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[152]->NotRange.StringIndex                  = 0
+pp_data->cap[152]->NotRange.Reserved2                    = 0
+pp_data->cap[152]->NotRange.DesignatorIndex              = 0
+pp_data->cap[152]->NotRange.Reserved3                    = 0
+pp_data->cap[152]->NotRange.DataIndex                    = 65
+pp_data->cap[152]->NotRange.Reserved4                    = 65
+pp_data->cap[152]->NotButton.HasNull                   = 0
+pp_data->cap[152]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[152]->NotButton.LogicalMin                = 0
+pp_data->cap[152]->NotButton.LogicalMax                = 127
+pp_data->cap[152]->NotButton.PhysicalMin               = 0
+pp_data->cap[152]->NotButton.PhysicalMax               = 0
+pp_data->cap[152]->Units                    = 0
+pp_data->cap[152]->UnitsExp                 = 0
+
+pp_data->cap[153]->UsagePage                    = 0xFF01
+pp_data->cap[153]->ReportID                     = 0x80
+pp_data->cap[153]->BitPosition                  = 0
+pp_data->cap[153]->BitSize                      = 8
+pp_data->cap[153]->ReportCount                  = 1
+pp_data->cap[153]->BytePosition                 = 0x001C
+pp_data->cap[153]->BitCount                     = 8
+pp_data->cap[153]->BitField                     = 0x02
+pp_data->cap[153]->NextBytePosition             = 0x001D
+pp_data->cap[153]->LinkCollection               = 0x0003
+pp_data->cap[153]->LinkUsagePage                = 0xFF01
+pp_data->cap[153]->LinkUsage                    = 0x0080
+pp_data->cap[153]->IsMultipleItemsForArray      = 0
+pp_data->cap[153]->IsButtonCap                  = 0
+pp_data->cap[153]->IsPadding                    = 0
+pp_data->cap[153]->IsAbsolute                   = 1
+pp_data->cap[153]->IsRange                      = 0
+pp_data->cap[153]->IsAlias                      = 0
+pp_data->cap[153]->IsStringRange                = 0
+pp_data->cap[153]->IsDesignatorRange            = 0
+pp_data->cap[153]->Reserved1                    = 0x000000
+pp_data->cap[153]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[153]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[153]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[153]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[153]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[153]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[153]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[153]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[153]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[153]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[153]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[153]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[153]->NotRange.Usage                        = 0x0081
+pp_data->cap[153]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[153]->NotRange.StringIndex                  = 0
+pp_data->cap[153]->NotRange.Reserved2                    = 0
+pp_data->cap[153]->NotRange.DesignatorIndex              = 0
+pp_data->cap[153]->NotRange.Reserved3                    = 0
+pp_data->cap[153]->NotRange.DataIndex                    = 66
+pp_data->cap[153]->NotRange.Reserved4                    = 66
+pp_data->cap[153]->NotButton.HasNull                   = 0
+pp_data->cap[153]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[153]->NotButton.LogicalMin                = 0
+pp_data->cap[153]->NotButton.LogicalMax                = 127
+pp_data->cap[153]->NotButton.PhysicalMin               = 0
+pp_data->cap[153]->NotButton.PhysicalMax               = 0
+pp_data->cap[153]->Units                    = 0
+pp_data->cap[153]->UnitsExp                 = 0
+
+pp_data->cap[154]->UsagePage                    = 0xFF01
+pp_data->cap[154]->ReportID                     = 0x80
+pp_data->cap[154]->BitPosition                  = 0
+pp_data->cap[154]->BitSize                      = 8
+pp_data->cap[154]->ReportCount                  = 1
+pp_data->cap[154]->BytePosition                 = 0x001B
+pp_data->cap[154]->BitCount                     = 8
+pp_data->cap[154]->BitField                     = 0x02
+pp_data->cap[154]->NextBytePosition             = 0x001C
+pp_data->cap[154]->LinkCollection               = 0x0003
+pp_data->cap[154]->LinkUsagePage                = 0xFF01
+pp_data->cap[154]->LinkUsage                    = 0x0080
+pp_data->cap[154]->IsMultipleItemsForArray      = 0
+pp_data->cap[154]->IsButtonCap                  = 0
+pp_data->cap[154]->IsPadding                    = 0
+pp_data->cap[154]->IsAbsolute                   = 1
+pp_data->cap[154]->IsRange                      = 0
+pp_data->cap[154]->IsAlias                      = 0
+pp_data->cap[154]->IsStringRange                = 0
+pp_data->cap[154]->IsDesignatorRange            = 0
+pp_data->cap[154]->Reserved1                    = 0x000000
+pp_data->cap[154]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[154]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[154]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[154]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[154]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[154]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[154]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[154]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[154]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[154]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[154]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[154]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[154]->NotRange.Usage                        = 0x0081
+pp_data->cap[154]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[154]->NotRange.StringIndex                  = 0
+pp_data->cap[154]->NotRange.Reserved2                    = 0
+pp_data->cap[154]->NotRange.DesignatorIndex              = 0
+pp_data->cap[154]->NotRange.Reserved3                    = 0
+pp_data->cap[154]->NotRange.DataIndex                    = 67
+pp_data->cap[154]->NotRange.Reserved4                    = 67
+pp_data->cap[154]->NotButton.HasNull                   = 0
+pp_data->cap[154]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[154]->NotButton.LogicalMin                = 0
+pp_data->cap[154]->NotButton.LogicalMax                = 127
+pp_data->cap[154]->NotButton.PhysicalMin               = 0
+pp_data->cap[154]->NotButton.PhysicalMax               = 0
+pp_data->cap[154]->Units                    = 0
+pp_data->cap[154]->UnitsExp                 = 0
+
+pp_data->cap[155]->UsagePage                    = 0xFF01
+pp_data->cap[155]->ReportID                     = 0x80
+pp_data->cap[155]->BitPosition                  = 0
+pp_data->cap[155]->BitSize                      = 8
+pp_data->cap[155]->ReportCount                  = 1
+pp_data->cap[155]->BytePosition                 = 0x001A
+pp_data->cap[155]->BitCount                     = 8
+pp_data->cap[155]->BitField                     = 0x02
+pp_data->cap[155]->NextBytePosition             = 0x001B
+pp_data->cap[155]->LinkCollection               = 0x0003
+pp_data->cap[155]->LinkUsagePage                = 0xFF01
+pp_data->cap[155]->LinkUsage                    = 0x0080
+pp_data->cap[155]->IsMultipleItemsForArray      = 0
+pp_data->cap[155]->IsButtonCap                  = 0
+pp_data->cap[155]->IsPadding                    = 0
+pp_data->cap[155]->IsAbsolute                   = 1
+pp_data->cap[155]->IsRange                      = 0
+pp_data->cap[155]->IsAlias                      = 0
+pp_data->cap[155]->IsStringRange                = 0
+pp_data->cap[155]->IsDesignatorRange            = 0
+pp_data->cap[155]->Reserved1                    = 0x000000
+pp_data->cap[155]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[155]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[155]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[155]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[155]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[155]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[155]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[155]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[155]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[155]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[155]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[155]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[155]->NotRange.Usage                        = 0x0081
+pp_data->cap[155]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[155]->NotRange.StringIndex                  = 0
+pp_data->cap[155]->NotRange.Reserved2                    = 0
+pp_data->cap[155]->NotRange.DesignatorIndex              = 0
+pp_data->cap[155]->NotRange.Reserved3                    = 0
+pp_data->cap[155]->NotRange.DataIndex                    = 68
+pp_data->cap[155]->NotRange.Reserved4                    = 68
+pp_data->cap[155]->NotButton.HasNull                   = 0
+pp_data->cap[155]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[155]->NotButton.LogicalMin                = 0
+pp_data->cap[155]->NotButton.LogicalMax                = 127
+pp_data->cap[155]->NotButton.PhysicalMin               = 0
+pp_data->cap[155]->NotButton.PhysicalMax               = 0
+pp_data->cap[155]->Units                    = 0
+pp_data->cap[155]->UnitsExp                 = 0
+
+pp_data->cap[156]->UsagePage                    = 0xFF01
+pp_data->cap[156]->ReportID                     = 0x80
+pp_data->cap[156]->BitPosition                  = 0
+pp_data->cap[156]->BitSize                      = 8
+pp_data->cap[156]->ReportCount                  = 1
+pp_data->cap[156]->BytePosition                 = 0x0019
+pp_data->cap[156]->BitCount                     = 8
+pp_data->cap[156]->BitField                     = 0x02
+pp_data->cap[156]->NextBytePosition             = 0x001A
+pp_data->cap[156]->LinkCollection               = 0x0003
+pp_data->cap[156]->LinkUsagePage                = 0xFF01
+pp_data->cap[156]->LinkUsage                    = 0x0080
+pp_data->cap[156]->IsMultipleItemsForArray      = 0
+pp_data->cap[156]->IsButtonCap                  = 0
+pp_data->cap[156]->IsPadding                    = 0
+pp_data->cap[156]->IsAbsolute                   = 1
+pp_data->cap[156]->IsRange                      = 0
+pp_data->cap[156]->IsAlias                      = 0
+pp_data->cap[156]->IsStringRange                = 0
+pp_data->cap[156]->IsDesignatorRange            = 0
+pp_data->cap[156]->Reserved1                    = 0x000000
+pp_data->cap[156]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[156]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[156]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[156]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[156]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[156]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[156]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[156]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[156]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[156]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[156]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[156]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[156]->NotRange.Usage                        = 0x0081
+pp_data->cap[156]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[156]->NotRange.StringIndex                  = 0
+pp_data->cap[156]->NotRange.Reserved2                    = 0
+pp_data->cap[156]->NotRange.DesignatorIndex              = 0
+pp_data->cap[156]->NotRange.Reserved3                    = 0
+pp_data->cap[156]->NotRange.DataIndex                    = 69
+pp_data->cap[156]->NotRange.Reserved4                    = 69
+pp_data->cap[156]->NotButton.HasNull                   = 0
+pp_data->cap[156]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[156]->NotButton.LogicalMin                = 0
+pp_data->cap[156]->NotButton.LogicalMax                = 127
+pp_data->cap[156]->NotButton.PhysicalMin               = 0
+pp_data->cap[156]->NotButton.PhysicalMax               = 0
+pp_data->cap[156]->Units                    = 0
+pp_data->cap[156]->UnitsExp                 = 0
+
+pp_data->cap[157]->UsagePage                    = 0xFF01
+pp_data->cap[157]->ReportID                     = 0x80
+pp_data->cap[157]->BitPosition                  = 0
+pp_data->cap[157]->BitSize                      = 8
+pp_data->cap[157]->ReportCount                  = 1
+pp_data->cap[157]->BytePosition                 = 0x0018
+pp_data->cap[157]->BitCount                     = 8
+pp_data->cap[157]->BitField                     = 0x02
+pp_data->cap[157]->NextBytePosition             = 0x0019
+pp_data->cap[157]->LinkCollection               = 0x0003
+pp_data->cap[157]->LinkUsagePage                = 0xFF01
+pp_data->cap[157]->LinkUsage                    = 0x0080
+pp_data->cap[157]->IsMultipleItemsForArray      = 0
+pp_data->cap[157]->IsButtonCap                  = 0
+pp_data->cap[157]->IsPadding                    = 0
+pp_data->cap[157]->IsAbsolute                   = 1
+pp_data->cap[157]->IsRange                      = 0
+pp_data->cap[157]->IsAlias                      = 0
+pp_data->cap[157]->IsStringRange                = 0
+pp_data->cap[157]->IsDesignatorRange            = 0
+pp_data->cap[157]->Reserved1                    = 0x000000
+pp_data->cap[157]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[157]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[157]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[157]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[157]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[157]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[157]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[157]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[157]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[157]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[157]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[157]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[157]->NotRange.Usage                        = 0x0081
+pp_data->cap[157]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[157]->NotRange.StringIndex                  = 0
+pp_data->cap[157]->NotRange.Reserved2                    = 0
+pp_data->cap[157]->NotRange.DesignatorIndex              = 0
+pp_data->cap[157]->NotRange.Reserved3                    = 0
+pp_data->cap[157]->NotRange.DataIndex                    = 70
+pp_data->cap[157]->NotRange.Reserved4                    = 70
+pp_data->cap[157]->NotButton.HasNull                   = 0
+pp_data->cap[157]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[157]->NotButton.LogicalMin                = 0
+pp_data->cap[157]->NotButton.LogicalMax                = 127
+pp_data->cap[157]->NotButton.PhysicalMin               = 0
+pp_data->cap[157]->NotButton.PhysicalMax               = 0
+pp_data->cap[157]->Units                    = 0
+pp_data->cap[157]->UnitsExp                 = 0
+
+pp_data->cap[158]->UsagePage                    = 0xFF01
+pp_data->cap[158]->ReportID                     = 0x80
+pp_data->cap[158]->BitPosition                  = 0
+pp_data->cap[158]->BitSize                      = 8
+pp_data->cap[158]->ReportCount                  = 1
+pp_data->cap[158]->BytePosition                 = 0x0017
+pp_data->cap[158]->BitCount                     = 8
+pp_data->cap[158]->BitField                     = 0x02
+pp_data->cap[158]->NextBytePosition             = 0x0018
+pp_data->cap[158]->LinkCollection               = 0x0003
+pp_data->cap[158]->LinkUsagePage                = 0xFF01
+pp_data->cap[158]->LinkUsage                    = 0x0080
+pp_data->cap[158]->IsMultipleItemsForArray      = 0
+pp_data->cap[158]->IsButtonCap                  = 0
+pp_data->cap[158]->IsPadding                    = 0
+pp_data->cap[158]->IsAbsolute                   = 1
+pp_data->cap[158]->IsRange                      = 0
+pp_data->cap[158]->IsAlias                      = 0
+pp_data->cap[158]->IsStringRange                = 0
+pp_data->cap[158]->IsDesignatorRange            = 0
+pp_data->cap[158]->Reserved1                    = 0x000000
+pp_data->cap[158]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[158]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[158]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[158]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[158]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[158]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[158]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[158]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[158]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[158]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[158]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[158]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[158]->NotRange.Usage                        = 0x0081
+pp_data->cap[158]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[158]->NotRange.StringIndex                  = 0
+pp_data->cap[158]->NotRange.Reserved2                    = 0
+pp_data->cap[158]->NotRange.DesignatorIndex              = 0
+pp_data->cap[158]->NotRange.Reserved3                    = 0
+pp_data->cap[158]->NotRange.DataIndex                    = 71
+pp_data->cap[158]->NotRange.Reserved4                    = 71
+pp_data->cap[158]->NotButton.HasNull                   = 0
+pp_data->cap[158]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[158]->NotButton.LogicalMin                = 0
+pp_data->cap[158]->NotButton.LogicalMax                = 127
+pp_data->cap[158]->NotButton.PhysicalMin               = 0
+pp_data->cap[158]->NotButton.PhysicalMax               = 0
+pp_data->cap[158]->Units                    = 0
+pp_data->cap[158]->UnitsExp                 = 0
+
+pp_data->cap[159]->UsagePage                    = 0xFF01
+pp_data->cap[159]->ReportID                     = 0x80
+pp_data->cap[159]->BitPosition                  = 0
+pp_data->cap[159]->BitSize                      = 8
+pp_data->cap[159]->ReportCount                  = 1
+pp_data->cap[159]->BytePosition                 = 0x0016
+pp_data->cap[159]->BitCount                     = 8
+pp_data->cap[159]->BitField                     = 0x02
+pp_data->cap[159]->NextBytePosition             = 0x0017
+pp_data->cap[159]->LinkCollection               = 0x0003
+pp_data->cap[159]->LinkUsagePage                = 0xFF01
+pp_data->cap[159]->LinkUsage                    = 0x0080
+pp_data->cap[159]->IsMultipleItemsForArray      = 0
+pp_data->cap[159]->IsButtonCap                  = 0
+pp_data->cap[159]->IsPadding                    = 0
+pp_data->cap[159]->IsAbsolute                   = 1
+pp_data->cap[159]->IsRange                      = 0
+pp_data->cap[159]->IsAlias                      = 0
+pp_data->cap[159]->IsStringRange                = 0
+pp_data->cap[159]->IsDesignatorRange            = 0
+pp_data->cap[159]->Reserved1                    = 0x000000
+pp_data->cap[159]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[159]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[159]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[159]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[159]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[159]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[159]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[159]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[159]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[159]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[159]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[159]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[159]->NotRange.Usage                        = 0x0081
+pp_data->cap[159]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[159]->NotRange.StringIndex                  = 0
+pp_data->cap[159]->NotRange.Reserved2                    = 0
+pp_data->cap[159]->NotRange.DesignatorIndex              = 0
+pp_data->cap[159]->NotRange.Reserved3                    = 0
+pp_data->cap[159]->NotRange.DataIndex                    = 72
+pp_data->cap[159]->NotRange.Reserved4                    = 72
+pp_data->cap[159]->NotButton.HasNull                   = 0
+pp_data->cap[159]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[159]->NotButton.LogicalMin                = 0
+pp_data->cap[159]->NotButton.LogicalMax                = 127
+pp_data->cap[159]->NotButton.PhysicalMin               = 0
+pp_data->cap[159]->NotButton.PhysicalMax               = 0
+pp_data->cap[159]->Units                    = 0
+pp_data->cap[159]->UnitsExp                 = 0
+
+pp_data->cap[160]->UsagePage                    = 0xFF01
+pp_data->cap[160]->ReportID                     = 0x80
+pp_data->cap[160]->BitPosition                  = 0
+pp_data->cap[160]->BitSize                      = 8
+pp_data->cap[160]->ReportCount                  = 1
+pp_data->cap[160]->BytePosition                 = 0x0015
+pp_data->cap[160]->BitCount                     = 8
+pp_data->cap[160]->BitField                     = 0x02
+pp_data->cap[160]->NextBytePosition             = 0x0016
+pp_data->cap[160]->LinkCollection               = 0x0003
+pp_data->cap[160]->LinkUsagePage                = 0xFF01
+pp_data->cap[160]->LinkUsage                    = 0x0080
+pp_data->cap[160]->IsMultipleItemsForArray      = 0
+pp_data->cap[160]->IsButtonCap                  = 0
+pp_data->cap[160]->IsPadding                    = 0
+pp_data->cap[160]->IsAbsolute                   = 1
+pp_data->cap[160]->IsRange                      = 0
+pp_data->cap[160]->IsAlias                      = 0
+pp_data->cap[160]->IsStringRange                = 0
+pp_data->cap[160]->IsDesignatorRange            = 0
+pp_data->cap[160]->Reserved1                    = 0x000000
+pp_data->cap[160]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[160]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[160]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[160]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[160]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[160]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[160]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[160]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[160]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[160]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[160]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[160]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[160]->NotRange.Usage                        = 0x0081
+pp_data->cap[160]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[160]->NotRange.StringIndex                  = 0
+pp_data->cap[160]->NotRange.Reserved2                    = 0
+pp_data->cap[160]->NotRange.DesignatorIndex              = 0
+pp_data->cap[160]->NotRange.Reserved3                    = 0
+pp_data->cap[160]->NotRange.DataIndex                    = 73
+pp_data->cap[160]->NotRange.Reserved4                    = 73
+pp_data->cap[160]->NotButton.HasNull                   = 0
+pp_data->cap[160]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[160]->NotButton.LogicalMin                = 0
+pp_data->cap[160]->NotButton.LogicalMax                = 127
+pp_data->cap[160]->NotButton.PhysicalMin               = 0
+pp_data->cap[160]->NotButton.PhysicalMax               = 0
+pp_data->cap[160]->Units                    = 0
+pp_data->cap[160]->UnitsExp                 = 0
+
+pp_data->cap[161]->UsagePage                    = 0xFF01
+pp_data->cap[161]->ReportID                     = 0x80
+pp_data->cap[161]->BitPosition                  = 0
+pp_data->cap[161]->BitSize                      = 8
+pp_data->cap[161]->ReportCount                  = 1
+pp_data->cap[161]->BytePosition                 = 0x0014
+pp_data->cap[161]->BitCount                     = 8
+pp_data->cap[161]->BitField                     = 0x02
+pp_data->cap[161]->NextBytePosition             = 0x0015
+pp_data->cap[161]->LinkCollection               = 0x0003
+pp_data->cap[161]->LinkUsagePage                = 0xFF01
+pp_data->cap[161]->LinkUsage                    = 0x0080
+pp_data->cap[161]->IsMultipleItemsForArray      = 0
+pp_data->cap[161]->IsButtonCap                  = 0
+pp_data->cap[161]->IsPadding                    = 0
+pp_data->cap[161]->IsAbsolute                   = 1
+pp_data->cap[161]->IsRange                      = 0
+pp_data->cap[161]->IsAlias                      = 0
+pp_data->cap[161]->IsStringRange                = 0
+pp_data->cap[161]->IsDesignatorRange            = 0
+pp_data->cap[161]->Reserved1                    = 0x000000
+pp_data->cap[161]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[161]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[161]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[161]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[161]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[161]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[161]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[161]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[161]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[161]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[161]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[161]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[161]->NotRange.Usage                        = 0x0081
+pp_data->cap[161]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[161]->NotRange.StringIndex                  = 0
+pp_data->cap[161]->NotRange.Reserved2                    = 0
+pp_data->cap[161]->NotRange.DesignatorIndex              = 0
+pp_data->cap[161]->NotRange.Reserved3                    = 0
+pp_data->cap[161]->NotRange.DataIndex                    = 74
+pp_data->cap[161]->NotRange.Reserved4                    = 74
+pp_data->cap[161]->NotButton.HasNull                   = 0
+pp_data->cap[161]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[161]->NotButton.LogicalMin                = 0
+pp_data->cap[161]->NotButton.LogicalMax                = 127
+pp_data->cap[161]->NotButton.PhysicalMin               = 0
+pp_data->cap[161]->NotButton.PhysicalMax               = 0
+pp_data->cap[161]->Units                    = 0
+pp_data->cap[161]->UnitsExp                 = 0
+
+pp_data->cap[162]->UsagePage                    = 0xFF01
+pp_data->cap[162]->ReportID                     = 0x80
+pp_data->cap[162]->BitPosition                  = 0
+pp_data->cap[162]->BitSize                      = 8
+pp_data->cap[162]->ReportCount                  = 1
+pp_data->cap[162]->BytePosition                 = 0x0013
+pp_data->cap[162]->BitCount                     = 8
+pp_data->cap[162]->BitField                     = 0x02
+pp_data->cap[162]->NextBytePosition             = 0x0014
+pp_data->cap[162]->LinkCollection               = 0x0003
+pp_data->cap[162]->LinkUsagePage                = 0xFF01
+pp_data->cap[162]->LinkUsage                    = 0x0080
+pp_data->cap[162]->IsMultipleItemsForArray      = 0
+pp_data->cap[162]->IsButtonCap                  = 0
+pp_data->cap[162]->IsPadding                    = 0
+pp_data->cap[162]->IsAbsolute                   = 1
+pp_data->cap[162]->IsRange                      = 0
+pp_data->cap[162]->IsAlias                      = 0
+pp_data->cap[162]->IsStringRange                = 0
+pp_data->cap[162]->IsDesignatorRange            = 0
+pp_data->cap[162]->Reserved1                    = 0x000000
+pp_data->cap[162]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[162]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[162]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[162]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[162]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[162]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[162]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[162]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[162]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[162]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[162]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[162]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[162]->NotRange.Usage                        = 0x0081
+pp_data->cap[162]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[162]->NotRange.StringIndex                  = 0
+pp_data->cap[162]->NotRange.Reserved2                    = 0
+pp_data->cap[162]->NotRange.DesignatorIndex              = 0
+pp_data->cap[162]->NotRange.Reserved3                    = 0
+pp_data->cap[162]->NotRange.DataIndex                    = 75
+pp_data->cap[162]->NotRange.Reserved4                    = 75
+pp_data->cap[162]->NotButton.HasNull                   = 0
+pp_data->cap[162]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[162]->NotButton.LogicalMin                = 0
+pp_data->cap[162]->NotButton.LogicalMax                = 127
+pp_data->cap[162]->NotButton.PhysicalMin               = 0
+pp_data->cap[162]->NotButton.PhysicalMax               = 0
+pp_data->cap[162]->Units                    = 0
+pp_data->cap[162]->UnitsExp                 = 0
+
+pp_data->cap[163]->UsagePage                    = 0xFF01
+pp_data->cap[163]->ReportID                     = 0x80
+pp_data->cap[163]->BitPosition                  = 0
+pp_data->cap[163]->BitSize                      = 8
+pp_data->cap[163]->ReportCount                  = 1
+pp_data->cap[163]->BytePosition                 = 0x0012
+pp_data->cap[163]->BitCount                     = 8
+pp_data->cap[163]->BitField                     = 0x02
+pp_data->cap[163]->NextBytePosition             = 0x0013
+pp_data->cap[163]->LinkCollection               = 0x0003
+pp_data->cap[163]->LinkUsagePage                = 0xFF01
+pp_data->cap[163]->LinkUsage                    = 0x0080
+pp_data->cap[163]->IsMultipleItemsForArray      = 0
+pp_data->cap[163]->IsButtonCap                  = 0
+pp_data->cap[163]->IsPadding                    = 0
+pp_data->cap[163]->IsAbsolute                   = 1
+pp_data->cap[163]->IsRange                      = 0
+pp_data->cap[163]->IsAlias                      = 0
+pp_data->cap[163]->IsStringRange                = 0
+pp_data->cap[163]->IsDesignatorRange            = 0
+pp_data->cap[163]->Reserved1                    = 0x000000
+pp_data->cap[163]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[163]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[163]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[163]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[163]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[163]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[163]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[163]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[163]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[163]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[163]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[163]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[163]->NotRange.Usage                        = 0x0081
+pp_data->cap[163]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[163]->NotRange.StringIndex                  = 0
+pp_data->cap[163]->NotRange.Reserved2                    = 0
+pp_data->cap[163]->NotRange.DesignatorIndex              = 0
+pp_data->cap[163]->NotRange.Reserved3                    = 0
+pp_data->cap[163]->NotRange.DataIndex                    = 76
+pp_data->cap[163]->NotRange.Reserved4                    = 76
+pp_data->cap[163]->NotButton.HasNull                   = 0
+pp_data->cap[163]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[163]->NotButton.LogicalMin                = 0
+pp_data->cap[163]->NotButton.LogicalMax                = 127
+pp_data->cap[163]->NotButton.PhysicalMin               = 0
+pp_data->cap[163]->NotButton.PhysicalMax               = 0
+pp_data->cap[163]->Units                    = 0
+pp_data->cap[163]->UnitsExp                 = 0
+
+pp_data->cap[164]->UsagePage                    = 0xFF01
+pp_data->cap[164]->ReportID                     = 0x80
+pp_data->cap[164]->BitPosition                  = 0
+pp_data->cap[164]->BitSize                      = 8
+pp_data->cap[164]->ReportCount                  = 1
+pp_data->cap[164]->BytePosition                 = 0x0011
+pp_data->cap[164]->BitCount                     = 8
+pp_data->cap[164]->BitField                     = 0x02
+pp_data->cap[164]->NextBytePosition             = 0x0012
+pp_data->cap[164]->LinkCollection               = 0x0003
+pp_data->cap[164]->LinkUsagePage                = 0xFF01
+pp_data->cap[164]->LinkUsage                    = 0x0080
+pp_data->cap[164]->IsMultipleItemsForArray      = 0
+pp_data->cap[164]->IsButtonCap                  = 0
+pp_data->cap[164]->IsPadding                    = 0
+pp_data->cap[164]->IsAbsolute                   = 1
+pp_data->cap[164]->IsRange                      = 0
+pp_data->cap[164]->IsAlias                      = 0
+pp_data->cap[164]->IsStringRange                = 0
+pp_data->cap[164]->IsDesignatorRange            = 0
+pp_data->cap[164]->Reserved1                    = 0x000000
+pp_data->cap[164]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[164]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[164]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[164]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[164]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[164]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[164]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[164]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[164]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[164]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[164]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[164]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[164]->NotRange.Usage                        = 0x0081
+pp_data->cap[164]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[164]->NotRange.StringIndex                  = 0
+pp_data->cap[164]->NotRange.Reserved2                    = 0
+pp_data->cap[164]->NotRange.DesignatorIndex              = 0
+pp_data->cap[164]->NotRange.Reserved3                    = 0
+pp_data->cap[164]->NotRange.DataIndex                    = 77
+pp_data->cap[164]->NotRange.Reserved4                    = 77
+pp_data->cap[164]->NotButton.HasNull                   = 0
+pp_data->cap[164]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[164]->NotButton.LogicalMin                = 0
+pp_data->cap[164]->NotButton.LogicalMax                = 127
+pp_data->cap[164]->NotButton.PhysicalMin               = 0
+pp_data->cap[164]->NotButton.PhysicalMax               = 0
+pp_data->cap[164]->Units                    = 0
+pp_data->cap[164]->UnitsExp                 = 0
+
+pp_data->cap[165]->UsagePage                    = 0xFF01
+pp_data->cap[165]->ReportID                     = 0x80
+pp_data->cap[165]->BitPosition                  = 0
+pp_data->cap[165]->BitSize                      = 8
+pp_data->cap[165]->ReportCount                  = 1
+pp_data->cap[165]->BytePosition                 = 0x0010
+pp_data->cap[165]->BitCount                     = 8
+pp_data->cap[165]->BitField                     = 0x02
+pp_data->cap[165]->NextBytePosition             = 0x0011
+pp_data->cap[165]->LinkCollection               = 0x0003
+pp_data->cap[165]->LinkUsagePage                = 0xFF01
+pp_data->cap[165]->LinkUsage                    = 0x0080
+pp_data->cap[165]->IsMultipleItemsForArray      = 0
+pp_data->cap[165]->IsButtonCap                  = 0
+pp_data->cap[165]->IsPadding                    = 0
+pp_data->cap[165]->IsAbsolute                   = 1
+pp_data->cap[165]->IsRange                      = 0
+pp_data->cap[165]->IsAlias                      = 0
+pp_data->cap[165]->IsStringRange                = 0
+pp_data->cap[165]->IsDesignatorRange            = 0
+pp_data->cap[165]->Reserved1                    = 0x000000
+pp_data->cap[165]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[165]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[165]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[165]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[165]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[165]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[165]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[165]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[165]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[165]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[165]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[165]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[165]->NotRange.Usage                        = 0x0081
+pp_data->cap[165]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[165]->NotRange.StringIndex                  = 0
+pp_data->cap[165]->NotRange.Reserved2                    = 0
+pp_data->cap[165]->NotRange.DesignatorIndex              = 0
+pp_data->cap[165]->NotRange.Reserved3                    = 0
+pp_data->cap[165]->NotRange.DataIndex                    = 78
+pp_data->cap[165]->NotRange.Reserved4                    = 78
+pp_data->cap[165]->NotButton.HasNull                   = 0
+pp_data->cap[165]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[165]->NotButton.LogicalMin                = 0
+pp_data->cap[165]->NotButton.LogicalMax                = 127
+pp_data->cap[165]->NotButton.PhysicalMin               = 0
+pp_data->cap[165]->NotButton.PhysicalMax               = 0
+pp_data->cap[165]->Units                    = 0
+pp_data->cap[165]->UnitsExp                 = 0
+
+pp_data->cap[166]->UsagePage                    = 0xFF01
+pp_data->cap[166]->ReportID                     = 0x80
+pp_data->cap[166]->BitPosition                  = 0
+pp_data->cap[166]->BitSize                      = 8
+pp_data->cap[166]->ReportCount                  = 1
+pp_data->cap[166]->BytePosition                 = 0x000F
+pp_data->cap[166]->BitCount                     = 8
+pp_data->cap[166]->BitField                     = 0x02
+pp_data->cap[166]->NextBytePosition             = 0x0010
+pp_data->cap[166]->LinkCollection               = 0x0003
+pp_data->cap[166]->LinkUsagePage                = 0xFF01
+pp_data->cap[166]->LinkUsage                    = 0x0080
+pp_data->cap[166]->IsMultipleItemsForArray      = 0
+pp_data->cap[166]->IsButtonCap                  = 0
+pp_data->cap[166]->IsPadding                    = 0
+pp_data->cap[166]->IsAbsolute                   = 1
+pp_data->cap[166]->IsRange                      = 0
+pp_data->cap[166]->IsAlias                      = 0
+pp_data->cap[166]->IsStringRange                = 0
+pp_data->cap[166]->IsDesignatorRange            = 0
+pp_data->cap[166]->Reserved1                    = 0x000000
+pp_data->cap[166]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[166]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[166]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[166]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[166]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[166]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[166]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[166]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[166]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[166]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[166]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[166]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[166]->NotRange.Usage                        = 0x0081
+pp_data->cap[166]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[166]->NotRange.StringIndex                  = 0
+pp_data->cap[166]->NotRange.Reserved2                    = 0
+pp_data->cap[166]->NotRange.DesignatorIndex              = 0
+pp_data->cap[166]->NotRange.Reserved3                    = 0
+pp_data->cap[166]->NotRange.DataIndex                    = 79
+pp_data->cap[166]->NotRange.Reserved4                    = 79
+pp_data->cap[166]->NotButton.HasNull                   = 0
+pp_data->cap[166]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[166]->NotButton.LogicalMin                = 0
+pp_data->cap[166]->NotButton.LogicalMax                = 127
+pp_data->cap[166]->NotButton.PhysicalMin               = 0
+pp_data->cap[166]->NotButton.PhysicalMax               = 0
+pp_data->cap[166]->Units                    = 0
+pp_data->cap[166]->UnitsExp                 = 0
+
+pp_data->cap[167]->UsagePage                    = 0xFF01
+pp_data->cap[167]->ReportID                     = 0x80
+pp_data->cap[167]->BitPosition                  = 0
+pp_data->cap[167]->BitSize                      = 8
+pp_data->cap[167]->ReportCount                  = 1
+pp_data->cap[167]->BytePosition                 = 0x000E
+pp_data->cap[167]->BitCount                     = 8
+pp_data->cap[167]->BitField                     = 0x02
+pp_data->cap[167]->NextBytePosition             = 0x000F
+pp_data->cap[167]->LinkCollection               = 0x0003
+pp_data->cap[167]->LinkUsagePage                = 0xFF01
+pp_data->cap[167]->LinkUsage                    = 0x0080
+pp_data->cap[167]->IsMultipleItemsForArray      = 0
+pp_data->cap[167]->IsButtonCap                  = 0
+pp_data->cap[167]->IsPadding                    = 0
+pp_data->cap[167]->IsAbsolute                   = 1
+pp_data->cap[167]->IsRange                      = 0
+pp_data->cap[167]->IsAlias                      = 0
+pp_data->cap[167]->IsStringRange                = 0
+pp_data->cap[167]->IsDesignatorRange            = 0
+pp_data->cap[167]->Reserved1                    = 0x000000
+pp_data->cap[167]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[167]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[167]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[167]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[167]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[167]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[167]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[167]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[167]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[167]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[167]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[167]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[167]->NotRange.Usage                        = 0x0081
+pp_data->cap[167]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[167]->NotRange.StringIndex                  = 0
+pp_data->cap[167]->NotRange.Reserved2                    = 0
+pp_data->cap[167]->NotRange.DesignatorIndex              = 0
+pp_data->cap[167]->NotRange.Reserved3                    = 0
+pp_data->cap[167]->NotRange.DataIndex                    = 80
+pp_data->cap[167]->NotRange.Reserved4                    = 80
+pp_data->cap[167]->NotButton.HasNull                   = 0
+pp_data->cap[167]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[167]->NotButton.LogicalMin                = 0
+pp_data->cap[167]->NotButton.LogicalMax                = 127
+pp_data->cap[167]->NotButton.PhysicalMin               = 0
+pp_data->cap[167]->NotButton.PhysicalMax               = 0
+pp_data->cap[167]->Units                    = 0
+pp_data->cap[167]->UnitsExp                 = 0
+
+pp_data->cap[168]->UsagePage                    = 0xFF01
+pp_data->cap[168]->ReportID                     = 0x80
+pp_data->cap[168]->BitPosition                  = 0
+pp_data->cap[168]->BitSize                      = 8
+pp_data->cap[168]->ReportCount                  = 1
+pp_data->cap[168]->BytePosition                 = 0x000D
+pp_data->cap[168]->BitCount                     = 8
+pp_data->cap[168]->BitField                     = 0x02
+pp_data->cap[168]->NextBytePosition             = 0x000E
+pp_data->cap[168]->LinkCollection               = 0x0003
+pp_data->cap[168]->LinkUsagePage                = 0xFF01
+pp_data->cap[168]->LinkUsage                    = 0x0080
+pp_data->cap[168]->IsMultipleItemsForArray      = 0
+pp_data->cap[168]->IsButtonCap                  = 0
+pp_data->cap[168]->IsPadding                    = 0
+pp_data->cap[168]->IsAbsolute                   = 1
+pp_data->cap[168]->IsRange                      = 0
+pp_data->cap[168]->IsAlias                      = 0
+pp_data->cap[168]->IsStringRange                = 0
+pp_data->cap[168]->IsDesignatorRange            = 0
+pp_data->cap[168]->Reserved1                    = 0x000000
+pp_data->cap[168]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[168]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[168]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[168]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[168]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[168]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[168]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[168]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[168]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[168]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[168]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[168]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[168]->NotRange.Usage                        = 0x0081
+pp_data->cap[168]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[168]->NotRange.StringIndex                  = 0
+pp_data->cap[168]->NotRange.Reserved2                    = 0
+pp_data->cap[168]->NotRange.DesignatorIndex              = 0
+pp_data->cap[168]->NotRange.Reserved3                    = 0
+pp_data->cap[168]->NotRange.DataIndex                    = 81
+pp_data->cap[168]->NotRange.Reserved4                    = 81
+pp_data->cap[168]->NotButton.HasNull                   = 0
+pp_data->cap[168]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[168]->NotButton.LogicalMin                = 0
+pp_data->cap[168]->NotButton.LogicalMax                = 127
+pp_data->cap[168]->NotButton.PhysicalMin               = 0
+pp_data->cap[168]->NotButton.PhysicalMax               = 0
+pp_data->cap[168]->Units                    = 0
+pp_data->cap[168]->UnitsExp                 = 0
+
+pp_data->cap[169]->UsagePage                    = 0xFF01
+pp_data->cap[169]->ReportID                     = 0x80
+pp_data->cap[169]->BitPosition                  = 0
+pp_data->cap[169]->BitSize                      = 8
+pp_data->cap[169]->ReportCount                  = 1
+pp_data->cap[169]->BytePosition                 = 0x000C
+pp_data->cap[169]->BitCount                     = 8
+pp_data->cap[169]->BitField                     = 0x02
+pp_data->cap[169]->NextBytePosition             = 0x000D
+pp_data->cap[169]->LinkCollection               = 0x0003
+pp_data->cap[169]->LinkUsagePage                = 0xFF01
+pp_data->cap[169]->LinkUsage                    = 0x0080
+pp_data->cap[169]->IsMultipleItemsForArray      = 0
+pp_data->cap[169]->IsButtonCap                  = 0
+pp_data->cap[169]->IsPadding                    = 0
+pp_data->cap[169]->IsAbsolute                   = 1
+pp_data->cap[169]->IsRange                      = 0
+pp_data->cap[169]->IsAlias                      = 0
+pp_data->cap[169]->IsStringRange                = 0
+pp_data->cap[169]->IsDesignatorRange            = 0
+pp_data->cap[169]->Reserved1                    = 0x000000
+pp_data->cap[169]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[169]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[169]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[169]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[169]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[169]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[169]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[169]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[169]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[169]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[169]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[169]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[169]->NotRange.Usage                        = 0x0081
+pp_data->cap[169]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[169]->NotRange.StringIndex                  = 0
+pp_data->cap[169]->NotRange.Reserved2                    = 0
+pp_data->cap[169]->NotRange.DesignatorIndex              = 0
+pp_data->cap[169]->NotRange.Reserved3                    = 0
+pp_data->cap[169]->NotRange.DataIndex                    = 82
+pp_data->cap[169]->NotRange.Reserved4                    = 82
+pp_data->cap[169]->NotButton.HasNull                   = 0
+pp_data->cap[169]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[169]->NotButton.LogicalMin                = 0
+pp_data->cap[169]->NotButton.LogicalMax                = 127
+pp_data->cap[169]->NotButton.PhysicalMin               = 0
+pp_data->cap[169]->NotButton.PhysicalMax               = 0
+pp_data->cap[169]->Units                    = 0
+pp_data->cap[169]->UnitsExp                 = 0
+
+pp_data->cap[170]->UsagePage                    = 0xFF01
+pp_data->cap[170]->ReportID                     = 0x80
+pp_data->cap[170]->BitPosition                  = 0
+pp_data->cap[170]->BitSize                      = 8
+pp_data->cap[170]->ReportCount                  = 1
+pp_data->cap[170]->BytePosition                 = 0x000B
+pp_data->cap[170]->BitCount                     = 8
+pp_data->cap[170]->BitField                     = 0x02
+pp_data->cap[170]->NextBytePosition             = 0x000C
+pp_data->cap[170]->LinkCollection               = 0x0003
+pp_data->cap[170]->LinkUsagePage                = 0xFF01
+pp_data->cap[170]->LinkUsage                    = 0x0080
+pp_data->cap[170]->IsMultipleItemsForArray      = 0
+pp_data->cap[170]->IsButtonCap                  = 0
+pp_data->cap[170]->IsPadding                    = 0
+pp_data->cap[170]->IsAbsolute                   = 1
+pp_data->cap[170]->IsRange                      = 0
+pp_data->cap[170]->IsAlias                      = 0
+pp_data->cap[170]->IsStringRange                = 0
+pp_data->cap[170]->IsDesignatorRange            = 0
+pp_data->cap[170]->Reserved1                    = 0x000000
+pp_data->cap[170]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[170]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[170]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[170]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[170]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[170]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[170]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[170]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[170]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[170]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[170]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[170]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[170]->NotRange.Usage                        = 0x0081
+pp_data->cap[170]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[170]->NotRange.StringIndex                  = 0
+pp_data->cap[170]->NotRange.Reserved2                    = 0
+pp_data->cap[170]->NotRange.DesignatorIndex              = 0
+pp_data->cap[170]->NotRange.Reserved3                    = 0
+pp_data->cap[170]->NotRange.DataIndex                    = 83
+pp_data->cap[170]->NotRange.Reserved4                    = 83
+pp_data->cap[170]->NotButton.HasNull                   = 0
+pp_data->cap[170]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[170]->NotButton.LogicalMin                = 0
+pp_data->cap[170]->NotButton.LogicalMax                = 127
+pp_data->cap[170]->NotButton.PhysicalMin               = 0
+pp_data->cap[170]->NotButton.PhysicalMax               = 0
+pp_data->cap[170]->Units                    = 0
+pp_data->cap[170]->UnitsExp                 = 0
+
+pp_data->cap[171]->UsagePage                    = 0xFF01
+pp_data->cap[171]->ReportID                     = 0x80
+pp_data->cap[171]->BitPosition                  = 0
+pp_data->cap[171]->BitSize                      = 8
+pp_data->cap[171]->ReportCount                  = 1
+pp_data->cap[171]->BytePosition                 = 0x000A
+pp_data->cap[171]->BitCount                     = 8
+pp_data->cap[171]->BitField                     = 0x02
+pp_data->cap[171]->NextBytePosition             = 0x000B
+pp_data->cap[171]->LinkCollection               = 0x0003
+pp_data->cap[171]->LinkUsagePage                = 0xFF01
+pp_data->cap[171]->LinkUsage                    = 0x0080
+pp_data->cap[171]->IsMultipleItemsForArray      = 0
+pp_data->cap[171]->IsButtonCap                  = 0
+pp_data->cap[171]->IsPadding                    = 0
+pp_data->cap[171]->IsAbsolute                   = 1
+pp_data->cap[171]->IsRange                      = 0
+pp_data->cap[171]->IsAlias                      = 0
+pp_data->cap[171]->IsStringRange                = 0
+pp_data->cap[171]->IsDesignatorRange            = 0
+pp_data->cap[171]->Reserved1                    = 0x000000
+pp_data->cap[171]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[171]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[171]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[171]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[171]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[171]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[171]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[171]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[171]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[171]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[171]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[171]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[171]->NotRange.Usage                        = 0x0081
+pp_data->cap[171]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[171]->NotRange.StringIndex                  = 0
+pp_data->cap[171]->NotRange.Reserved2                    = 0
+pp_data->cap[171]->NotRange.DesignatorIndex              = 0
+pp_data->cap[171]->NotRange.Reserved3                    = 0
+pp_data->cap[171]->NotRange.DataIndex                    = 84
+pp_data->cap[171]->NotRange.Reserved4                    = 84
+pp_data->cap[171]->NotButton.HasNull                   = 0
+pp_data->cap[171]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[171]->NotButton.LogicalMin                = 0
+pp_data->cap[171]->NotButton.LogicalMax                = 127
+pp_data->cap[171]->NotButton.PhysicalMin               = 0
+pp_data->cap[171]->NotButton.PhysicalMax               = 0
+pp_data->cap[171]->Units                    = 0
+pp_data->cap[171]->UnitsExp                 = 0
+
+pp_data->cap[172]->UsagePage                    = 0xFF01
+pp_data->cap[172]->ReportID                     = 0x80
+pp_data->cap[172]->BitPosition                  = 0
+pp_data->cap[172]->BitSize                      = 8
+pp_data->cap[172]->ReportCount                  = 1
+pp_data->cap[172]->BytePosition                 = 0x0009
+pp_data->cap[172]->BitCount                     = 8
+pp_data->cap[172]->BitField                     = 0x02
+pp_data->cap[172]->NextBytePosition             = 0x000A
+pp_data->cap[172]->LinkCollection               = 0x0003
+pp_data->cap[172]->LinkUsagePage                = 0xFF01
+pp_data->cap[172]->LinkUsage                    = 0x0080
+pp_data->cap[172]->IsMultipleItemsForArray      = 0
+pp_data->cap[172]->IsButtonCap                  = 0
+pp_data->cap[172]->IsPadding                    = 0
+pp_data->cap[172]->IsAbsolute                   = 1
+pp_data->cap[172]->IsRange                      = 0
+pp_data->cap[172]->IsAlias                      = 0
+pp_data->cap[172]->IsStringRange                = 0
+pp_data->cap[172]->IsDesignatorRange            = 0
+pp_data->cap[172]->Reserved1                    = 0x000000
+pp_data->cap[172]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[172]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[172]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[172]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[172]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[172]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[172]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[172]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[172]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[172]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[172]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[172]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[172]->NotRange.Usage                        = 0x0081
+pp_data->cap[172]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[172]->NotRange.StringIndex                  = 0
+pp_data->cap[172]->NotRange.Reserved2                    = 0
+pp_data->cap[172]->NotRange.DesignatorIndex              = 0
+pp_data->cap[172]->NotRange.Reserved3                    = 0
+pp_data->cap[172]->NotRange.DataIndex                    = 85
+pp_data->cap[172]->NotRange.Reserved4                    = 85
+pp_data->cap[172]->NotButton.HasNull                   = 0
+pp_data->cap[172]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[172]->NotButton.LogicalMin                = 0
+pp_data->cap[172]->NotButton.LogicalMax                = 127
+pp_data->cap[172]->NotButton.PhysicalMin               = 0
+pp_data->cap[172]->NotButton.PhysicalMax               = 0
+pp_data->cap[172]->Units                    = 0
+pp_data->cap[172]->UnitsExp                 = 0
+
+pp_data->cap[173]->UsagePage                    = 0xFF01
+pp_data->cap[173]->ReportID                     = 0x80
+pp_data->cap[173]->BitPosition                  = 0
+pp_data->cap[173]->BitSize                      = 8
+pp_data->cap[173]->ReportCount                  = 1
+pp_data->cap[173]->BytePosition                 = 0x0008
+pp_data->cap[173]->BitCount                     = 8
+pp_data->cap[173]->BitField                     = 0x02
+pp_data->cap[173]->NextBytePosition             = 0x0009
+pp_data->cap[173]->LinkCollection               = 0x0003
+pp_data->cap[173]->LinkUsagePage                = 0xFF01
+pp_data->cap[173]->LinkUsage                    = 0x0080
+pp_data->cap[173]->IsMultipleItemsForArray      = 0
+pp_data->cap[173]->IsButtonCap                  = 0
+pp_data->cap[173]->IsPadding                    = 0
+pp_data->cap[173]->IsAbsolute                   = 1
+pp_data->cap[173]->IsRange                      = 0
+pp_data->cap[173]->IsAlias                      = 0
+pp_data->cap[173]->IsStringRange                = 0
+pp_data->cap[173]->IsDesignatorRange            = 0
+pp_data->cap[173]->Reserved1                    = 0x000000
+pp_data->cap[173]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[173]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[173]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[173]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[173]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[173]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[173]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[173]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[173]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[173]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[173]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[173]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[173]->NotRange.Usage                        = 0x0081
+pp_data->cap[173]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[173]->NotRange.StringIndex                  = 0
+pp_data->cap[173]->NotRange.Reserved2                    = 0
+pp_data->cap[173]->NotRange.DesignatorIndex              = 0
+pp_data->cap[173]->NotRange.Reserved3                    = 0
+pp_data->cap[173]->NotRange.DataIndex                    = 86
+pp_data->cap[173]->NotRange.Reserved4                    = 86
+pp_data->cap[173]->NotButton.HasNull                   = 0
+pp_data->cap[173]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[173]->NotButton.LogicalMin                = 0
+pp_data->cap[173]->NotButton.LogicalMax                = 127
+pp_data->cap[173]->NotButton.PhysicalMin               = 0
+pp_data->cap[173]->NotButton.PhysicalMax               = 0
+pp_data->cap[173]->Units                    = 0
+pp_data->cap[173]->UnitsExp                 = 0
+
+pp_data->cap[174]->UsagePage                    = 0xFF01
+pp_data->cap[174]->ReportID                     = 0x80
+pp_data->cap[174]->BitPosition                  = 0
+pp_data->cap[174]->BitSize                      = 8
+pp_data->cap[174]->ReportCount                  = 1
+pp_data->cap[174]->BytePosition                 = 0x0007
+pp_data->cap[174]->BitCount                     = 8
+pp_data->cap[174]->BitField                     = 0x02
+pp_data->cap[174]->NextBytePosition             = 0x0008
+pp_data->cap[174]->LinkCollection               = 0x0003
+pp_data->cap[174]->LinkUsagePage                = 0xFF01
+pp_data->cap[174]->LinkUsage                    = 0x0080
+pp_data->cap[174]->IsMultipleItemsForArray      = 0
+pp_data->cap[174]->IsButtonCap                  = 0
+pp_data->cap[174]->IsPadding                    = 0
+pp_data->cap[174]->IsAbsolute                   = 1
+pp_data->cap[174]->IsRange                      = 0
+pp_data->cap[174]->IsAlias                      = 0
+pp_data->cap[174]->IsStringRange                = 0
+pp_data->cap[174]->IsDesignatorRange            = 0
+pp_data->cap[174]->Reserved1                    = 0x000000
+pp_data->cap[174]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[174]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[174]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[174]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[174]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[174]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[174]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[174]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[174]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[174]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[174]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[174]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[174]->NotRange.Usage                        = 0x0081
+pp_data->cap[174]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[174]->NotRange.StringIndex                  = 0
+pp_data->cap[174]->NotRange.Reserved2                    = 0
+pp_data->cap[174]->NotRange.DesignatorIndex              = 0
+pp_data->cap[174]->NotRange.Reserved3                    = 0
+pp_data->cap[174]->NotRange.DataIndex                    = 87
+pp_data->cap[174]->NotRange.Reserved4                    = 87
+pp_data->cap[174]->NotButton.HasNull                   = 0
+pp_data->cap[174]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[174]->NotButton.LogicalMin                = 0
+pp_data->cap[174]->NotButton.LogicalMax                = 127
+pp_data->cap[174]->NotButton.PhysicalMin               = 0
+pp_data->cap[174]->NotButton.PhysicalMax               = 0
+pp_data->cap[174]->Units                    = 0
+pp_data->cap[174]->UnitsExp                 = 0
+
+pp_data->cap[175]->UsagePage                    = 0xFF01
+pp_data->cap[175]->ReportID                     = 0x80
+pp_data->cap[175]->BitPosition                  = 0
+pp_data->cap[175]->BitSize                      = 8
+pp_data->cap[175]->ReportCount                  = 1
+pp_data->cap[175]->BytePosition                 = 0x0006
+pp_data->cap[175]->BitCount                     = 8
+pp_data->cap[175]->BitField                     = 0x02
+pp_data->cap[175]->NextBytePosition             = 0x0007
+pp_data->cap[175]->LinkCollection               = 0x0003
+pp_data->cap[175]->LinkUsagePage                = 0xFF01
+pp_data->cap[175]->LinkUsage                    = 0x0080
+pp_data->cap[175]->IsMultipleItemsForArray      = 0
+pp_data->cap[175]->IsButtonCap                  = 0
+pp_data->cap[175]->IsPadding                    = 0
+pp_data->cap[175]->IsAbsolute                   = 1
+pp_data->cap[175]->IsRange                      = 0
+pp_data->cap[175]->IsAlias                      = 0
+pp_data->cap[175]->IsStringRange                = 0
+pp_data->cap[175]->IsDesignatorRange            = 0
+pp_data->cap[175]->Reserved1                    = 0x000000
+pp_data->cap[175]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[175]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[175]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[175]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[175]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[175]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[175]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[175]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[175]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[175]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[175]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[175]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[175]->NotRange.Usage                        = 0x0081
+pp_data->cap[175]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[175]->NotRange.StringIndex                  = 0
+pp_data->cap[175]->NotRange.Reserved2                    = 0
+pp_data->cap[175]->NotRange.DesignatorIndex              = 0
+pp_data->cap[175]->NotRange.Reserved3                    = 0
+pp_data->cap[175]->NotRange.DataIndex                    = 88
+pp_data->cap[175]->NotRange.Reserved4                    = 88
+pp_data->cap[175]->NotButton.HasNull                   = 0
+pp_data->cap[175]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[175]->NotButton.LogicalMin                = 0
+pp_data->cap[175]->NotButton.LogicalMax                = 127
+pp_data->cap[175]->NotButton.PhysicalMin               = 0
+pp_data->cap[175]->NotButton.PhysicalMax               = 0
+pp_data->cap[175]->Units                    = 0
+pp_data->cap[175]->UnitsExp                 = 0
+
+pp_data->cap[176]->UsagePage                    = 0xFF01
+pp_data->cap[176]->ReportID                     = 0x80
+pp_data->cap[176]->BitPosition                  = 0
+pp_data->cap[176]->BitSize                      = 8
+pp_data->cap[176]->ReportCount                  = 1
+pp_data->cap[176]->BytePosition                 = 0x0005
+pp_data->cap[176]->BitCount                     = 8
+pp_data->cap[176]->BitField                     = 0x02
+pp_data->cap[176]->NextBytePosition             = 0x0006
+pp_data->cap[176]->LinkCollection               = 0x0003
+pp_data->cap[176]->LinkUsagePage                = 0xFF01
+pp_data->cap[176]->LinkUsage                    = 0x0080
+pp_data->cap[176]->IsMultipleItemsForArray      = 0
+pp_data->cap[176]->IsButtonCap                  = 0
+pp_data->cap[176]->IsPadding                    = 0
+pp_data->cap[176]->IsAbsolute                   = 1
+pp_data->cap[176]->IsRange                      = 0
+pp_data->cap[176]->IsAlias                      = 0
+pp_data->cap[176]->IsStringRange                = 0
+pp_data->cap[176]->IsDesignatorRange            = 0
+pp_data->cap[176]->Reserved1                    = 0x000000
+pp_data->cap[176]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[176]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[176]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[176]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[176]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[176]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[176]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[176]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[176]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[176]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[176]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[176]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[176]->NotRange.Usage                        = 0x0081
+pp_data->cap[176]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[176]->NotRange.StringIndex                  = 0
+pp_data->cap[176]->NotRange.Reserved2                    = 0
+pp_data->cap[176]->NotRange.DesignatorIndex              = 0
+pp_data->cap[176]->NotRange.Reserved3                    = 0
+pp_data->cap[176]->NotRange.DataIndex                    = 89
+pp_data->cap[176]->NotRange.Reserved4                    = 89
+pp_data->cap[176]->NotButton.HasNull                   = 0
+pp_data->cap[176]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[176]->NotButton.LogicalMin                = 0
+pp_data->cap[176]->NotButton.LogicalMax                = 127
+pp_data->cap[176]->NotButton.PhysicalMin               = 0
+pp_data->cap[176]->NotButton.PhysicalMax               = 0
+pp_data->cap[176]->Units                    = 0
+pp_data->cap[176]->UnitsExp                 = 0
+
+pp_data->cap[177]->UsagePage                    = 0xFF01
+pp_data->cap[177]->ReportID                     = 0x80
+pp_data->cap[177]->BitPosition                  = 0
+pp_data->cap[177]->BitSize                      = 8
+pp_data->cap[177]->ReportCount                  = 1
+pp_data->cap[177]->BytePosition                 = 0x0004
+pp_data->cap[177]->BitCount                     = 8
+pp_data->cap[177]->BitField                     = 0x02
+pp_data->cap[177]->NextBytePosition             = 0x0005
+pp_data->cap[177]->LinkCollection               = 0x0003
+pp_data->cap[177]->LinkUsagePage                = 0xFF01
+pp_data->cap[177]->LinkUsage                    = 0x0080
+pp_data->cap[177]->IsMultipleItemsForArray      = 0
+pp_data->cap[177]->IsButtonCap                  = 0
+pp_data->cap[177]->IsPadding                    = 0
+pp_data->cap[177]->IsAbsolute                   = 1
+pp_data->cap[177]->IsRange                      = 0
+pp_data->cap[177]->IsAlias                      = 0
+pp_data->cap[177]->IsStringRange                = 0
+pp_data->cap[177]->IsDesignatorRange            = 0
+pp_data->cap[177]->Reserved1                    = 0x000000
+pp_data->cap[177]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[177]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[177]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[177]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[177]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[177]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[177]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[177]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[177]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[177]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[177]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[177]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[177]->NotRange.Usage                        = 0x0081
+pp_data->cap[177]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[177]->NotRange.StringIndex                  = 0
+pp_data->cap[177]->NotRange.Reserved2                    = 0
+pp_data->cap[177]->NotRange.DesignatorIndex              = 0
+pp_data->cap[177]->NotRange.Reserved3                    = 0
+pp_data->cap[177]->NotRange.DataIndex                    = 90
+pp_data->cap[177]->NotRange.Reserved4                    = 90
+pp_data->cap[177]->NotButton.HasNull                   = 0
+pp_data->cap[177]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[177]->NotButton.LogicalMin                = 0
+pp_data->cap[177]->NotButton.LogicalMax                = 127
+pp_data->cap[177]->NotButton.PhysicalMin               = 0
+pp_data->cap[177]->NotButton.PhysicalMax               = 0
+pp_data->cap[177]->Units                    = 0
+pp_data->cap[177]->UnitsExp                 = 0
+
+pp_data->cap[178]->UsagePage                    = 0xFF01
+pp_data->cap[178]->ReportID                     = 0x80
+pp_data->cap[178]->BitPosition                  = 0
+pp_data->cap[178]->BitSize                      = 8
+pp_data->cap[178]->ReportCount                  = 1
+pp_data->cap[178]->BytePosition                 = 0x0003
+pp_data->cap[178]->BitCount                     = 8
+pp_data->cap[178]->BitField                     = 0x02
+pp_data->cap[178]->NextBytePosition             = 0x0004
+pp_data->cap[178]->LinkCollection               = 0x0003
+pp_data->cap[178]->LinkUsagePage                = 0xFF01
+pp_data->cap[178]->LinkUsage                    = 0x0080
+pp_data->cap[178]->IsMultipleItemsForArray      = 0
+pp_data->cap[178]->IsButtonCap                  = 0
+pp_data->cap[178]->IsPadding                    = 0
+pp_data->cap[178]->IsAbsolute                   = 1
+pp_data->cap[178]->IsRange                      = 0
+pp_data->cap[178]->IsAlias                      = 0
+pp_data->cap[178]->IsStringRange                = 0
+pp_data->cap[178]->IsDesignatorRange            = 0
+pp_data->cap[178]->Reserved1                    = 0x000000
+pp_data->cap[178]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[178]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[178]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[178]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[178]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[178]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[178]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[178]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[178]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[178]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[178]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[178]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[178]->NotRange.Usage                        = 0x0081
+pp_data->cap[178]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[178]->NotRange.StringIndex                  = 0
+pp_data->cap[178]->NotRange.Reserved2                    = 0
+pp_data->cap[178]->NotRange.DesignatorIndex              = 0
+pp_data->cap[178]->NotRange.Reserved3                    = 0
+pp_data->cap[178]->NotRange.DataIndex                    = 91
+pp_data->cap[178]->NotRange.Reserved4                    = 91
+pp_data->cap[178]->NotButton.HasNull                   = 0
+pp_data->cap[178]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[178]->NotButton.LogicalMin                = 0
+pp_data->cap[178]->NotButton.LogicalMax                = 127
+pp_data->cap[178]->NotButton.PhysicalMin               = 0
+pp_data->cap[178]->NotButton.PhysicalMax               = 0
+pp_data->cap[178]->Units                    = 0
+pp_data->cap[178]->UnitsExp                 = 0
+
+pp_data->cap[179]->UsagePage                    = 0xFF01
+pp_data->cap[179]->ReportID                     = 0x80
+pp_data->cap[179]->BitPosition                  = 0
+pp_data->cap[179]->BitSize                      = 8
+pp_data->cap[179]->ReportCount                  = 1
+pp_data->cap[179]->BytePosition                 = 0x0002
+pp_data->cap[179]->BitCount                     = 8
+pp_data->cap[179]->BitField                     = 0x02
+pp_data->cap[179]->NextBytePosition             = 0x0003
+pp_data->cap[179]->LinkCollection               = 0x0003
+pp_data->cap[179]->LinkUsagePage                = 0xFF01
+pp_data->cap[179]->LinkUsage                    = 0x0080
+pp_data->cap[179]->IsMultipleItemsForArray      = 0
+pp_data->cap[179]->IsButtonCap                  = 0
+pp_data->cap[179]->IsPadding                    = 0
+pp_data->cap[179]->IsAbsolute                   = 1
+pp_data->cap[179]->IsRange                      = 0
+pp_data->cap[179]->IsAlias                      = 0
+pp_data->cap[179]->IsStringRange                = 0
+pp_data->cap[179]->IsDesignatorRange            = 0
+pp_data->cap[179]->Reserved1                    = 0x000000
+pp_data->cap[179]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[179]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[179]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[179]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[179]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[179]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[179]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[179]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[179]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[179]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[179]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[179]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[179]->NotRange.Usage                        = 0x0081
+pp_data->cap[179]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[179]->NotRange.StringIndex                  = 0
+pp_data->cap[179]->NotRange.Reserved2                    = 0
+pp_data->cap[179]->NotRange.DesignatorIndex              = 0
+pp_data->cap[179]->NotRange.Reserved3                    = 0
+pp_data->cap[179]->NotRange.DataIndex                    = 92
+pp_data->cap[179]->NotRange.Reserved4                    = 92
+pp_data->cap[179]->NotButton.HasNull                   = 0
+pp_data->cap[179]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[179]->NotButton.LogicalMin                = 0
+pp_data->cap[179]->NotButton.LogicalMax                = 127
+pp_data->cap[179]->NotButton.PhysicalMin               = 0
+pp_data->cap[179]->NotButton.PhysicalMax               = 0
+pp_data->cap[179]->Units                    = 0
+pp_data->cap[179]->UnitsExp                 = 0
+
+pp_data->cap[180]->UsagePage                    = 0xFF01
+pp_data->cap[180]->ReportID                     = 0x80
+pp_data->cap[180]->BitPosition                  = 0
+pp_data->cap[180]->BitSize                      = 8
+pp_data->cap[180]->ReportCount                  = 1
+pp_data->cap[180]->BytePosition                 = 0x0001
+pp_data->cap[180]->BitCount                     = 8
+pp_data->cap[180]->BitField                     = 0x02
+pp_data->cap[180]->NextBytePosition             = 0x0002
+pp_data->cap[180]->LinkCollection               = 0x0003
+pp_data->cap[180]->LinkUsagePage                = 0xFF01
+pp_data->cap[180]->LinkUsage                    = 0x0080
+pp_data->cap[180]->IsMultipleItemsForArray      = 0
+pp_data->cap[180]->IsButtonCap                  = 0
+pp_data->cap[180]->IsPadding                    = 0
+pp_data->cap[180]->IsAbsolute                   = 1
+pp_data->cap[180]->IsRange                      = 0
+pp_data->cap[180]->IsAlias                      = 0
+pp_data->cap[180]->IsStringRange                = 0
+pp_data->cap[180]->IsDesignatorRange            = 0
+pp_data->cap[180]->Reserved1                    = 0x000000
+pp_data->cap[180]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[180]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[180]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[180]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[180]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[180]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[180]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[180]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[180]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[180]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[180]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[180]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[180]->NotRange.Usage                        = 0x0081
+pp_data->cap[180]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[180]->NotRange.StringIndex                  = 0
+pp_data->cap[180]->NotRange.Reserved2                    = 0
+pp_data->cap[180]->NotRange.DesignatorIndex              = 0
+pp_data->cap[180]->NotRange.Reserved3                    = 0
+pp_data->cap[180]->NotRange.DataIndex                    = 93
+pp_data->cap[180]->NotRange.Reserved4                    = 93
+pp_data->cap[180]->NotButton.HasNull                   = 0
+pp_data->cap[180]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[180]->NotButton.LogicalMin                = 0
+pp_data->cap[180]->NotButton.LogicalMax                = 127
+pp_data->cap[180]->NotButton.PhysicalMin               = 0
+pp_data->cap[180]->NotButton.PhysicalMax               = 0
+pp_data->cap[180]->Units                    = 0
+pp_data->cap[180]->UnitsExp                 = 0
+
+pp_data->cap[181]->UsagePage                    = 0xFF01
+pp_data->cap[181]->ReportID                     = 0x81
+pp_data->cap[181]->BitPosition                  = 0
+pp_data->cap[181]->BitSize                      = 8
+pp_data->cap[181]->ReportCount                  = 1
+pp_data->cap[181]->BytePosition                 = 0x0028
+pp_data->cap[181]->BitCount                     = 8
+pp_data->cap[181]->BitField                     = 0x02
+pp_data->cap[181]->NextBytePosition             = 0x0029
+pp_data->cap[181]->LinkCollection               = 0x0004
+pp_data->cap[181]->LinkUsagePage                = 0xFF01
+pp_data->cap[181]->LinkUsage                    = 0x0080
+pp_data->cap[181]->IsMultipleItemsForArray      = 0
+pp_data->cap[181]->IsButtonCap                  = 0
+pp_data->cap[181]->IsPadding                    = 0
+pp_data->cap[181]->IsAbsolute                   = 1
+pp_data->cap[181]->IsRange                      = 0
+pp_data->cap[181]->IsAlias                      = 0
+pp_data->cap[181]->IsStringRange                = 0
+pp_data->cap[181]->IsDesignatorRange            = 0
+pp_data->cap[181]->Reserved1                    = 0x000000
+pp_data->cap[181]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[181]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[181]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[181]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[181]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[181]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[181]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[181]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[181]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[181]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[181]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[181]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[181]->NotRange.Usage                        = 0x0081
+pp_data->cap[181]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[181]->NotRange.StringIndex                  = 0
+pp_data->cap[181]->NotRange.Reserved2                    = 0
+pp_data->cap[181]->NotRange.DesignatorIndex              = 0
+pp_data->cap[181]->NotRange.Reserved3                    = 0
+pp_data->cap[181]->NotRange.DataIndex                    = 94
+pp_data->cap[181]->NotRange.Reserved4                    = 94
+pp_data->cap[181]->NotButton.HasNull                   = 0
+pp_data->cap[181]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[181]->NotButton.LogicalMin                = 0
+pp_data->cap[181]->NotButton.LogicalMax                = 127
+pp_data->cap[181]->NotButton.PhysicalMin               = 0
+pp_data->cap[181]->NotButton.PhysicalMax               = 0
+pp_data->cap[181]->Units                    = 0
+pp_data->cap[181]->UnitsExp                 = 0
+
+pp_data->cap[182]->UsagePage                    = 0xFF01
+pp_data->cap[182]->ReportID                     = 0x81
+pp_data->cap[182]->BitPosition                  = 0
+pp_data->cap[182]->BitSize                      = 8
+pp_data->cap[182]->ReportCount                  = 1
+pp_data->cap[182]->BytePosition                 = 0x0027
+pp_data->cap[182]->BitCount                     = 8
+pp_data->cap[182]->BitField                     = 0x02
+pp_data->cap[182]->NextBytePosition             = 0x0028
+pp_data->cap[182]->LinkCollection               = 0x0004
+pp_data->cap[182]->LinkUsagePage                = 0xFF01
+pp_data->cap[182]->LinkUsage                    = 0x0080
+pp_data->cap[182]->IsMultipleItemsForArray      = 0
+pp_data->cap[182]->IsButtonCap                  = 0
+pp_data->cap[182]->IsPadding                    = 0
+pp_data->cap[182]->IsAbsolute                   = 1
+pp_data->cap[182]->IsRange                      = 0
+pp_data->cap[182]->IsAlias                      = 0
+pp_data->cap[182]->IsStringRange                = 0
+pp_data->cap[182]->IsDesignatorRange            = 0
+pp_data->cap[182]->Reserved1                    = 0x000000
+pp_data->cap[182]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[182]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[182]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[182]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[182]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[182]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[182]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[182]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[182]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[182]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[182]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[182]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[182]->NotRange.Usage                        = 0x0081
+pp_data->cap[182]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[182]->NotRange.StringIndex                  = 0
+pp_data->cap[182]->NotRange.Reserved2                    = 0
+pp_data->cap[182]->NotRange.DesignatorIndex              = 0
+pp_data->cap[182]->NotRange.Reserved3                    = 0
+pp_data->cap[182]->NotRange.DataIndex                    = 95
+pp_data->cap[182]->NotRange.Reserved4                    = 95
+pp_data->cap[182]->NotButton.HasNull                   = 0
+pp_data->cap[182]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[182]->NotButton.LogicalMin                = 0
+pp_data->cap[182]->NotButton.LogicalMax                = 127
+pp_data->cap[182]->NotButton.PhysicalMin               = 0
+pp_data->cap[182]->NotButton.PhysicalMax               = 0
+pp_data->cap[182]->Units                    = 0
+pp_data->cap[182]->UnitsExp                 = 0
+
+pp_data->cap[183]->UsagePage                    = 0xFF01
+pp_data->cap[183]->ReportID                     = 0x81
+pp_data->cap[183]->BitPosition                  = 0
+pp_data->cap[183]->BitSize                      = 8
+pp_data->cap[183]->ReportCount                  = 1
+pp_data->cap[183]->BytePosition                 = 0x0026
+pp_data->cap[183]->BitCount                     = 8
+pp_data->cap[183]->BitField                     = 0x02
+pp_data->cap[183]->NextBytePosition             = 0x0027
+pp_data->cap[183]->LinkCollection               = 0x0004
+pp_data->cap[183]->LinkUsagePage                = 0xFF01
+pp_data->cap[183]->LinkUsage                    = 0x0080
+pp_data->cap[183]->IsMultipleItemsForArray      = 0
+pp_data->cap[183]->IsButtonCap                  = 0
+pp_data->cap[183]->IsPadding                    = 0
+pp_data->cap[183]->IsAbsolute                   = 1
+pp_data->cap[183]->IsRange                      = 0
+pp_data->cap[183]->IsAlias                      = 0
+pp_data->cap[183]->IsStringRange                = 0
+pp_data->cap[183]->IsDesignatorRange            = 0
+pp_data->cap[183]->Reserved1                    = 0x000000
+pp_data->cap[183]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[183]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[183]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[183]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[183]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[183]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[183]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[183]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[183]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[183]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[183]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[183]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[183]->NotRange.Usage                        = 0x0081
+pp_data->cap[183]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[183]->NotRange.StringIndex                  = 0
+pp_data->cap[183]->NotRange.Reserved2                    = 0
+pp_data->cap[183]->NotRange.DesignatorIndex              = 0
+pp_data->cap[183]->NotRange.Reserved3                    = 0
+pp_data->cap[183]->NotRange.DataIndex                    = 96
+pp_data->cap[183]->NotRange.Reserved4                    = 96
+pp_data->cap[183]->NotButton.HasNull                   = 0
+pp_data->cap[183]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[183]->NotButton.LogicalMin                = 0
+pp_data->cap[183]->NotButton.LogicalMax                = 127
+pp_data->cap[183]->NotButton.PhysicalMin               = 0
+pp_data->cap[183]->NotButton.PhysicalMax               = 0
+pp_data->cap[183]->Units                    = 0
+pp_data->cap[183]->UnitsExp                 = 0
+
+pp_data->cap[184]->UsagePage                    = 0xFF01
+pp_data->cap[184]->ReportID                     = 0x81
+pp_data->cap[184]->BitPosition                  = 0
+pp_data->cap[184]->BitSize                      = 8
+pp_data->cap[184]->ReportCount                  = 1
+pp_data->cap[184]->BytePosition                 = 0x0025
+pp_data->cap[184]->BitCount                     = 8
+pp_data->cap[184]->BitField                     = 0x02
+pp_data->cap[184]->NextBytePosition             = 0x0026
+pp_data->cap[184]->LinkCollection               = 0x0004
+pp_data->cap[184]->LinkUsagePage                = 0xFF01
+pp_data->cap[184]->LinkUsage                    = 0x0080
+pp_data->cap[184]->IsMultipleItemsForArray      = 0
+pp_data->cap[184]->IsButtonCap                  = 0
+pp_data->cap[184]->IsPadding                    = 0
+pp_data->cap[184]->IsAbsolute                   = 1
+pp_data->cap[184]->IsRange                      = 0
+pp_data->cap[184]->IsAlias                      = 0
+pp_data->cap[184]->IsStringRange                = 0
+pp_data->cap[184]->IsDesignatorRange            = 0
+pp_data->cap[184]->Reserved1                    = 0x000000
+pp_data->cap[184]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[184]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[184]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[184]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[184]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[184]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[184]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[184]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[184]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[184]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[184]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[184]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[184]->NotRange.Usage                        = 0x0081
+pp_data->cap[184]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[184]->NotRange.StringIndex                  = 0
+pp_data->cap[184]->NotRange.Reserved2                    = 0
+pp_data->cap[184]->NotRange.DesignatorIndex              = 0
+pp_data->cap[184]->NotRange.Reserved3                    = 0
+pp_data->cap[184]->NotRange.DataIndex                    = 97
+pp_data->cap[184]->NotRange.Reserved4                    = 97
+pp_data->cap[184]->NotButton.HasNull                   = 0
+pp_data->cap[184]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[184]->NotButton.LogicalMin                = 0
+pp_data->cap[184]->NotButton.LogicalMax                = 127
+pp_data->cap[184]->NotButton.PhysicalMin               = 0
+pp_data->cap[184]->NotButton.PhysicalMax               = 0
+pp_data->cap[184]->Units                    = 0
+pp_data->cap[184]->UnitsExp                 = 0
+
+pp_data->cap[185]->UsagePage                    = 0xFF01
+pp_data->cap[185]->ReportID                     = 0x81
+pp_data->cap[185]->BitPosition                  = 0
+pp_data->cap[185]->BitSize                      = 8
+pp_data->cap[185]->ReportCount                  = 1
+pp_data->cap[185]->BytePosition                 = 0x0024
+pp_data->cap[185]->BitCount                     = 8
+pp_data->cap[185]->BitField                     = 0x02
+pp_data->cap[185]->NextBytePosition             = 0x0025
+pp_data->cap[185]->LinkCollection               = 0x0004
+pp_data->cap[185]->LinkUsagePage                = 0xFF01
+pp_data->cap[185]->LinkUsage                    = 0x0080
+pp_data->cap[185]->IsMultipleItemsForArray      = 0
+pp_data->cap[185]->IsButtonCap                  = 0
+pp_data->cap[185]->IsPadding                    = 0
+pp_data->cap[185]->IsAbsolute                   = 1
+pp_data->cap[185]->IsRange                      = 0
+pp_data->cap[185]->IsAlias                      = 0
+pp_data->cap[185]->IsStringRange                = 0
+pp_data->cap[185]->IsDesignatorRange            = 0
+pp_data->cap[185]->Reserved1                    = 0x000000
+pp_data->cap[185]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[185]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[185]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[185]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[185]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[185]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[185]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[185]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[185]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[185]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[185]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[185]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[185]->NotRange.Usage                        = 0x0081
+pp_data->cap[185]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[185]->NotRange.StringIndex                  = 0
+pp_data->cap[185]->NotRange.Reserved2                    = 0
+pp_data->cap[185]->NotRange.DesignatorIndex              = 0
+pp_data->cap[185]->NotRange.Reserved3                    = 0
+pp_data->cap[185]->NotRange.DataIndex                    = 98
+pp_data->cap[185]->NotRange.Reserved4                    = 98
+pp_data->cap[185]->NotButton.HasNull                   = 0
+pp_data->cap[185]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[185]->NotButton.LogicalMin                = 0
+pp_data->cap[185]->NotButton.LogicalMax                = 127
+pp_data->cap[185]->NotButton.PhysicalMin               = 0
+pp_data->cap[185]->NotButton.PhysicalMax               = 0
+pp_data->cap[185]->Units                    = 0
+pp_data->cap[185]->UnitsExp                 = 0
+
+pp_data->cap[186]->UsagePage                    = 0xFF01
+pp_data->cap[186]->ReportID                     = 0x81
+pp_data->cap[186]->BitPosition                  = 0
+pp_data->cap[186]->BitSize                      = 8
+pp_data->cap[186]->ReportCount                  = 1
+pp_data->cap[186]->BytePosition                 = 0x0023
+pp_data->cap[186]->BitCount                     = 8
+pp_data->cap[186]->BitField                     = 0x02
+pp_data->cap[186]->NextBytePosition             = 0x0024
+pp_data->cap[186]->LinkCollection               = 0x0004
+pp_data->cap[186]->LinkUsagePage                = 0xFF01
+pp_data->cap[186]->LinkUsage                    = 0x0080
+pp_data->cap[186]->IsMultipleItemsForArray      = 0
+pp_data->cap[186]->IsButtonCap                  = 0
+pp_data->cap[186]->IsPadding                    = 0
+pp_data->cap[186]->IsAbsolute                   = 1
+pp_data->cap[186]->IsRange                      = 0
+pp_data->cap[186]->IsAlias                      = 0
+pp_data->cap[186]->IsStringRange                = 0
+pp_data->cap[186]->IsDesignatorRange            = 0
+pp_data->cap[186]->Reserved1                    = 0x000000
+pp_data->cap[186]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[186]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[186]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[186]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[186]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[186]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[186]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[186]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[186]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[186]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[186]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[186]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[186]->NotRange.Usage                        = 0x0081
+pp_data->cap[186]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[186]->NotRange.StringIndex                  = 0
+pp_data->cap[186]->NotRange.Reserved2                    = 0
+pp_data->cap[186]->NotRange.DesignatorIndex              = 0
+pp_data->cap[186]->NotRange.Reserved3                    = 0
+pp_data->cap[186]->NotRange.DataIndex                    = 99
+pp_data->cap[186]->NotRange.Reserved4                    = 99
+pp_data->cap[186]->NotButton.HasNull                   = 0
+pp_data->cap[186]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[186]->NotButton.LogicalMin                = 0
+pp_data->cap[186]->NotButton.LogicalMax                = 127
+pp_data->cap[186]->NotButton.PhysicalMin               = 0
+pp_data->cap[186]->NotButton.PhysicalMax               = 0
+pp_data->cap[186]->Units                    = 0
+pp_data->cap[186]->UnitsExp                 = 0
+
+pp_data->cap[187]->UsagePage                    = 0xFF01
+pp_data->cap[187]->ReportID                     = 0x81
+pp_data->cap[187]->BitPosition                  = 0
+pp_data->cap[187]->BitSize                      = 8
+pp_data->cap[187]->ReportCount                  = 1
+pp_data->cap[187]->BytePosition                 = 0x0022
+pp_data->cap[187]->BitCount                     = 8
+pp_data->cap[187]->BitField                     = 0x02
+pp_data->cap[187]->NextBytePosition             = 0x0023
+pp_data->cap[187]->LinkCollection               = 0x0004
+pp_data->cap[187]->LinkUsagePage                = 0xFF01
+pp_data->cap[187]->LinkUsage                    = 0x0080
+pp_data->cap[187]->IsMultipleItemsForArray      = 0
+pp_data->cap[187]->IsButtonCap                  = 0
+pp_data->cap[187]->IsPadding                    = 0
+pp_data->cap[187]->IsAbsolute                   = 1
+pp_data->cap[187]->IsRange                      = 0
+pp_data->cap[187]->IsAlias                      = 0
+pp_data->cap[187]->IsStringRange                = 0
+pp_data->cap[187]->IsDesignatorRange            = 0
+pp_data->cap[187]->Reserved1                    = 0x000000
+pp_data->cap[187]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[187]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[187]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[187]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[187]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[187]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[187]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[187]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[187]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[187]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[187]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[187]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[187]->NotRange.Usage                        = 0x0081
+pp_data->cap[187]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[187]->NotRange.StringIndex                  = 0
+pp_data->cap[187]->NotRange.Reserved2                    = 0
+pp_data->cap[187]->NotRange.DesignatorIndex              = 0
+pp_data->cap[187]->NotRange.Reserved3                    = 0
+pp_data->cap[187]->NotRange.DataIndex                    = 100
+pp_data->cap[187]->NotRange.Reserved4                    = 100
+pp_data->cap[187]->NotButton.HasNull                   = 0
+pp_data->cap[187]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[187]->NotButton.LogicalMin                = 0
+pp_data->cap[187]->NotButton.LogicalMax                = 127
+pp_data->cap[187]->NotButton.PhysicalMin               = 0
+pp_data->cap[187]->NotButton.PhysicalMax               = 0
+pp_data->cap[187]->Units                    = 0
+pp_data->cap[187]->UnitsExp                 = 0
+
+pp_data->cap[188]->UsagePage                    = 0xFF01
+pp_data->cap[188]->ReportID                     = 0x81
+pp_data->cap[188]->BitPosition                  = 0
+pp_data->cap[188]->BitSize                      = 8
+pp_data->cap[188]->ReportCount                  = 1
+pp_data->cap[188]->BytePosition                 = 0x0021
+pp_data->cap[188]->BitCount                     = 8
+pp_data->cap[188]->BitField                     = 0x02
+pp_data->cap[188]->NextBytePosition             = 0x0022
+pp_data->cap[188]->LinkCollection               = 0x0004
+pp_data->cap[188]->LinkUsagePage                = 0xFF01
+pp_data->cap[188]->LinkUsage                    = 0x0080
+pp_data->cap[188]->IsMultipleItemsForArray      = 0
+pp_data->cap[188]->IsButtonCap                  = 0
+pp_data->cap[188]->IsPadding                    = 0
+pp_data->cap[188]->IsAbsolute                   = 1
+pp_data->cap[188]->IsRange                      = 0
+pp_data->cap[188]->IsAlias                      = 0
+pp_data->cap[188]->IsStringRange                = 0
+pp_data->cap[188]->IsDesignatorRange            = 0
+pp_data->cap[188]->Reserved1                    = 0x000000
+pp_data->cap[188]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[188]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[188]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[188]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[188]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[188]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[188]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[188]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[188]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[188]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[188]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[188]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[188]->NotRange.Usage                        = 0x0081
+pp_data->cap[188]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[188]->NotRange.StringIndex                  = 0
+pp_data->cap[188]->NotRange.Reserved2                    = 0
+pp_data->cap[188]->NotRange.DesignatorIndex              = 0
+pp_data->cap[188]->NotRange.Reserved3                    = 0
+pp_data->cap[188]->NotRange.DataIndex                    = 101
+pp_data->cap[188]->NotRange.Reserved4                    = 101
+pp_data->cap[188]->NotButton.HasNull                   = 0
+pp_data->cap[188]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[188]->NotButton.LogicalMin                = 0
+pp_data->cap[188]->NotButton.LogicalMax                = 127
+pp_data->cap[188]->NotButton.PhysicalMin               = 0
+pp_data->cap[188]->NotButton.PhysicalMax               = 0
+pp_data->cap[188]->Units                    = 0
+pp_data->cap[188]->UnitsExp                 = 0
+
+pp_data->cap[189]->UsagePage                    = 0xFF01
+pp_data->cap[189]->ReportID                     = 0x81
+pp_data->cap[189]->BitPosition                  = 0
+pp_data->cap[189]->BitSize                      = 8
+pp_data->cap[189]->ReportCount                  = 1
+pp_data->cap[189]->BytePosition                 = 0x0020
+pp_data->cap[189]->BitCount                     = 8
+pp_data->cap[189]->BitField                     = 0x02
+pp_data->cap[189]->NextBytePosition             = 0x0021
+pp_data->cap[189]->LinkCollection               = 0x0004
+pp_data->cap[189]->LinkUsagePage                = 0xFF01
+pp_data->cap[189]->LinkUsage                    = 0x0080
+pp_data->cap[189]->IsMultipleItemsForArray      = 0
+pp_data->cap[189]->IsButtonCap                  = 0
+pp_data->cap[189]->IsPadding                    = 0
+pp_data->cap[189]->IsAbsolute                   = 1
+pp_data->cap[189]->IsRange                      = 0
+pp_data->cap[189]->IsAlias                      = 0
+pp_data->cap[189]->IsStringRange                = 0
+pp_data->cap[189]->IsDesignatorRange            = 0
+pp_data->cap[189]->Reserved1                    = 0x000000
+pp_data->cap[189]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[189]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[189]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[189]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[189]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[189]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[189]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[189]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[189]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[189]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[189]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[189]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[189]->NotRange.Usage                        = 0x0081
+pp_data->cap[189]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[189]->NotRange.StringIndex                  = 0
+pp_data->cap[189]->NotRange.Reserved2                    = 0
+pp_data->cap[189]->NotRange.DesignatorIndex              = 0
+pp_data->cap[189]->NotRange.Reserved3                    = 0
+pp_data->cap[189]->NotRange.DataIndex                    = 102
+pp_data->cap[189]->NotRange.Reserved4                    = 102
+pp_data->cap[189]->NotButton.HasNull                   = 0
+pp_data->cap[189]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[189]->NotButton.LogicalMin                = 0
+pp_data->cap[189]->NotButton.LogicalMax                = 127
+pp_data->cap[189]->NotButton.PhysicalMin               = 0
+pp_data->cap[189]->NotButton.PhysicalMax               = 0
+pp_data->cap[189]->Units                    = 0
+pp_data->cap[189]->UnitsExp                 = 0
+
+pp_data->cap[190]->UsagePage                    = 0xFF01
+pp_data->cap[190]->ReportID                     = 0x81
+pp_data->cap[190]->BitPosition                  = 0
+pp_data->cap[190]->BitSize                      = 8
+pp_data->cap[190]->ReportCount                  = 1
+pp_data->cap[190]->BytePosition                 = 0x001F
+pp_data->cap[190]->BitCount                     = 8
+pp_data->cap[190]->BitField                     = 0x02
+pp_data->cap[190]->NextBytePosition             = 0x0020
+pp_data->cap[190]->LinkCollection               = 0x0004
+pp_data->cap[190]->LinkUsagePage                = 0xFF01
+pp_data->cap[190]->LinkUsage                    = 0x0080
+pp_data->cap[190]->IsMultipleItemsForArray      = 0
+pp_data->cap[190]->IsButtonCap                  = 0
+pp_data->cap[190]->IsPadding                    = 0
+pp_data->cap[190]->IsAbsolute                   = 1
+pp_data->cap[190]->IsRange                      = 0
+pp_data->cap[190]->IsAlias                      = 0
+pp_data->cap[190]->IsStringRange                = 0
+pp_data->cap[190]->IsDesignatorRange            = 0
+pp_data->cap[190]->Reserved1                    = 0x000000
+pp_data->cap[190]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[190]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[190]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[190]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[190]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[190]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[190]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[190]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[190]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[190]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[190]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[190]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[190]->NotRange.Usage                        = 0x0081
+pp_data->cap[190]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[190]->NotRange.StringIndex                  = 0
+pp_data->cap[190]->NotRange.Reserved2                    = 0
+pp_data->cap[190]->NotRange.DesignatorIndex              = 0
+pp_data->cap[190]->NotRange.Reserved3                    = 0
+pp_data->cap[190]->NotRange.DataIndex                    = 103
+pp_data->cap[190]->NotRange.Reserved4                    = 103
+pp_data->cap[190]->NotButton.HasNull                   = 0
+pp_data->cap[190]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[190]->NotButton.LogicalMin                = 0
+pp_data->cap[190]->NotButton.LogicalMax                = 127
+pp_data->cap[190]->NotButton.PhysicalMin               = 0
+pp_data->cap[190]->NotButton.PhysicalMax               = 0
+pp_data->cap[190]->Units                    = 0
+pp_data->cap[190]->UnitsExp                 = 0
+
+pp_data->cap[191]->UsagePage                    = 0xFF01
+pp_data->cap[191]->ReportID                     = 0x81
+pp_data->cap[191]->BitPosition                  = 0
+pp_data->cap[191]->BitSize                      = 8
+pp_data->cap[191]->ReportCount                  = 1
+pp_data->cap[191]->BytePosition                 = 0x001E
+pp_data->cap[191]->BitCount                     = 8
+pp_data->cap[191]->BitField                     = 0x02
+pp_data->cap[191]->NextBytePosition             = 0x001F
+pp_data->cap[191]->LinkCollection               = 0x0004
+pp_data->cap[191]->LinkUsagePage                = 0xFF01
+pp_data->cap[191]->LinkUsage                    = 0x0080
+pp_data->cap[191]->IsMultipleItemsForArray      = 0
+pp_data->cap[191]->IsButtonCap                  = 0
+pp_data->cap[191]->IsPadding                    = 0
+pp_data->cap[191]->IsAbsolute                   = 1
+pp_data->cap[191]->IsRange                      = 0
+pp_data->cap[191]->IsAlias                      = 0
+pp_data->cap[191]->IsStringRange                = 0
+pp_data->cap[191]->IsDesignatorRange            = 0
+pp_data->cap[191]->Reserved1                    = 0x000000
+pp_data->cap[191]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[191]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[191]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[191]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[191]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[191]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[191]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[191]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[191]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[191]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[191]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[191]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[191]->NotRange.Usage                        = 0x0081
+pp_data->cap[191]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[191]->NotRange.StringIndex                  = 0
+pp_data->cap[191]->NotRange.Reserved2                    = 0
+pp_data->cap[191]->NotRange.DesignatorIndex              = 0
+pp_data->cap[191]->NotRange.Reserved3                    = 0
+pp_data->cap[191]->NotRange.DataIndex                    = 104
+pp_data->cap[191]->NotRange.Reserved4                    = 104
+pp_data->cap[191]->NotButton.HasNull                   = 0
+pp_data->cap[191]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[191]->NotButton.LogicalMin                = 0
+pp_data->cap[191]->NotButton.LogicalMax                = 127
+pp_data->cap[191]->NotButton.PhysicalMin               = 0
+pp_data->cap[191]->NotButton.PhysicalMax               = 0
+pp_data->cap[191]->Units                    = 0
+pp_data->cap[191]->UnitsExp                 = 0
+
+pp_data->cap[192]->UsagePage                    = 0xFF01
+pp_data->cap[192]->ReportID                     = 0x81
+pp_data->cap[192]->BitPosition                  = 0
+pp_data->cap[192]->BitSize                      = 8
+pp_data->cap[192]->ReportCount                  = 1
+pp_data->cap[192]->BytePosition                 = 0x001D
+pp_data->cap[192]->BitCount                     = 8
+pp_data->cap[192]->BitField                     = 0x02
+pp_data->cap[192]->NextBytePosition             = 0x001E
+pp_data->cap[192]->LinkCollection               = 0x0004
+pp_data->cap[192]->LinkUsagePage                = 0xFF01
+pp_data->cap[192]->LinkUsage                    = 0x0080
+pp_data->cap[192]->IsMultipleItemsForArray      = 0
+pp_data->cap[192]->IsButtonCap                  = 0
+pp_data->cap[192]->IsPadding                    = 0
+pp_data->cap[192]->IsAbsolute                   = 1
+pp_data->cap[192]->IsRange                      = 0
+pp_data->cap[192]->IsAlias                      = 0
+pp_data->cap[192]->IsStringRange                = 0
+pp_data->cap[192]->IsDesignatorRange            = 0
+pp_data->cap[192]->Reserved1                    = 0x000000
+pp_data->cap[192]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[192]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[192]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[192]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[192]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[192]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[192]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[192]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[192]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[192]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[192]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[192]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[192]->NotRange.Usage                        = 0x0081
+pp_data->cap[192]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[192]->NotRange.StringIndex                  = 0
+pp_data->cap[192]->NotRange.Reserved2                    = 0
+pp_data->cap[192]->NotRange.DesignatorIndex              = 0
+pp_data->cap[192]->NotRange.Reserved3                    = 0
+pp_data->cap[192]->NotRange.DataIndex                    = 105
+pp_data->cap[192]->NotRange.Reserved4                    = 105
+pp_data->cap[192]->NotButton.HasNull                   = 0
+pp_data->cap[192]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[192]->NotButton.LogicalMin                = 0
+pp_data->cap[192]->NotButton.LogicalMax                = 127
+pp_data->cap[192]->NotButton.PhysicalMin               = 0
+pp_data->cap[192]->NotButton.PhysicalMax               = 0
+pp_data->cap[192]->Units                    = 0
+pp_data->cap[192]->UnitsExp                 = 0
+
+pp_data->cap[193]->UsagePage                    = 0xFF01
+pp_data->cap[193]->ReportID                     = 0x81
+pp_data->cap[193]->BitPosition                  = 0
+pp_data->cap[193]->BitSize                      = 8
+pp_data->cap[193]->ReportCount                  = 1
+pp_data->cap[193]->BytePosition                 = 0x001C
+pp_data->cap[193]->BitCount                     = 8
+pp_data->cap[193]->BitField                     = 0x02
+pp_data->cap[193]->NextBytePosition             = 0x001D
+pp_data->cap[193]->LinkCollection               = 0x0004
+pp_data->cap[193]->LinkUsagePage                = 0xFF01
+pp_data->cap[193]->LinkUsage                    = 0x0080
+pp_data->cap[193]->IsMultipleItemsForArray      = 0
+pp_data->cap[193]->IsButtonCap                  = 0
+pp_data->cap[193]->IsPadding                    = 0
+pp_data->cap[193]->IsAbsolute                   = 1
+pp_data->cap[193]->IsRange                      = 0
+pp_data->cap[193]->IsAlias                      = 0
+pp_data->cap[193]->IsStringRange                = 0
+pp_data->cap[193]->IsDesignatorRange            = 0
+pp_data->cap[193]->Reserved1                    = 0x000000
+pp_data->cap[193]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[193]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[193]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[193]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[193]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[193]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[193]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[193]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[193]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[193]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[193]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[193]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[193]->NotRange.Usage                        = 0x0081
+pp_data->cap[193]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[193]->NotRange.StringIndex                  = 0
+pp_data->cap[193]->NotRange.Reserved2                    = 0
+pp_data->cap[193]->NotRange.DesignatorIndex              = 0
+pp_data->cap[193]->NotRange.Reserved3                    = 0
+pp_data->cap[193]->NotRange.DataIndex                    = 106
+pp_data->cap[193]->NotRange.Reserved4                    = 106
+pp_data->cap[193]->NotButton.HasNull                   = 0
+pp_data->cap[193]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[193]->NotButton.LogicalMin                = 0
+pp_data->cap[193]->NotButton.LogicalMax                = 127
+pp_data->cap[193]->NotButton.PhysicalMin               = 0
+pp_data->cap[193]->NotButton.PhysicalMax               = 0
+pp_data->cap[193]->Units                    = 0
+pp_data->cap[193]->UnitsExp                 = 0
+
+pp_data->cap[194]->UsagePage                    = 0xFF01
+pp_data->cap[194]->ReportID                     = 0x81
+pp_data->cap[194]->BitPosition                  = 0
+pp_data->cap[194]->BitSize                      = 8
+pp_data->cap[194]->ReportCount                  = 1
+pp_data->cap[194]->BytePosition                 = 0x001B
+pp_data->cap[194]->BitCount                     = 8
+pp_data->cap[194]->BitField                     = 0x02
+pp_data->cap[194]->NextBytePosition             = 0x001C
+pp_data->cap[194]->LinkCollection               = 0x0004
+pp_data->cap[194]->LinkUsagePage                = 0xFF01
+pp_data->cap[194]->LinkUsage                    = 0x0080
+pp_data->cap[194]->IsMultipleItemsForArray      = 0
+pp_data->cap[194]->IsButtonCap                  = 0
+pp_data->cap[194]->IsPadding                    = 0
+pp_data->cap[194]->IsAbsolute                   = 1
+pp_data->cap[194]->IsRange                      = 0
+pp_data->cap[194]->IsAlias                      = 0
+pp_data->cap[194]->IsStringRange                = 0
+pp_data->cap[194]->IsDesignatorRange            = 0
+pp_data->cap[194]->Reserved1                    = 0x000000
+pp_data->cap[194]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[194]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[194]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[194]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[194]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[194]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[194]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[194]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[194]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[194]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[194]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[194]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[194]->NotRange.Usage                        = 0x0081
+pp_data->cap[194]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[194]->NotRange.StringIndex                  = 0
+pp_data->cap[194]->NotRange.Reserved2                    = 0
+pp_data->cap[194]->NotRange.DesignatorIndex              = 0
+pp_data->cap[194]->NotRange.Reserved3                    = 0
+pp_data->cap[194]->NotRange.DataIndex                    = 107
+pp_data->cap[194]->NotRange.Reserved4                    = 107
+pp_data->cap[194]->NotButton.HasNull                   = 0
+pp_data->cap[194]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[194]->NotButton.LogicalMin                = 0
+pp_data->cap[194]->NotButton.LogicalMax                = 127
+pp_data->cap[194]->NotButton.PhysicalMin               = 0
+pp_data->cap[194]->NotButton.PhysicalMax               = 0
+pp_data->cap[194]->Units                    = 0
+pp_data->cap[194]->UnitsExp                 = 0
+
+pp_data->cap[195]->UsagePage                    = 0xFF01
+pp_data->cap[195]->ReportID                     = 0x81
+pp_data->cap[195]->BitPosition                  = 0
+pp_data->cap[195]->BitSize                      = 8
+pp_data->cap[195]->ReportCount                  = 1
+pp_data->cap[195]->BytePosition                 = 0x001A
+pp_data->cap[195]->BitCount                     = 8
+pp_data->cap[195]->BitField                     = 0x02
+pp_data->cap[195]->NextBytePosition             = 0x001B
+pp_data->cap[195]->LinkCollection               = 0x0004
+pp_data->cap[195]->LinkUsagePage                = 0xFF01
+pp_data->cap[195]->LinkUsage                    = 0x0080
+pp_data->cap[195]->IsMultipleItemsForArray      = 0
+pp_data->cap[195]->IsButtonCap                  = 0
+pp_data->cap[195]->IsPadding                    = 0
+pp_data->cap[195]->IsAbsolute                   = 1
+pp_data->cap[195]->IsRange                      = 0
+pp_data->cap[195]->IsAlias                      = 0
+pp_data->cap[195]->IsStringRange                = 0
+pp_data->cap[195]->IsDesignatorRange            = 0
+pp_data->cap[195]->Reserved1                    = 0x000000
+pp_data->cap[195]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[195]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[195]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[195]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[195]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[195]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[195]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[195]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[195]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[195]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[195]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[195]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[195]->NotRange.Usage                        = 0x0081
+pp_data->cap[195]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[195]->NotRange.StringIndex                  = 0
+pp_data->cap[195]->NotRange.Reserved2                    = 0
+pp_data->cap[195]->NotRange.DesignatorIndex              = 0
+pp_data->cap[195]->NotRange.Reserved3                    = 0
+pp_data->cap[195]->NotRange.DataIndex                    = 108
+pp_data->cap[195]->NotRange.Reserved4                    = 108
+pp_data->cap[195]->NotButton.HasNull                   = 0
+pp_data->cap[195]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[195]->NotButton.LogicalMin                = 0
+pp_data->cap[195]->NotButton.LogicalMax                = 127
+pp_data->cap[195]->NotButton.PhysicalMin               = 0
+pp_data->cap[195]->NotButton.PhysicalMax               = 0
+pp_data->cap[195]->Units                    = 0
+pp_data->cap[195]->UnitsExp                 = 0
+
+pp_data->cap[196]->UsagePage                    = 0xFF01
+pp_data->cap[196]->ReportID                     = 0x81
+pp_data->cap[196]->BitPosition                  = 0
+pp_data->cap[196]->BitSize                      = 8
+pp_data->cap[196]->ReportCount                  = 1
+pp_data->cap[196]->BytePosition                 = 0x0019
+pp_data->cap[196]->BitCount                     = 8
+pp_data->cap[196]->BitField                     = 0x02
+pp_data->cap[196]->NextBytePosition             = 0x001A
+pp_data->cap[196]->LinkCollection               = 0x0004
+pp_data->cap[196]->LinkUsagePage                = 0xFF01
+pp_data->cap[196]->LinkUsage                    = 0x0080
+pp_data->cap[196]->IsMultipleItemsForArray      = 0
+pp_data->cap[196]->IsButtonCap                  = 0
+pp_data->cap[196]->IsPadding                    = 0
+pp_data->cap[196]->IsAbsolute                   = 1
+pp_data->cap[196]->IsRange                      = 0
+pp_data->cap[196]->IsAlias                      = 0
+pp_data->cap[196]->IsStringRange                = 0
+pp_data->cap[196]->IsDesignatorRange            = 0
+pp_data->cap[196]->Reserved1                    = 0x000000
+pp_data->cap[196]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[196]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[196]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[196]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[196]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[196]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[196]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[196]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[196]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[196]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[196]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[196]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[196]->NotRange.Usage                        = 0x0081
+pp_data->cap[196]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[196]->NotRange.StringIndex                  = 0
+pp_data->cap[196]->NotRange.Reserved2                    = 0
+pp_data->cap[196]->NotRange.DesignatorIndex              = 0
+pp_data->cap[196]->NotRange.Reserved3                    = 0
+pp_data->cap[196]->NotRange.DataIndex                    = 109
+pp_data->cap[196]->NotRange.Reserved4                    = 109
+pp_data->cap[196]->NotButton.HasNull                   = 0
+pp_data->cap[196]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[196]->NotButton.LogicalMin                = 0
+pp_data->cap[196]->NotButton.LogicalMax                = 127
+pp_data->cap[196]->NotButton.PhysicalMin               = 0
+pp_data->cap[196]->NotButton.PhysicalMax               = 0
+pp_data->cap[196]->Units                    = 0
+pp_data->cap[196]->UnitsExp                 = 0
+
+pp_data->cap[197]->UsagePage                    = 0xFF01
+pp_data->cap[197]->ReportID                     = 0x81
+pp_data->cap[197]->BitPosition                  = 0
+pp_data->cap[197]->BitSize                      = 8
+pp_data->cap[197]->ReportCount                  = 1
+pp_data->cap[197]->BytePosition                 = 0x0018
+pp_data->cap[197]->BitCount                     = 8
+pp_data->cap[197]->BitField                     = 0x02
+pp_data->cap[197]->NextBytePosition             = 0x0019
+pp_data->cap[197]->LinkCollection               = 0x0004
+pp_data->cap[197]->LinkUsagePage                = 0xFF01
+pp_data->cap[197]->LinkUsage                    = 0x0080
+pp_data->cap[197]->IsMultipleItemsForArray      = 0
+pp_data->cap[197]->IsButtonCap                  = 0
+pp_data->cap[197]->IsPadding                    = 0
+pp_data->cap[197]->IsAbsolute                   = 1
+pp_data->cap[197]->IsRange                      = 0
+pp_data->cap[197]->IsAlias                      = 0
+pp_data->cap[197]->IsStringRange                = 0
+pp_data->cap[197]->IsDesignatorRange            = 0
+pp_data->cap[197]->Reserved1                    = 0x000000
+pp_data->cap[197]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[197]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[197]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[197]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[197]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[197]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[197]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[197]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[197]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[197]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[197]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[197]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[197]->NotRange.Usage                        = 0x0081
+pp_data->cap[197]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[197]->NotRange.StringIndex                  = 0
+pp_data->cap[197]->NotRange.Reserved2                    = 0
+pp_data->cap[197]->NotRange.DesignatorIndex              = 0
+pp_data->cap[197]->NotRange.Reserved3                    = 0
+pp_data->cap[197]->NotRange.DataIndex                    = 110
+pp_data->cap[197]->NotRange.Reserved4                    = 110
+pp_data->cap[197]->NotButton.HasNull                   = 0
+pp_data->cap[197]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[197]->NotButton.LogicalMin                = 0
+pp_data->cap[197]->NotButton.LogicalMax                = 127
+pp_data->cap[197]->NotButton.PhysicalMin               = 0
+pp_data->cap[197]->NotButton.PhysicalMax               = 0
+pp_data->cap[197]->Units                    = 0
+pp_data->cap[197]->UnitsExp                 = 0
+
+pp_data->cap[198]->UsagePage                    = 0xFF01
+pp_data->cap[198]->ReportID                     = 0x81
+pp_data->cap[198]->BitPosition                  = 0
+pp_data->cap[198]->BitSize                      = 8
+pp_data->cap[198]->ReportCount                  = 1
+pp_data->cap[198]->BytePosition                 = 0x0017
+pp_data->cap[198]->BitCount                     = 8
+pp_data->cap[198]->BitField                     = 0x02
+pp_data->cap[198]->NextBytePosition             = 0x0018
+pp_data->cap[198]->LinkCollection               = 0x0004
+pp_data->cap[198]->LinkUsagePage                = 0xFF01
+pp_data->cap[198]->LinkUsage                    = 0x0080
+pp_data->cap[198]->IsMultipleItemsForArray      = 0
+pp_data->cap[198]->IsButtonCap                  = 0
+pp_data->cap[198]->IsPadding                    = 0
+pp_data->cap[198]->IsAbsolute                   = 1
+pp_data->cap[198]->IsRange                      = 0
+pp_data->cap[198]->IsAlias                      = 0
+pp_data->cap[198]->IsStringRange                = 0
+pp_data->cap[198]->IsDesignatorRange            = 0
+pp_data->cap[198]->Reserved1                    = 0x000000
+pp_data->cap[198]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[198]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[198]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[198]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[198]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[198]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[198]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[198]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[198]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[198]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[198]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[198]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[198]->NotRange.Usage                        = 0x0081
+pp_data->cap[198]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[198]->NotRange.StringIndex                  = 0
+pp_data->cap[198]->NotRange.Reserved2                    = 0
+pp_data->cap[198]->NotRange.DesignatorIndex              = 0
+pp_data->cap[198]->NotRange.Reserved3                    = 0
+pp_data->cap[198]->NotRange.DataIndex                    = 111
+pp_data->cap[198]->NotRange.Reserved4                    = 111
+pp_data->cap[198]->NotButton.HasNull                   = 0
+pp_data->cap[198]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[198]->NotButton.LogicalMin                = 0
+pp_data->cap[198]->NotButton.LogicalMax                = 127
+pp_data->cap[198]->NotButton.PhysicalMin               = 0
+pp_data->cap[198]->NotButton.PhysicalMax               = 0
+pp_data->cap[198]->Units                    = 0
+pp_data->cap[198]->UnitsExp                 = 0
+
+pp_data->cap[199]->UsagePage                    = 0xFF01
+pp_data->cap[199]->ReportID                     = 0x81
+pp_data->cap[199]->BitPosition                  = 0
+pp_data->cap[199]->BitSize                      = 8
+pp_data->cap[199]->ReportCount                  = 1
+pp_data->cap[199]->BytePosition                 = 0x0016
+pp_data->cap[199]->BitCount                     = 8
+pp_data->cap[199]->BitField                     = 0x02
+pp_data->cap[199]->NextBytePosition             = 0x0017
+pp_data->cap[199]->LinkCollection               = 0x0004
+pp_data->cap[199]->LinkUsagePage                = 0xFF01
+pp_data->cap[199]->LinkUsage                    = 0x0080
+pp_data->cap[199]->IsMultipleItemsForArray      = 0
+pp_data->cap[199]->IsButtonCap                  = 0
+pp_data->cap[199]->IsPadding                    = 0
+pp_data->cap[199]->IsAbsolute                   = 1
+pp_data->cap[199]->IsRange                      = 0
+pp_data->cap[199]->IsAlias                      = 0
+pp_data->cap[199]->IsStringRange                = 0
+pp_data->cap[199]->IsDesignatorRange            = 0
+pp_data->cap[199]->Reserved1                    = 0x000000
+pp_data->cap[199]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[199]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[199]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[199]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[199]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[199]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[199]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[199]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[199]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[199]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[199]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[199]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[199]->NotRange.Usage                        = 0x0081
+pp_data->cap[199]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[199]->NotRange.StringIndex                  = 0
+pp_data->cap[199]->NotRange.Reserved2                    = 0
+pp_data->cap[199]->NotRange.DesignatorIndex              = 0
+pp_data->cap[199]->NotRange.Reserved3                    = 0
+pp_data->cap[199]->NotRange.DataIndex                    = 112
+pp_data->cap[199]->NotRange.Reserved4                    = 112
+pp_data->cap[199]->NotButton.HasNull                   = 0
+pp_data->cap[199]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[199]->NotButton.LogicalMin                = 0
+pp_data->cap[199]->NotButton.LogicalMax                = 127
+pp_data->cap[199]->NotButton.PhysicalMin               = 0
+pp_data->cap[199]->NotButton.PhysicalMax               = 0
+pp_data->cap[199]->Units                    = 0
+pp_data->cap[199]->UnitsExp                 = 0
+
+pp_data->cap[200]->UsagePage                    = 0xFF01
+pp_data->cap[200]->ReportID                     = 0x81
+pp_data->cap[200]->BitPosition                  = 0
+pp_data->cap[200]->BitSize                      = 8
+pp_data->cap[200]->ReportCount                  = 1
+pp_data->cap[200]->BytePosition                 = 0x0015
+pp_data->cap[200]->BitCount                     = 8
+pp_data->cap[200]->BitField                     = 0x02
+pp_data->cap[200]->NextBytePosition             = 0x0016
+pp_data->cap[200]->LinkCollection               = 0x0004
+pp_data->cap[200]->LinkUsagePage                = 0xFF01
+pp_data->cap[200]->LinkUsage                    = 0x0080
+pp_data->cap[200]->IsMultipleItemsForArray      = 0
+pp_data->cap[200]->IsButtonCap                  = 0
+pp_data->cap[200]->IsPadding                    = 0
+pp_data->cap[200]->IsAbsolute                   = 1
+pp_data->cap[200]->IsRange                      = 0
+pp_data->cap[200]->IsAlias                      = 0
+pp_data->cap[200]->IsStringRange                = 0
+pp_data->cap[200]->IsDesignatorRange            = 0
+pp_data->cap[200]->Reserved1                    = 0x000000
+pp_data->cap[200]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[200]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[200]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[200]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[200]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[200]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[200]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[200]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[200]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[200]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[200]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[200]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[200]->NotRange.Usage                        = 0x0081
+pp_data->cap[200]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[200]->NotRange.StringIndex                  = 0
+pp_data->cap[200]->NotRange.Reserved2                    = 0
+pp_data->cap[200]->NotRange.DesignatorIndex              = 0
+pp_data->cap[200]->NotRange.Reserved3                    = 0
+pp_data->cap[200]->NotRange.DataIndex                    = 113
+pp_data->cap[200]->NotRange.Reserved4                    = 113
+pp_data->cap[200]->NotButton.HasNull                   = 0
+pp_data->cap[200]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[200]->NotButton.LogicalMin                = 0
+pp_data->cap[200]->NotButton.LogicalMax                = 127
+pp_data->cap[200]->NotButton.PhysicalMin               = 0
+pp_data->cap[200]->NotButton.PhysicalMax               = 0
+pp_data->cap[200]->Units                    = 0
+pp_data->cap[200]->UnitsExp                 = 0
+
+pp_data->cap[201]->UsagePage                    = 0xFF01
+pp_data->cap[201]->ReportID                     = 0x81
+pp_data->cap[201]->BitPosition                  = 0
+pp_data->cap[201]->BitSize                      = 8
+pp_data->cap[201]->ReportCount                  = 1
+pp_data->cap[201]->BytePosition                 = 0x0014
+pp_data->cap[201]->BitCount                     = 8
+pp_data->cap[201]->BitField                     = 0x02
+pp_data->cap[201]->NextBytePosition             = 0x0015
+pp_data->cap[201]->LinkCollection               = 0x0004
+pp_data->cap[201]->LinkUsagePage                = 0xFF01
+pp_data->cap[201]->LinkUsage                    = 0x0080
+pp_data->cap[201]->IsMultipleItemsForArray      = 0
+pp_data->cap[201]->IsButtonCap                  = 0
+pp_data->cap[201]->IsPadding                    = 0
+pp_data->cap[201]->IsAbsolute                   = 1
+pp_data->cap[201]->IsRange                      = 0
+pp_data->cap[201]->IsAlias                      = 0
+pp_data->cap[201]->IsStringRange                = 0
+pp_data->cap[201]->IsDesignatorRange            = 0
+pp_data->cap[201]->Reserved1                    = 0x000000
+pp_data->cap[201]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[201]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[201]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[201]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[201]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[201]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[201]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[201]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[201]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[201]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[201]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[201]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[201]->NotRange.Usage                        = 0x0081
+pp_data->cap[201]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[201]->NotRange.StringIndex                  = 0
+pp_data->cap[201]->NotRange.Reserved2                    = 0
+pp_data->cap[201]->NotRange.DesignatorIndex              = 0
+pp_data->cap[201]->NotRange.Reserved3                    = 0
+pp_data->cap[201]->NotRange.DataIndex                    = 114
+pp_data->cap[201]->NotRange.Reserved4                    = 114
+pp_data->cap[201]->NotButton.HasNull                   = 0
+pp_data->cap[201]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[201]->NotButton.LogicalMin                = 0
+pp_data->cap[201]->NotButton.LogicalMax                = 127
+pp_data->cap[201]->NotButton.PhysicalMin               = 0
+pp_data->cap[201]->NotButton.PhysicalMax               = 0
+pp_data->cap[201]->Units                    = 0
+pp_data->cap[201]->UnitsExp                 = 0
+
+pp_data->cap[202]->UsagePage                    = 0xFF01
+pp_data->cap[202]->ReportID                     = 0x81
+pp_data->cap[202]->BitPosition                  = 0
+pp_data->cap[202]->BitSize                      = 8
+pp_data->cap[202]->ReportCount                  = 1
+pp_data->cap[202]->BytePosition                 = 0x0013
+pp_data->cap[202]->BitCount                     = 8
+pp_data->cap[202]->BitField                     = 0x02
+pp_data->cap[202]->NextBytePosition             = 0x0014
+pp_data->cap[202]->LinkCollection               = 0x0004
+pp_data->cap[202]->LinkUsagePage                = 0xFF01
+pp_data->cap[202]->LinkUsage                    = 0x0080
+pp_data->cap[202]->IsMultipleItemsForArray      = 0
+pp_data->cap[202]->IsButtonCap                  = 0
+pp_data->cap[202]->IsPadding                    = 0
+pp_data->cap[202]->IsAbsolute                   = 1
+pp_data->cap[202]->IsRange                      = 0
+pp_data->cap[202]->IsAlias                      = 0
+pp_data->cap[202]->IsStringRange                = 0
+pp_data->cap[202]->IsDesignatorRange            = 0
+pp_data->cap[202]->Reserved1                    = 0x000000
+pp_data->cap[202]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[202]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[202]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[202]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[202]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[202]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[202]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[202]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[202]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[202]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[202]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[202]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[202]->NotRange.Usage                        = 0x0081
+pp_data->cap[202]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[202]->NotRange.StringIndex                  = 0
+pp_data->cap[202]->NotRange.Reserved2                    = 0
+pp_data->cap[202]->NotRange.DesignatorIndex              = 0
+pp_data->cap[202]->NotRange.Reserved3                    = 0
+pp_data->cap[202]->NotRange.DataIndex                    = 115
+pp_data->cap[202]->NotRange.Reserved4                    = 115
+pp_data->cap[202]->NotButton.HasNull                   = 0
+pp_data->cap[202]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[202]->NotButton.LogicalMin                = 0
+pp_data->cap[202]->NotButton.LogicalMax                = 127
+pp_data->cap[202]->NotButton.PhysicalMin               = 0
+pp_data->cap[202]->NotButton.PhysicalMax               = 0
+pp_data->cap[202]->Units                    = 0
+pp_data->cap[202]->UnitsExp                 = 0
+
+pp_data->cap[203]->UsagePage                    = 0xFF01
+pp_data->cap[203]->ReportID                     = 0x81
+pp_data->cap[203]->BitPosition                  = 0
+pp_data->cap[203]->BitSize                      = 8
+pp_data->cap[203]->ReportCount                  = 1
+pp_data->cap[203]->BytePosition                 = 0x0012
+pp_data->cap[203]->BitCount                     = 8
+pp_data->cap[203]->BitField                     = 0x02
+pp_data->cap[203]->NextBytePosition             = 0x0013
+pp_data->cap[203]->LinkCollection               = 0x0004
+pp_data->cap[203]->LinkUsagePage                = 0xFF01
+pp_data->cap[203]->LinkUsage                    = 0x0080
+pp_data->cap[203]->IsMultipleItemsForArray      = 0
+pp_data->cap[203]->IsButtonCap                  = 0
+pp_data->cap[203]->IsPadding                    = 0
+pp_data->cap[203]->IsAbsolute                   = 1
+pp_data->cap[203]->IsRange                      = 0
+pp_data->cap[203]->IsAlias                      = 0
+pp_data->cap[203]->IsStringRange                = 0
+pp_data->cap[203]->IsDesignatorRange            = 0
+pp_data->cap[203]->Reserved1                    = 0x000000
+pp_data->cap[203]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[203]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[203]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[203]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[203]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[203]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[203]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[203]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[203]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[203]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[203]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[203]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[203]->NotRange.Usage                        = 0x0081
+pp_data->cap[203]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[203]->NotRange.StringIndex                  = 0
+pp_data->cap[203]->NotRange.Reserved2                    = 0
+pp_data->cap[203]->NotRange.DesignatorIndex              = 0
+pp_data->cap[203]->NotRange.Reserved3                    = 0
+pp_data->cap[203]->NotRange.DataIndex                    = 116
+pp_data->cap[203]->NotRange.Reserved4                    = 116
+pp_data->cap[203]->NotButton.HasNull                   = 0
+pp_data->cap[203]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[203]->NotButton.LogicalMin                = 0
+pp_data->cap[203]->NotButton.LogicalMax                = 127
+pp_data->cap[203]->NotButton.PhysicalMin               = 0
+pp_data->cap[203]->NotButton.PhysicalMax               = 0
+pp_data->cap[203]->Units                    = 0
+pp_data->cap[203]->UnitsExp                 = 0
+
+pp_data->cap[204]->UsagePage                    = 0xFF01
+pp_data->cap[204]->ReportID                     = 0x81
+pp_data->cap[204]->BitPosition                  = 0
+pp_data->cap[204]->BitSize                      = 8
+pp_data->cap[204]->ReportCount                  = 1
+pp_data->cap[204]->BytePosition                 = 0x0011
+pp_data->cap[204]->BitCount                     = 8
+pp_data->cap[204]->BitField                     = 0x02
+pp_data->cap[204]->NextBytePosition             = 0x0012
+pp_data->cap[204]->LinkCollection               = 0x0004
+pp_data->cap[204]->LinkUsagePage                = 0xFF01
+pp_data->cap[204]->LinkUsage                    = 0x0080
+pp_data->cap[204]->IsMultipleItemsForArray      = 0
+pp_data->cap[204]->IsButtonCap                  = 0
+pp_data->cap[204]->IsPadding                    = 0
+pp_data->cap[204]->IsAbsolute                   = 1
+pp_data->cap[204]->IsRange                      = 0
+pp_data->cap[204]->IsAlias                      = 0
+pp_data->cap[204]->IsStringRange                = 0
+pp_data->cap[204]->IsDesignatorRange            = 0
+pp_data->cap[204]->Reserved1                    = 0x000000
+pp_data->cap[204]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[204]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[204]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[204]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[204]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[204]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[204]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[204]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[204]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[204]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[204]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[204]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[204]->NotRange.Usage                        = 0x0081
+pp_data->cap[204]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[204]->NotRange.StringIndex                  = 0
+pp_data->cap[204]->NotRange.Reserved2                    = 0
+pp_data->cap[204]->NotRange.DesignatorIndex              = 0
+pp_data->cap[204]->NotRange.Reserved3                    = 0
+pp_data->cap[204]->NotRange.DataIndex                    = 117
+pp_data->cap[204]->NotRange.Reserved4                    = 117
+pp_data->cap[204]->NotButton.HasNull                   = 0
+pp_data->cap[204]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[204]->NotButton.LogicalMin                = 0
+pp_data->cap[204]->NotButton.LogicalMax                = 127
+pp_data->cap[204]->NotButton.PhysicalMin               = 0
+pp_data->cap[204]->NotButton.PhysicalMax               = 0
+pp_data->cap[204]->Units                    = 0
+pp_data->cap[204]->UnitsExp                 = 0
+
+pp_data->cap[205]->UsagePage                    = 0xFF01
+pp_data->cap[205]->ReportID                     = 0x81
+pp_data->cap[205]->BitPosition                  = 0
+pp_data->cap[205]->BitSize                      = 8
+pp_data->cap[205]->ReportCount                  = 1
+pp_data->cap[205]->BytePosition                 = 0x0010
+pp_data->cap[205]->BitCount                     = 8
+pp_data->cap[205]->BitField                     = 0x02
+pp_data->cap[205]->NextBytePosition             = 0x0011
+pp_data->cap[205]->LinkCollection               = 0x0004
+pp_data->cap[205]->LinkUsagePage                = 0xFF01
+pp_data->cap[205]->LinkUsage                    = 0x0080
+pp_data->cap[205]->IsMultipleItemsForArray      = 0
+pp_data->cap[205]->IsButtonCap                  = 0
+pp_data->cap[205]->IsPadding                    = 0
+pp_data->cap[205]->IsAbsolute                   = 1
+pp_data->cap[205]->IsRange                      = 0
+pp_data->cap[205]->IsAlias                      = 0
+pp_data->cap[205]->IsStringRange                = 0
+pp_data->cap[205]->IsDesignatorRange            = 0
+pp_data->cap[205]->Reserved1                    = 0x000000
+pp_data->cap[205]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[205]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[205]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[205]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[205]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[205]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[205]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[205]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[205]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[205]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[205]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[205]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[205]->NotRange.Usage                        = 0x0081
+pp_data->cap[205]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[205]->NotRange.StringIndex                  = 0
+pp_data->cap[205]->NotRange.Reserved2                    = 0
+pp_data->cap[205]->NotRange.DesignatorIndex              = 0
+pp_data->cap[205]->NotRange.Reserved3                    = 0
+pp_data->cap[205]->NotRange.DataIndex                    = 118
+pp_data->cap[205]->NotRange.Reserved4                    = 118
+pp_data->cap[205]->NotButton.HasNull                   = 0
+pp_data->cap[205]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[205]->NotButton.LogicalMin                = 0
+pp_data->cap[205]->NotButton.LogicalMax                = 127
+pp_data->cap[205]->NotButton.PhysicalMin               = 0
+pp_data->cap[205]->NotButton.PhysicalMax               = 0
+pp_data->cap[205]->Units                    = 0
+pp_data->cap[205]->UnitsExp                 = 0
+
+pp_data->cap[206]->UsagePage                    = 0xFF01
+pp_data->cap[206]->ReportID                     = 0x81
+pp_data->cap[206]->BitPosition                  = 0
+pp_data->cap[206]->BitSize                      = 8
+pp_data->cap[206]->ReportCount                  = 1
+pp_data->cap[206]->BytePosition                 = 0x000F
+pp_data->cap[206]->BitCount                     = 8
+pp_data->cap[206]->BitField                     = 0x02
+pp_data->cap[206]->NextBytePosition             = 0x0010
+pp_data->cap[206]->LinkCollection               = 0x0004
+pp_data->cap[206]->LinkUsagePage                = 0xFF01
+pp_data->cap[206]->LinkUsage                    = 0x0080
+pp_data->cap[206]->IsMultipleItemsForArray      = 0
+pp_data->cap[206]->IsButtonCap                  = 0
+pp_data->cap[206]->IsPadding                    = 0
+pp_data->cap[206]->IsAbsolute                   = 1
+pp_data->cap[206]->IsRange                      = 0
+pp_data->cap[206]->IsAlias                      = 0
+pp_data->cap[206]->IsStringRange                = 0
+pp_data->cap[206]->IsDesignatorRange            = 0
+pp_data->cap[206]->Reserved1                    = 0x000000
+pp_data->cap[206]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[206]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[206]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[206]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[206]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[206]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[206]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[206]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[206]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[206]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[206]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[206]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[206]->NotRange.Usage                        = 0x0081
+pp_data->cap[206]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[206]->NotRange.StringIndex                  = 0
+pp_data->cap[206]->NotRange.Reserved2                    = 0
+pp_data->cap[206]->NotRange.DesignatorIndex              = 0
+pp_data->cap[206]->NotRange.Reserved3                    = 0
+pp_data->cap[206]->NotRange.DataIndex                    = 119
+pp_data->cap[206]->NotRange.Reserved4                    = 119
+pp_data->cap[206]->NotButton.HasNull                   = 0
+pp_data->cap[206]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[206]->NotButton.LogicalMin                = 0
+pp_data->cap[206]->NotButton.LogicalMax                = 127
+pp_data->cap[206]->NotButton.PhysicalMin               = 0
+pp_data->cap[206]->NotButton.PhysicalMax               = 0
+pp_data->cap[206]->Units                    = 0
+pp_data->cap[206]->UnitsExp                 = 0
+
+pp_data->cap[207]->UsagePage                    = 0xFF01
+pp_data->cap[207]->ReportID                     = 0x81
+pp_data->cap[207]->BitPosition                  = 0
+pp_data->cap[207]->BitSize                      = 8
+pp_data->cap[207]->ReportCount                  = 1
+pp_data->cap[207]->BytePosition                 = 0x000E
+pp_data->cap[207]->BitCount                     = 8
+pp_data->cap[207]->BitField                     = 0x02
+pp_data->cap[207]->NextBytePosition             = 0x000F
+pp_data->cap[207]->LinkCollection               = 0x0004
+pp_data->cap[207]->LinkUsagePage                = 0xFF01
+pp_data->cap[207]->LinkUsage                    = 0x0080
+pp_data->cap[207]->IsMultipleItemsForArray      = 0
+pp_data->cap[207]->IsButtonCap                  = 0
+pp_data->cap[207]->IsPadding                    = 0
+pp_data->cap[207]->IsAbsolute                   = 1
+pp_data->cap[207]->IsRange                      = 0
+pp_data->cap[207]->IsAlias                      = 0
+pp_data->cap[207]->IsStringRange                = 0
+pp_data->cap[207]->IsDesignatorRange            = 0
+pp_data->cap[207]->Reserved1                    = 0x000000
+pp_data->cap[207]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[207]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[207]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[207]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[207]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[207]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[207]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[207]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[207]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[207]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[207]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[207]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[207]->NotRange.Usage                        = 0x0081
+pp_data->cap[207]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[207]->NotRange.StringIndex                  = 0
+pp_data->cap[207]->NotRange.Reserved2                    = 0
+pp_data->cap[207]->NotRange.DesignatorIndex              = 0
+pp_data->cap[207]->NotRange.Reserved3                    = 0
+pp_data->cap[207]->NotRange.DataIndex                    = 120
+pp_data->cap[207]->NotRange.Reserved4                    = 120
+pp_data->cap[207]->NotButton.HasNull                   = 0
+pp_data->cap[207]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[207]->NotButton.LogicalMin                = 0
+pp_data->cap[207]->NotButton.LogicalMax                = 127
+pp_data->cap[207]->NotButton.PhysicalMin               = 0
+pp_data->cap[207]->NotButton.PhysicalMax               = 0
+pp_data->cap[207]->Units                    = 0
+pp_data->cap[207]->UnitsExp                 = 0
+
+pp_data->cap[208]->UsagePage                    = 0xFF01
+pp_data->cap[208]->ReportID                     = 0x81
+pp_data->cap[208]->BitPosition                  = 0
+pp_data->cap[208]->BitSize                      = 8
+pp_data->cap[208]->ReportCount                  = 1
+pp_data->cap[208]->BytePosition                 = 0x000D
+pp_data->cap[208]->BitCount                     = 8
+pp_data->cap[208]->BitField                     = 0x02
+pp_data->cap[208]->NextBytePosition             = 0x000E
+pp_data->cap[208]->LinkCollection               = 0x0004
+pp_data->cap[208]->LinkUsagePage                = 0xFF01
+pp_data->cap[208]->LinkUsage                    = 0x0080
+pp_data->cap[208]->IsMultipleItemsForArray      = 0
+pp_data->cap[208]->IsButtonCap                  = 0
+pp_data->cap[208]->IsPadding                    = 0
+pp_data->cap[208]->IsAbsolute                   = 1
+pp_data->cap[208]->IsRange                      = 0
+pp_data->cap[208]->IsAlias                      = 0
+pp_data->cap[208]->IsStringRange                = 0
+pp_data->cap[208]->IsDesignatorRange            = 0
+pp_data->cap[208]->Reserved1                    = 0x000000
+pp_data->cap[208]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[208]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[208]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[208]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[208]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[208]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[208]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[208]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[208]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[208]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[208]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[208]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[208]->NotRange.Usage                        = 0x0081
+pp_data->cap[208]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[208]->NotRange.StringIndex                  = 0
+pp_data->cap[208]->NotRange.Reserved2                    = 0
+pp_data->cap[208]->NotRange.DesignatorIndex              = 0
+pp_data->cap[208]->NotRange.Reserved3                    = 0
+pp_data->cap[208]->NotRange.DataIndex                    = 121
+pp_data->cap[208]->NotRange.Reserved4                    = 121
+pp_data->cap[208]->NotButton.HasNull                   = 0
+pp_data->cap[208]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[208]->NotButton.LogicalMin                = 0
+pp_data->cap[208]->NotButton.LogicalMax                = 127
+pp_data->cap[208]->NotButton.PhysicalMin               = 0
+pp_data->cap[208]->NotButton.PhysicalMax               = 0
+pp_data->cap[208]->Units                    = 0
+pp_data->cap[208]->UnitsExp                 = 0
+
+pp_data->cap[209]->UsagePage                    = 0xFF01
+pp_data->cap[209]->ReportID                     = 0x81
+pp_data->cap[209]->BitPosition                  = 0
+pp_data->cap[209]->BitSize                      = 8
+pp_data->cap[209]->ReportCount                  = 1
+pp_data->cap[209]->BytePosition                 = 0x000C
+pp_data->cap[209]->BitCount                     = 8
+pp_data->cap[209]->BitField                     = 0x02
+pp_data->cap[209]->NextBytePosition             = 0x000D
+pp_data->cap[209]->LinkCollection               = 0x0004
+pp_data->cap[209]->LinkUsagePage                = 0xFF01
+pp_data->cap[209]->LinkUsage                    = 0x0080
+pp_data->cap[209]->IsMultipleItemsForArray      = 0
+pp_data->cap[209]->IsButtonCap                  = 0
+pp_data->cap[209]->IsPadding                    = 0
+pp_data->cap[209]->IsAbsolute                   = 1
+pp_data->cap[209]->IsRange                      = 0
+pp_data->cap[209]->IsAlias                      = 0
+pp_data->cap[209]->IsStringRange                = 0
+pp_data->cap[209]->IsDesignatorRange            = 0
+pp_data->cap[209]->Reserved1                    = 0x000000
+pp_data->cap[209]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[209]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[209]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[209]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[209]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[209]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[209]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[209]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[209]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[209]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[209]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[209]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[209]->NotRange.Usage                        = 0x0081
+pp_data->cap[209]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[209]->NotRange.StringIndex                  = 0
+pp_data->cap[209]->NotRange.Reserved2                    = 0
+pp_data->cap[209]->NotRange.DesignatorIndex              = 0
+pp_data->cap[209]->NotRange.Reserved3                    = 0
+pp_data->cap[209]->NotRange.DataIndex                    = 122
+pp_data->cap[209]->NotRange.Reserved4                    = 122
+pp_data->cap[209]->NotButton.HasNull                   = 0
+pp_data->cap[209]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[209]->NotButton.LogicalMin                = 0
+pp_data->cap[209]->NotButton.LogicalMax                = 127
+pp_data->cap[209]->NotButton.PhysicalMin               = 0
+pp_data->cap[209]->NotButton.PhysicalMax               = 0
+pp_data->cap[209]->Units                    = 0
+pp_data->cap[209]->UnitsExp                 = 0
+
+pp_data->cap[210]->UsagePage                    = 0xFF01
+pp_data->cap[210]->ReportID                     = 0x81
+pp_data->cap[210]->BitPosition                  = 0
+pp_data->cap[210]->BitSize                      = 8
+pp_data->cap[210]->ReportCount                  = 1
+pp_data->cap[210]->BytePosition                 = 0x000B
+pp_data->cap[210]->BitCount                     = 8
+pp_data->cap[210]->BitField                     = 0x02
+pp_data->cap[210]->NextBytePosition             = 0x000C
+pp_data->cap[210]->LinkCollection               = 0x0004
+pp_data->cap[210]->LinkUsagePage                = 0xFF01
+pp_data->cap[210]->LinkUsage                    = 0x0080
+pp_data->cap[210]->IsMultipleItemsForArray      = 0
+pp_data->cap[210]->IsButtonCap                  = 0
+pp_data->cap[210]->IsPadding                    = 0
+pp_data->cap[210]->IsAbsolute                   = 1
+pp_data->cap[210]->IsRange                      = 0
+pp_data->cap[210]->IsAlias                      = 0
+pp_data->cap[210]->IsStringRange                = 0
+pp_data->cap[210]->IsDesignatorRange            = 0
+pp_data->cap[210]->Reserved1                    = 0x000000
+pp_data->cap[210]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[210]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[210]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[210]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[210]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[210]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[210]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[210]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[210]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[210]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[210]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[210]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[210]->NotRange.Usage                        = 0x0081
+pp_data->cap[210]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[210]->NotRange.StringIndex                  = 0
+pp_data->cap[210]->NotRange.Reserved2                    = 0
+pp_data->cap[210]->NotRange.DesignatorIndex              = 0
+pp_data->cap[210]->NotRange.Reserved3                    = 0
+pp_data->cap[210]->NotRange.DataIndex                    = 123
+pp_data->cap[210]->NotRange.Reserved4                    = 123
+pp_data->cap[210]->NotButton.HasNull                   = 0
+pp_data->cap[210]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[210]->NotButton.LogicalMin                = 0
+pp_data->cap[210]->NotButton.LogicalMax                = 127
+pp_data->cap[210]->NotButton.PhysicalMin               = 0
+pp_data->cap[210]->NotButton.PhysicalMax               = 0
+pp_data->cap[210]->Units                    = 0
+pp_data->cap[210]->UnitsExp                 = 0
+
+pp_data->cap[211]->UsagePage                    = 0xFF01
+pp_data->cap[211]->ReportID                     = 0x81
+pp_data->cap[211]->BitPosition                  = 0
+pp_data->cap[211]->BitSize                      = 8
+pp_data->cap[211]->ReportCount                  = 1
+pp_data->cap[211]->BytePosition                 = 0x000A
+pp_data->cap[211]->BitCount                     = 8
+pp_data->cap[211]->BitField                     = 0x02
+pp_data->cap[211]->NextBytePosition             = 0x000B
+pp_data->cap[211]->LinkCollection               = 0x0004
+pp_data->cap[211]->LinkUsagePage                = 0xFF01
+pp_data->cap[211]->LinkUsage                    = 0x0080
+pp_data->cap[211]->IsMultipleItemsForArray      = 0
+pp_data->cap[211]->IsButtonCap                  = 0
+pp_data->cap[211]->IsPadding                    = 0
+pp_data->cap[211]->IsAbsolute                   = 1
+pp_data->cap[211]->IsRange                      = 0
+pp_data->cap[211]->IsAlias                      = 0
+pp_data->cap[211]->IsStringRange                = 0
+pp_data->cap[211]->IsDesignatorRange            = 0
+pp_data->cap[211]->Reserved1                    = 0x000000
+pp_data->cap[211]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[211]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[211]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[211]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[211]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[211]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[211]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[211]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[211]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[211]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[211]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[211]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[211]->NotRange.Usage                        = 0x0081
+pp_data->cap[211]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[211]->NotRange.StringIndex                  = 0
+pp_data->cap[211]->NotRange.Reserved2                    = 0
+pp_data->cap[211]->NotRange.DesignatorIndex              = 0
+pp_data->cap[211]->NotRange.Reserved3                    = 0
+pp_data->cap[211]->NotRange.DataIndex                    = 124
+pp_data->cap[211]->NotRange.Reserved4                    = 124
+pp_data->cap[211]->NotButton.HasNull                   = 0
+pp_data->cap[211]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[211]->NotButton.LogicalMin                = 0
+pp_data->cap[211]->NotButton.LogicalMax                = 127
+pp_data->cap[211]->NotButton.PhysicalMin               = 0
+pp_data->cap[211]->NotButton.PhysicalMax               = 0
+pp_data->cap[211]->Units                    = 0
+pp_data->cap[211]->UnitsExp                 = 0
+
+pp_data->cap[212]->UsagePage                    = 0xFF01
+pp_data->cap[212]->ReportID                     = 0x81
+pp_data->cap[212]->BitPosition                  = 0
+pp_data->cap[212]->BitSize                      = 8
+pp_data->cap[212]->ReportCount                  = 1
+pp_data->cap[212]->BytePosition                 = 0x0009
+pp_data->cap[212]->BitCount                     = 8
+pp_data->cap[212]->BitField                     = 0x02
+pp_data->cap[212]->NextBytePosition             = 0x000A
+pp_data->cap[212]->LinkCollection               = 0x0004
+pp_data->cap[212]->LinkUsagePage                = 0xFF01
+pp_data->cap[212]->LinkUsage                    = 0x0080
+pp_data->cap[212]->IsMultipleItemsForArray      = 0
+pp_data->cap[212]->IsButtonCap                  = 0
+pp_data->cap[212]->IsPadding                    = 0
+pp_data->cap[212]->IsAbsolute                   = 1
+pp_data->cap[212]->IsRange                      = 0
+pp_data->cap[212]->IsAlias                      = 0
+pp_data->cap[212]->IsStringRange                = 0
+pp_data->cap[212]->IsDesignatorRange            = 0
+pp_data->cap[212]->Reserved1                    = 0x000000
+pp_data->cap[212]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[212]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[212]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[212]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[212]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[212]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[212]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[212]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[212]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[212]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[212]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[212]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[212]->NotRange.Usage                        = 0x0081
+pp_data->cap[212]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[212]->NotRange.StringIndex                  = 0
+pp_data->cap[212]->NotRange.Reserved2                    = 0
+pp_data->cap[212]->NotRange.DesignatorIndex              = 0
+pp_data->cap[212]->NotRange.Reserved3                    = 0
+pp_data->cap[212]->NotRange.DataIndex                    = 125
+pp_data->cap[212]->NotRange.Reserved4                    = 125
+pp_data->cap[212]->NotButton.HasNull                   = 0
+pp_data->cap[212]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[212]->NotButton.LogicalMin                = 0
+pp_data->cap[212]->NotButton.LogicalMax                = 127
+pp_data->cap[212]->NotButton.PhysicalMin               = 0
+pp_data->cap[212]->NotButton.PhysicalMax               = 0
+pp_data->cap[212]->Units                    = 0
+pp_data->cap[212]->UnitsExp                 = 0
+
+pp_data->cap[213]->UsagePage                    = 0xFF01
+pp_data->cap[213]->ReportID                     = 0x81
+pp_data->cap[213]->BitPosition                  = 0
+pp_data->cap[213]->BitSize                      = 8
+pp_data->cap[213]->ReportCount                  = 1
+pp_data->cap[213]->BytePosition                 = 0x0008
+pp_data->cap[213]->BitCount                     = 8
+pp_data->cap[213]->BitField                     = 0x02
+pp_data->cap[213]->NextBytePosition             = 0x0009
+pp_data->cap[213]->LinkCollection               = 0x0004
+pp_data->cap[213]->LinkUsagePage                = 0xFF01
+pp_data->cap[213]->LinkUsage                    = 0x0080
+pp_data->cap[213]->IsMultipleItemsForArray      = 0
+pp_data->cap[213]->IsButtonCap                  = 0
+pp_data->cap[213]->IsPadding                    = 0
+pp_data->cap[213]->IsAbsolute                   = 1
+pp_data->cap[213]->IsRange                      = 0
+pp_data->cap[213]->IsAlias                      = 0
+pp_data->cap[213]->IsStringRange                = 0
+pp_data->cap[213]->IsDesignatorRange            = 0
+pp_data->cap[213]->Reserved1                    = 0x000000
+pp_data->cap[213]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[213]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[213]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[213]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[213]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[213]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[213]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[213]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[213]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[213]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[213]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[213]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[213]->NotRange.Usage                        = 0x0081
+pp_data->cap[213]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[213]->NotRange.StringIndex                  = 0
+pp_data->cap[213]->NotRange.Reserved2                    = 0
+pp_data->cap[213]->NotRange.DesignatorIndex              = 0
+pp_data->cap[213]->NotRange.Reserved3                    = 0
+pp_data->cap[213]->NotRange.DataIndex                    = 126
+pp_data->cap[213]->NotRange.Reserved4                    = 126
+pp_data->cap[213]->NotButton.HasNull                   = 0
+pp_data->cap[213]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[213]->NotButton.LogicalMin                = 0
+pp_data->cap[213]->NotButton.LogicalMax                = 127
+pp_data->cap[213]->NotButton.PhysicalMin               = 0
+pp_data->cap[213]->NotButton.PhysicalMax               = 0
+pp_data->cap[213]->Units                    = 0
+pp_data->cap[213]->UnitsExp                 = 0
+
+pp_data->cap[214]->UsagePage                    = 0xFF01
+pp_data->cap[214]->ReportID                     = 0x81
+pp_data->cap[214]->BitPosition                  = 0
+pp_data->cap[214]->BitSize                      = 8
+pp_data->cap[214]->ReportCount                  = 1
+pp_data->cap[214]->BytePosition                 = 0x0007
+pp_data->cap[214]->BitCount                     = 8
+pp_data->cap[214]->BitField                     = 0x02
+pp_data->cap[214]->NextBytePosition             = 0x0008
+pp_data->cap[214]->LinkCollection               = 0x0004
+pp_data->cap[214]->LinkUsagePage                = 0xFF01
+pp_data->cap[214]->LinkUsage                    = 0x0080
+pp_data->cap[214]->IsMultipleItemsForArray      = 0
+pp_data->cap[214]->IsButtonCap                  = 0
+pp_data->cap[214]->IsPadding                    = 0
+pp_data->cap[214]->IsAbsolute                   = 1
+pp_data->cap[214]->IsRange                      = 0
+pp_data->cap[214]->IsAlias                      = 0
+pp_data->cap[214]->IsStringRange                = 0
+pp_data->cap[214]->IsDesignatorRange            = 0
+pp_data->cap[214]->Reserved1                    = 0x000000
+pp_data->cap[214]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[214]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[214]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[214]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[214]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[214]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[214]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[214]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[214]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[214]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[214]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[214]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[214]->NotRange.Usage                        = 0x0081
+pp_data->cap[214]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[214]->NotRange.StringIndex                  = 0
+pp_data->cap[214]->NotRange.Reserved2                    = 0
+pp_data->cap[214]->NotRange.DesignatorIndex              = 0
+pp_data->cap[214]->NotRange.Reserved3                    = 0
+pp_data->cap[214]->NotRange.DataIndex                    = 127
+pp_data->cap[214]->NotRange.Reserved4                    = 127
+pp_data->cap[214]->NotButton.HasNull                   = 0
+pp_data->cap[214]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[214]->NotButton.LogicalMin                = 0
+pp_data->cap[214]->NotButton.LogicalMax                = 127
+pp_data->cap[214]->NotButton.PhysicalMin               = 0
+pp_data->cap[214]->NotButton.PhysicalMax               = 0
+pp_data->cap[214]->Units                    = 0
+pp_data->cap[214]->UnitsExp                 = 0
+
+pp_data->cap[215]->UsagePage                    = 0xFF01
+pp_data->cap[215]->ReportID                     = 0x81
+pp_data->cap[215]->BitPosition                  = 0
+pp_data->cap[215]->BitSize                      = 8
+pp_data->cap[215]->ReportCount                  = 1
+pp_data->cap[215]->BytePosition                 = 0x0006
+pp_data->cap[215]->BitCount                     = 8
+pp_data->cap[215]->BitField                     = 0x02
+pp_data->cap[215]->NextBytePosition             = 0x0007
+pp_data->cap[215]->LinkCollection               = 0x0004
+pp_data->cap[215]->LinkUsagePage                = 0xFF01
+pp_data->cap[215]->LinkUsage                    = 0x0080
+pp_data->cap[215]->IsMultipleItemsForArray      = 0
+pp_data->cap[215]->IsButtonCap                  = 0
+pp_data->cap[215]->IsPadding                    = 0
+pp_data->cap[215]->IsAbsolute                   = 1
+pp_data->cap[215]->IsRange                      = 0
+pp_data->cap[215]->IsAlias                      = 0
+pp_data->cap[215]->IsStringRange                = 0
+pp_data->cap[215]->IsDesignatorRange            = 0
+pp_data->cap[215]->Reserved1                    = 0x000000
+pp_data->cap[215]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[215]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[215]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[215]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[215]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[215]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[215]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[215]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[215]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[215]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[215]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[215]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[215]->NotRange.Usage                        = 0x0081
+pp_data->cap[215]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[215]->NotRange.StringIndex                  = 0
+pp_data->cap[215]->NotRange.Reserved2                    = 0
+pp_data->cap[215]->NotRange.DesignatorIndex              = 0
+pp_data->cap[215]->NotRange.Reserved3                    = 0
+pp_data->cap[215]->NotRange.DataIndex                    = 128
+pp_data->cap[215]->NotRange.Reserved4                    = 128
+pp_data->cap[215]->NotButton.HasNull                   = 0
+pp_data->cap[215]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[215]->NotButton.LogicalMin                = 0
+pp_data->cap[215]->NotButton.LogicalMax                = 127
+pp_data->cap[215]->NotButton.PhysicalMin               = 0
+pp_data->cap[215]->NotButton.PhysicalMax               = 0
+pp_data->cap[215]->Units                    = 0
+pp_data->cap[215]->UnitsExp                 = 0
+
+pp_data->cap[216]->UsagePage                    = 0xFF01
+pp_data->cap[216]->ReportID                     = 0x81
+pp_data->cap[216]->BitPosition                  = 0
+pp_data->cap[216]->BitSize                      = 8
+pp_data->cap[216]->ReportCount                  = 1
+pp_data->cap[216]->BytePosition                 = 0x0005
+pp_data->cap[216]->BitCount                     = 8
+pp_data->cap[216]->BitField                     = 0x02
+pp_data->cap[216]->NextBytePosition             = 0x0006
+pp_data->cap[216]->LinkCollection               = 0x0004
+pp_data->cap[216]->LinkUsagePage                = 0xFF01
+pp_data->cap[216]->LinkUsage                    = 0x0080
+pp_data->cap[216]->IsMultipleItemsForArray      = 0
+pp_data->cap[216]->IsButtonCap                  = 0
+pp_data->cap[216]->IsPadding                    = 0
+pp_data->cap[216]->IsAbsolute                   = 1
+pp_data->cap[216]->IsRange                      = 0
+pp_data->cap[216]->IsAlias                      = 0
+pp_data->cap[216]->IsStringRange                = 0
+pp_data->cap[216]->IsDesignatorRange            = 0
+pp_data->cap[216]->Reserved1                    = 0x000000
+pp_data->cap[216]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[216]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[216]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[216]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[216]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[216]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[216]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[216]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[216]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[216]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[216]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[216]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[216]->NotRange.Usage                        = 0x0081
+pp_data->cap[216]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[216]->NotRange.StringIndex                  = 0
+pp_data->cap[216]->NotRange.Reserved2                    = 0
+pp_data->cap[216]->NotRange.DesignatorIndex              = 0
+pp_data->cap[216]->NotRange.Reserved3                    = 0
+pp_data->cap[216]->NotRange.DataIndex                    = 129
+pp_data->cap[216]->NotRange.Reserved4                    = 129
+pp_data->cap[216]->NotButton.HasNull                   = 0
+pp_data->cap[216]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[216]->NotButton.LogicalMin                = 0
+pp_data->cap[216]->NotButton.LogicalMax                = 127
+pp_data->cap[216]->NotButton.PhysicalMin               = 0
+pp_data->cap[216]->NotButton.PhysicalMax               = 0
+pp_data->cap[216]->Units                    = 0
+pp_data->cap[216]->UnitsExp                 = 0
+
+pp_data->cap[217]->UsagePage                    = 0xFF01
+pp_data->cap[217]->ReportID                     = 0x81
+pp_data->cap[217]->BitPosition                  = 0
+pp_data->cap[217]->BitSize                      = 8
+pp_data->cap[217]->ReportCount                  = 1
+pp_data->cap[217]->BytePosition                 = 0x0004
+pp_data->cap[217]->BitCount                     = 8
+pp_data->cap[217]->BitField                     = 0x02
+pp_data->cap[217]->NextBytePosition             = 0x0005
+pp_data->cap[217]->LinkCollection               = 0x0004
+pp_data->cap[217]->LinkUsagePage                = 0xFF01
+pp_data->cap[217]->LinkUsage                    = 0x0080
+pp_data->cap[217]->IsMultipleItemsForArray      = 0
+pp_data->cap[217]->IsButtonCap                  = 0
+pp_data->cap[217]->IsPadding                    = 0
+pp_data->cap[217]->IsAbsolute                   = 1
+pp_data->cap[217]->IsRange                      = 0
+pp_data->cap[217]->IsAlias                      = 0
+pp_data->cap[217]->IsStringRange                = 0
+pp_data->cap[217]->IsDesignatorRange            = 0
+pp_data->cap[217]->Reserved1                    = 0x000000
+pp_data->cap[217]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[217]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[217]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[217]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[217]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[217]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[217]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[217]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[217]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[217]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[217]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[217]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[217]->NotRange.Usage                        = 0x0081
+pp_data->cap[217]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[217]->NotRange.StringIndex                  = 0
+pp_data->cap[217]->NotRange.Reserved2                    = 0
+pp_data->cap[217]->NotRange.DesignatorIndex              = 0
+pp_data->cap[217]->NotRange.Reserved3                    = 0
+pp_data->cap[217]->NotRange.DataIndex                    = 130
+pp_data->cap[217]->NotRange.Reserved4                    = 130
+pp_data->cap[217]->NotButton.HasNull                   = 0
+pp_data->cap[217]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[217]->NotButton.LogicalMin                = 0
+pp_data->cap[217]->NotButton.LogicalMax                = 127
+pp_data->cap[217]->NotButton.PhysicalMin               = 0
+pp_data->cap[217]->NotButton.PhysicalMax               = 0
+pp_data->cap[217]->Units                    = 0
+pp_data->cap[217]->UnitsExp                 = 0
+
+pp_data->cap[218]->UsagePage                    = 0xFF01
+pp_data->cap[218]->ReportID                     = 0x81
+pp_data->cap[218]->BitPosition                  = 0
+pp_data->cap[218]->BitSize                      = 8
+pp_data->cap[218]->ReportCount                  = 1
+pp_data->cap[218]->BytePosition                 = 0x0003
+pp_data->cap[218]->BitCount                     = 8
+pp_data->cap[218]->BitField                     = 0x02
+pp_data->cap[218]->NextBytePosition             = 0x0004
+pp_data->cap[218]->LinkCollection               = 0x0004
+pp_data->cap[218]->LinkUsagePage                = 0xFF01
+pp_data->cap[218]->LinkUsage                    = 0x0080
+pp_data->cap[218]->IsMultipleItemsForArray      = 0
+pp_data->cap[218]->IsButtonCap                  = 0
+pp_data->cap[218]->IsPadding                    = 0
+pp_data->cap[218]->IsAbsolute                   = 1
+pp_data->cap[218]->IsRange                      = 0
+pp_data->cap[218]->IsAlias                      = 0
+pp_data->cap[218]->IsStringRange                = 0
+pp_data->cap[218]->IsDesignatorRange            = 0
+pp_data->cap[218]->Reserved1                    = 0x000000
+pp_data->cap[218]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[218]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[218]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[218]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[218]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[218]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[218]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[218]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[218]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[218]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[218]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[218]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[218]->NotRange.Usage                        = 0x0081
+pp_data->cap[218]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[218]->NotRange.StringIndex                  = 0
+pp_data->cap[218]->NotRange.Reserved2                    = 0
+pp_data->cap[218]->NotRange.DesignatorIndex              = 0
+pp_data->cap[218]->NotRange.Reserved3                    = 0
+pp_data->cap[218]->NotRange.DataIndex                    = 131
+pp_data->cap[218]->NotRange.Reserved4                    = 131
+pp_data->cap[218]->NotButton.HasNull                   = 0
+pp_data->cap[218]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[218]->NotButton.LogicalMin                = 0
+pp_data->cap[218]->NotButton.LogicalMax                = 127
+pp_data->cap[218]->NotButton.PhysicalMin               = 0
+pp_data->cap[218]->NotButton.PhysicalMax               = 0
+pp_data->cap[218]->Units                    = 0
+pp_data->cap[218]->UnitsExp                 = 0
+
+pp_data->cap[219]->UsagePage                    = 0xFF01
+pp_data->cap[219]->ReportID                     = 0x81
+pp_data->cap[219]->BitPosition                  = 0
+pp_data->cap[219]->BitSize                      = 8
+pp_data->cap[219]->ReportCount                  = 1
+pp_data->cap[219]->BytePosition                 = 0x0002
+pp_data->cap[219]->BitCount                     = 8
+pp_data->cap[219]->BitField                     = 0x02
+pp_data->cap[219]->NextBytePosition             = 0x0003
+pp_data->cap[219]->LinkCollection               = 0x0004
+pp_data->cap[219]->LinkUsagePage                = 0xFF01
+pp_data->cap[219]->LinkUsage                    = 0x0080
+pp_data->cap[219]->IsMultipleItemsForArray      = 0
+pp_data->cap[219]->IsButtonCap                  = 0
+pp_data->cap[219]->IsPadding                    = 0
+pp_data->cap[219]->IsAbsolute                   = 1
+pp_data->cap[219]->IsRange                      = 0
+pp_data->cap[219]->IsAlias                      = 0
+pp_data->cap[219]->IsStringRange                = 0
+pp_data->cap[219]->IsDesignatorRange            = 0
+pp_data->cap[219]->Reserved1                    = 0x000000
+pp_data->cap[219]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[219]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[219]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[219]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[219]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[219]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[219]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[219]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[219]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[219]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[219]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[219]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[219]->NotRange.Usage                        = 0x0081
+pp_data->cap[219]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[219]->NotRange.StringIndex                  = 0
+pp_data->cap[219]->NotRange.Reserved2                    = 0
+pp_data->cap[219]->NotRange.DesignatorIndex              = 0
+pp_data->cap[219]->NotRange.Reserved3                    = 0
+pp_data->cap[219]->NotRange.DataIndex                    = 132
+pp_data->cap[219]->NotRange.Reserved4                    = 132
+pp_data->cap[219]->NotButton.HasNull                   = 0
+pp_data->cap[219]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[219]->NotButton.LogicalMin                = 0
+pp_data->cap[219]->NotButton.LogicalMax                = 127
+pp_data->cap[219]->NotButton.PhysicalMin               = 0
+pp_data->cap[219]->NotButton.PhysicalMax               = 0
+pp_data->cap[219]->Units                    = 0
+pp_data->cap[219]->UnitsExp                 = 0
+
+pp_data->cap[220]->UsagePage                    = 0xFF01
+pp_data->cap[220]->ReportID                     = 0x81
+pp_data->cap[220]->BitPosition                  = 0
+pp_data->cap[220]->BitSize                      = 8
+pp_data->cap[220]->ReportCount                  = 1
+pp_data->cap[220]->BytePosition                 = 0x0001
+pp_data->cap[220]->BitCount                     = 8
+pp_data->cap[220]->BitField                     = 0x02
+pp_data->cap[220]->NextBytePosition             = 0x0002
+pp_data->cap[220]->LinkCollection               = 0x0004
+pp_data->cap[220]->LinkUsagePage                = 0xFF01
+pp_data->cap[220]->LinkUsage                    = 0x0080
+pp_data->cap[220]->IsMultipleItemsForArray      = 0
+pp_data->cap[220]->IsButtonCap                  = 0
+pp_data->cap[220]->IsPadding                    = 0
+pp_data->cap[220]->IsAbsolute                   = 1
+pp_data->cap[220]->IsRange                      = 0
+pp_data->cap[220]->IsAlias                      = 0
+pp_data->cap[220]->IsStringRange                = 0
+pp_data->cap[220]->IsDesignatorRange            = 0
+pp_data->cap[220]->Reserved1                    = 0x000000
+pp_data->cap[220]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[220]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[220]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[220]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[220]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[220]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[220]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[220]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[220]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[220]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[220]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[220]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[220]->NotRange.Usage                        = 0x0081
+pp_data->cap[220]->NotRange.Reserved1                    = 0x0081
+pp_data->cap[220]->NotRange.StringIndex                  = 0
+pp_data->cap[220]->NotRange.Reserved2                    = 0
+pp_data->cap[220]->NotRange.DesignatorIndex              = 0
+pp_data->cap[220]->NotRange.Reserved3                    = 0
+pp_data->cap[220]->NotRange.DataIndex                    = 133
+pp_data->cap[220]->NotRange.Reserved4                    = 133
+pp_data->cap[220]->NotButton.HasNull                   = 0
+pp_data->cap[220]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[220]->NotButton.LogicalMin                = 0
+pp_data->cap[220]->NotButton.LogicalMax                = 127
+pp_data->cap[220]->NotButton.PhysicalMin               = 0
+pp_data->cap[220]->NotButton.PhysicalMax               = 0
+pp_data->cap[220]->Units                    = 0
+pp_data->cap[220]->UnitsExp                 = 0
+
+# Feature hid_pp_cap struct:
+pp_data->cap[221]->UsagePage                    = 0xFF01
+pp_data->cap[221]->ReportID                     = 0xD0
+pp_data->cap[221]->BitPosition                  = 0
+pp_data->cap[221]->BitSize                      = 8
+pp_data->cap[221]->ReportCount                  = 32
+pp_data->cap[221]->BytePosition                 = 0x0001
+pp_data->cap[221]->BitCount                     = 256
+pp_data->cap[221]->BitField                     = 0x82
+pp_data->cap[221]->NextBytePosition             = 0x0021
+pp_data->cap[221]->LinkCollection               = 0x0005
+pp_data->cap[221]->LinkUsagePage                = 0xFF01
+pp_data->cap[221]->LinkUsage                    = 0x00D0
+pp_data->cap[221]->IsMultipleItemsForArray      = 0
+pp_data->cap[221]->IsButtonCap                  = 0
+pp_data->cap[221]->IsPadding                    = 0
+pp_data->cap[221]->IsAbsolute                   = 1
+pp_data->cap[221]->IsRange                      = 0
+pp_data->cap[221]->IsAlias                      = 0
+pp_data->cap[221]->IsStringRange                = 0
+pp_data->cap[221]->IsDesignatorRange            = 0
+pp_data->cap[221]->Reserved1                    = 0x000000
+pp_data->cap[221]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[221]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[221]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[221]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[221]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[221]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[221]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[221]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[221]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[221]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[221]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[221]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[221]->NotRange.Usage                        = 0x00D1
+pp_data->cap[221]->NotRange.Reserved1                    = 0x00D1
+pp_data->cap[221]->NotRange.StringIndex                  = 0
+pp_data->cap[221]->NotRange.Reserved2                    = 0
+pp_data->cap[221]->NotRange.DesignatorIndex              = 0
+pp_data->cap[221]->NotRange.Reserved3                    = 0
+pp_data->cap[221]->NotRange.DataIndex                    = 0
+pp_data->cap[221]->NotRange.Reserved4                    = 0
+pp_data->cap[221]->NotButton.HasNull                   = 0
+pp_data->cap[221]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[221]->NotButton.LogicalMin                = 0
+pp_data->cap[221]->NotButton.LogicalMax                = 255
+pp_data->cap[221]->NotButton.PhysicalMin               = 0
+pp_data->cap[221]->NotButton.PhysicalMax               = 0
+pp_data->cap[221]->Units                    = 0
+pp_data->cap[221]->UnitsExp                 = 0
+
+pp_data->cap[222]->UsagePage                    = 0xFF01
+pp_data->cap[222]->ReportID                     = 0xD1
+pp_data->cap[222]->BitPosition                  = 0
+pp_data->cap[222]->BitSize                      = 8
+pp_data->cap[222]->ReportCount                  = 32
+pp_data->cap[222]->BytePosition                 = 0x0001
+pp_data->cap[222]->BitCount                     = 256
+pp_data->cap[222]->BitField                     = 0x82
+pp_data->cap[222]->NextBytePosition             = 0x0021
+pp_data->cap[222]->LinkCollection               = 0x0006
+pp_data->cap[222]->LinkUsagePage                = 0xFF01
+pp_data->cap[222]->LinkUsage                    = 0x00D0
+pp_data->cap[222]->IsMultipleItemsForArray      = 0
+pp_data->cap[222]->IsButtonCap                  = 0
+pp_data->cap[222]->IsPadding                    = 0
+pp_data->cap[222]->IsAbsolute                   = 1
+pp_data->cap[222]->IsRange                      = 0
+pp_data->cap[222]->IsAlias                      = 0
+pp_data->cap[222]->IsStringRange                = 0
+pp_data->cap[222]->IsDesignatorRange            = 0
+pp_data->cap[222]->Reserved1                    = 0x000000
+pp_data->cap[222]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[222]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[222]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[222]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[222]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[222]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[222]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[222]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[222]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[222]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[222]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[222]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[222]->NotRange.Usage                        = 0x00D1
+pp_data->cap[222]->NotRange.Reserved1                    = 0x00D1
+pp_data->cap[222]->NotRange.StringIndex                  = 0
+pp_data->cap[222]->NotRange.Reserved2                    = 0
+pp_data->cap[222]->NotRange.DesignatorIndex              = 0
+pp_data->cap[222]->NotRange.Reserved3                    = 0
+pp_data->cap[222]->NotRange.DataIndex                    = 1
+pp_data->cap[222]->NotRange.Reserved4                    = 1
+pp_data->cap[222]->NotButton.HasNull                   = 0
+pp_data->cap[222]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[222]->NotButton.LogicalMin                = 0
+pp_data->cap[222]->NotButton.LogicalMax                = 255
+pp_data->cap[222]->NotButton.PhysicalMin               = 0
+pp_data->cap[222]->NotButton.PhysicalMax               = 0
+pp_data->cap[222]->Units                    = 0
+pp_data->cap[222]->UnitsExp                 = 0
+
+pp_data->cap[223]->UsagePage                    = 0xFF01
+pp_data->cap[223]->ReportID                     = 0xD2
+pp_data->cap[223]->BitPosition                  = 0
+pp_data->cap[223]->BitSize                      = 8
+pp_data->cap[223]->ReportCount                  = 32
+pp_data->cap[223]->BytePosition                 = 0x0001
+pp_data->cap[223]->BitCount                     = 256
+pp_data->cap[223]->BitField                     = 0x82
+pp_data->cap[223]->NextBytePosition             = 0x0021
+pp_data->cap[223]->LinkCollection               = 0x0007
+pp_data->cap[223]->LinkUsagePage                = 0xFF01
+pp_data->cap[223]->LinkUsage                    = 0x00D0
+pp_data->cap[223]->IsMultipleItemsForArray      = 0
+pp_data->cap[223]->IsButtonCap                  = 0
+pp_data->cap[223]->IsPadding                    = 0
+pp_data->cap[223]->IsAbsolute                   = 1
+pp_data->cap[223]->IsRange                      = 0
+pp_data->cap[223]->IsAlias                      = 0
+pp_data->cap[223]->IsStringRange                = 0
+pp_data->cap[223]->IsDesignatorRange            = 0
+pp_data->cap[223]->Reserved1                    = 0x000000
+pp_data->cap[223]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[223]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[223]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[223]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[223]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[223]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[223]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[223]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[223]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[223]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[223]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[223]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[223]->NotRange.Usage                        = 0x00D1
+pp_data->cap[223]->NotRange.Reserved1                    = 0x00D1
+pp_data->cap[223]->NotRange.StringIndex                  = 0
+pp_data->cap[223]->NotRange.Reserved2                    = 0
+pp_data->cap[223]->NotRange.DesignatorIndex              = 0
+pp_data->cap[223]->NotRange.Reserved3                    = 0
+pp_data->cap[223]->NotRange.DataIndex                    = 2
+pp_data->cap[223]->NotRange.Reserved4                    = 2
+pp_data->cap[223]->NotButton.HasNull                   = 0
+pp_data->cap[223]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[223]->NotButton.LogicalMin                = 0
+pp_data->cap[223]->NotButton.LogicalMax                = 255
+pp_data->cap[223]->NotButton.PhysicalMin               = 0
+pp_data->cap[223]->NotButton.PhysicalMax               = 0
+pp_data->cap[223]->Units                    = 0
+pp_data->cap[223]->UnitsExp                 = 0
+
+pp_data->cap[224]->UsagePage                    = 0xFF01
+pp_data->cap[224]->ReportID                     = 0xD3
+pp_data->cap[224]->BitPosition                  = 0
+pp_data->cap[224]->BitSize                      = 8
+pp_data->cap[224]->ReportCount                  = 32
+pp_data->cap[224]->BytePosition                 = 0x0001
+pp_data->cap[224]->BitCount                     = 256
+pp_data->cap[224]->BitField                     = 0x82
+pp_data->cap[224]->NextBytePosition             = 0x0021
+pp_data->cap[224]->LinkCollection               = 0x0008
+pp_data->cap[224]->LinkUsagePage                = 0xFF01
+pp_data->cap[224]->LinkUsage                    = 0x00D0
+pp_data->cap[224]->IsMultipleItemsForArray      = 0
+pp_data->cap[224]->IsButtonCap                  = 0
+pp_data->cap[224]->IsPadding                    = 0
+pp_data->cap[224]->IsAbsolute                   = 1
+pp_data->cap[224]->IsRange                      = 0
+pp_data->cap[224]->IsAlias                      = 0
+pp_data->cap[224]->IsStringRange                = 0
+pp_data->cap[224]->IsDesignatorRange            = 0
+pp_data->cap[224]->Reserved1                    = 0x000000
+pp_data->cap[224]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[224]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[224]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[224]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[224]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[224]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[224]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[224]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[224]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[224]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[224]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[224]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[224]->NotRange.Usage                        = 0x00D1
+pp_data->cap[224]->NotRange.Reserved1                    = 0x00D1
+pp_data->cap[224]->NotRange.StringIndex                  = 0
+pp_data->cap[224]->NotRange.Reserved2                    = 0
+pp_data->cap[224]->NotRange.DesignatorIndex              = 0
+pp_data->cap[224]->NotRange.Reserved3                    = 0
+pp_data->cap[224]->NotRange.DataIndex                    = 3
+pp_data->cap[224]->NotRange.Reserved4                    = 3
+pp_data->cap[224]->NotButton.HasNull                   = 0
+pp_data->cap[224]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[224]->NotButton.LogicalMin                = 0
+pp_data->cap[224]->NotButton.LogicalMax                = 255
+pp_data->cap[224]->NotButton.PhysicalMin               = 0
+pp_data->cap[224]->NotButton.PhysicalMax               = 0
+pp_data->cap[224]->Units                    = 0
+pp_data->cap[224]->UnitsExp                 = 0
+
+pp_data->cap[225]->UsagePage                    = 0xFF01
+pp_data->cap[225]->ReportID                     = 0xD4
+pp_data->cap[225]->BitPosition                  = 0
+pp_data->cap[225]->BitSize                      = 8
+pp_data->cap[225]->ReportCount                  = 32
+pp_data->cap[225]->BytePosition                 = 0x0001
+pp_data->cap[225]->BitCount                     = 256
+pp_data->cap[225]->BitField                     = 0x82
+pp_data->cap[225]->NextBytePosition             = 0x0021
+pp_data->cap[225]->LinkCollection               = 0x0009
+pp_data->cap[225]->LinkUsagePage                = 0xFF01
+pp_data->cap[225]->LinkUsage                    = 0x00D0
+pp_data->cap[225]->IsMultipleItemsForArray      = 0
+pp_data->cap[225]->IsButtonCap                  = 0
+pp_data->cap[225]->IsPadding                    = 0
+pp_data->cap[225]->IsAbsolute                   = 1
+pp_data->cap[225]->IsRange                      = 0
+pp_data->cap[225]->IsAlias                      = 0
+pp_data->cap[225]->IsStringRange                = 0
+pp_data->cap[225]->IsDesignatorRange            = 0
+pp_data->cap[225]->Reserved1                    = 0x000000
+pp_data->cap[225]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[225]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[225]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[225]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[225]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[225]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[225]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[225]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[225]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[225]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[225]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[225]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[225]->NotRange.Usage                        = 0x00D1
+pp_data->cap[225]->NotRange.Reserved1                    = 0x00D1
+pp_data->cap[225]->NotRange.StringIndex                  = 0
+pp_data->cap[225]->NotRange.Reserved2                    = 0
+pp_data->cap[225]->NotRange.DesignatorIndex              = 0
+pp_data->cap[225]->NotRange.Reserved3                    = 0
+pp_data->cap[225]->NotRange.DataIndex                    = 4
+pp_data->cap[225]->NotRange.Reserved4                    = 4
+pp_data->cap[225]->NotButton.HasNull                   = 0
+pp_data->cap[225]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[225]->NotButton.LogicalMin                = 0
+pp_data->cap[225]->NotButton.LogicalMax                = 255
+pp_data->cap[225]->NotButton.PhysicalMin               = 0
+pp_data->cap[225]->NotButton.PhysicalMax               = 0
+pp_data->cap[225]->Units                    = 0
+pp_data->cap[225]->UnitsExp                 = 0
+
+pp_data->cap[226]->UsagePage                    = 0xFF01
+pp_data->cap[226]->ReportID                     = 0xD5
+pp_data->cap[226]->BitPosition                  = 0
+pp_data->cap[226]->BitSize                      = 8
+pp_data->cap[226]->ReportCount                  = 32
+pp_data->cap[226]->BytePosition                 = 0x0001
+pp_data->cap[226]->BitCount                     = 256
+pp_data->cap[226]->BitField                     = 0x82
+pp_data->cap[226]->NextBytePosition             = 0x0021
+pp_data->cap[226]->LinkCollection               = 0x000A
+pp_data->cap[226]->LinkUsagePage                = 0xFF01
+pp_data->cap[226]->LinkUsage                    = 0x00D0
+pp_data->cap[226]->IsMultipleItemsForArray      = 0
+pp_data->cap[226]->IsButtonCap                  = 0
+pp_data->cap[226]->IsPadding                    = 0
+pp_data->cap[226]->IsAbsolute                   = 1
+pp_data->cap[226]->IsRange                      = 0
+pp_data->cap[226]->IsAlias                      = 0
+pp_data->cap[226]->IsStringRange                = 0
+pp_data->cap[226]->IsDesignatorRange            = 0
+pp_data->cap[226]->Reserved1                    = 0x000000
+pp_data->cap[226]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[226]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[226]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[226]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[226]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[226]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[226]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[226]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[226]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[226]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[226]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[226]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[226]->NotRange.Usage                        = 0x00D1
+pp_data->cap[226]->NotRange.Reserved1                    = 0x00D1
+pp_data->cap[226]->NotRange.StringIndex                  = 0
+pp_data->cap[226]->NotRange.Reserved2                    = 0
+pp_data->cap[226]->NotRange.DesignatorIndex              = 0
+pp_data->cap[226]->NotRange.Reserved3                    = 0
+pp_data->cap[226]->NotRange.DataIndex                    = 5
+pp_data->cap[226]->NotRange.Reserved4                    = 5
+pp_data->cap[226]->NotButton.HasNull                   = 0
+pp_data->cap[226]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[226]->NotButton.LogicalMin                = 0
+pp_data->cap[226]->NotButton.LogicalMax                = 255
+pp_data->cap[226]->NotButton.PhysicalMin               = 0
+pp_data->cap[226]->NotButton.PhysicalMax               = 0
+pp_data->cap[226]->Units                    = 0
+pp_data->cap[226]->UnitsExp                 = 0
+
+pp_data->cap[227]->UsagePage                    = 0xFF01
+pp_data->cap[227]->ReportID                     = 0xD6
+pp_data->cap[227]->BitPosition                  = 0
+pp_data->cap[227]->BitSize                      = 8
+pp_data->cap[227]->ReportCount                  = 32
+pp_data->cap[227]->BytePosition                 = 0x0001
+pp_data->cap[227]->BitCount                     = 256
+pp_data->cap[227]->BitField                     = 0x82
+pp_data->cap[227]->NextBytePosition             = 0x0021
+pp_data->cap[227]->LinkCollection               = 0x000B
+pp_data->cap[227]->LinkUsagePage                = 0xFF01
+pp_data->cap[227]->LinkUsage                    = 0x00D0
+pp_data->cap[227]->IsMultipleItemsForArray      = 0
+pp_data->cap[227]->IsButtonCap                  = 0
+pp_data->cap[227]->IsPadding                    = 0
+pp_data->cap[227]->IsAbsolute                   = 1
+pp_data->cap[227]->IsRange                      = 0
+pp_data->cap[227]->IsAlias                      = 0
+pp_data->cap[227]->IsStringRange                = 0
+pp_data->cap[227]->IsDesignatorRange            = 0
+pp_data->cap[227]->Reserved1                    = 0x000000
+pp_data->cap[227]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[227]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[227]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[227]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[227]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[227]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[227]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[227]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[227]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[227]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[227]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[227]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[227]->NotRange.Usage                        = 0x00D1
+pp_data->cap[227]->NotRange.Reserved1                    = 0x00D1
+pp_data->cap[227]->NotRange.StringIndex                  = 0
+pp_data->cap[227]->NotRange.Reserved2                    = 0
+pp_data->cap[227]->NotRange.DesignatorIndex              = 0
+pp_data->cap[227]->NotRange.Reserved3                    = 0
+pp_data->cap[227]->NotRange.DataIndex                    = 6
+pp_data->cap[227]->NotRange.Reserved4                    = 6
+pp_data->cap[227]->NotButton.HasNull                   = 0
+pp_data->cap[227]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[227]->NotButton.LogicalMin                = 0
+pp_data->cap[227]->NotButton.LogicalMax                = 255
+pp_data->cap[227]->NotButton.PhysicalMin               = 0
+pp_data->cap[227]->NotButton.PhysicalMax               = 0
+pp_data->cap[227]->Units                    = 0
+pp_data->cap[227]->UnitsExp                 = 0
+
+pp_data->cap[228]->UsagePage                    = 0xFF01
+pp_data->cap[228]->ReportID                     = 0xD8
+pp_data->cap[228]->BitPosition                  = 0
+pp_data->cap[228]->BitSize                      = 8
+pp_data->cap[228]->ReportCount                  = 32
+pp_data->cap[228]->BytePosition                 = 0x0001
+pp_data->cap[228]->BitCount                     = 256
+pp_data->cap[228]->BitField                     = 0x82
+pp_data->cap[228]->NextBytePosition             = 0x0021
+pp_data->cap[228]->LinkCollection               = 0x000C
+pp_data->cap[228]->LinkUsagePage                = 0xFF01
+pp_data->cap[228]->LinkUsage                    = 0x00D0
+pp_data->cap[228]->IsMultipleItemsForArray      = 0
+pp_data->cap[228]->IsButtonCap                  = 0
+pp_data->cap[228]->IsPadding                    = 0
+pp_data->cap[228]->IsAbsolute                   = 1
+pp_data->cap[228]->IsRange                      = 0
+pp_data->cap[228]->IsAlias                      = 0
+pp_data->cap[228]->IsStringRange                = 0
+pp_data->cap[228]->IsDesignatorRange            = 0
+pp_data->cap[228]->Reserved1                    = 0x000000
+pp_data->cap[228]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[228]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[228]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[228]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[228]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[228]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[228]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[228]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[228]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[228]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[228]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[228]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[228]->NotRange.Usage                        = 0x00D1
+pp_data->cap[228]->NotRange.Reserved1                    = 0x00D1
+pp_data->cap[228]->NotRange.StringIndex                  = 0
+pp_data->cap[228]->NotRange.Reserved2                    = 0
+pp_data->cap[228]->NotRange.DesignatorIndex              = 0
+pp_data->cap[228]->NotRange.Reserved3                    = 0
+pp_data->cap[228]->NotRange.DataIndex                    = 7
+pp_data->cap[228]->NotRange.Reserved4                    = 7
+pp_data->cap[228]->NotButton.HasNull                   = 0
+pp_data->cap[228]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[228]->NotButton.LogicalMin                = 0
+pp_data->cap[228]->NotButton.LogicalMax                = 255
+pp_data->cap[228]->NotButton.PhysicalMin               = 0
+pp_data->cap[228]->NotButton.PhysicalMax               = 0
+pp_data->cap[228]->Units                    = 0
+pp_data->cap[228]->UnitsExp                 = 0
+
+pp_data->cap[229]->UsagePage                    = 0xFF01
+pp_data->cap[229]->ReportID                     = 0xD9
+pp_data->cap[229]->BitPosition                  = 0
+pp_data->cap[229]->BitSize                      = 8
+pp_data->cap[229]->ReportCount                  = 32
+pp_data->cap[229]->BytePosition                 = 0x0001
+pp_data->cap[229]->BitCount                     = 256
+pp_data->cap[229]->BitField                     = 0x82
+pp_data->cap[229]->NextBytePosition             = 0x0021
+pp_data->cap[229]->LinkCollection               = 0x000D
+pp_data->cap[229]->LinkUsagePage                = 0xFF01
+pp_data->cap[229]->LinkUsage                    = 0x00D0
+pp_data->cap[229]->IsMultipleItemsForArray      = 0
+pp_data->cap[229]->IsButtonCap                  = 0
+pp_data->cap[229]->IsPadding                    = 0
+pp_data->cap[229]->IsAbsolute                   = 1
+pp_data->cap[229]->IsRange                      = 0
+pp_data->cap[229]->IsAlias                      = 0
+pp_data->cap[229]->IsStringRange                = 0
+pp_data->cap[229]->IsDesignatorRange            = 0
+pp_data->cap[229]->Reserved1                    = 0x000000
+pp_data->cap[229]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[229]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[229]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[229]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[229]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[229]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[229]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[229]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[229]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[229]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[229]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[229]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[229]->NotRange.Usage                        = 0x00D1
+pp_data->cap[229]->NotRange.Reserved1                    = 0x00D1
+pp_data->cap[229]->NotRange.StringIndex                  = 0
+pp_data->cap[229]->NotRange.Reserved2                    = 0
+pp_data->cap[229]->NotRange.DesignatorIndex              = 0
+pp_data->cap[229]->NotRange.Reserved3                    = 0
+pp_data->cap[229]->NotRange.DataIndex                    = 8
+pp_data->cap[229]->NotRange.Reserved4                    = 8
+pp_data->cap[229]->NotButton.HasNull                   = 0
+pp_data->cap[229]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[229]->NotButton.LogicalMin                = 0
+pp_data->cap[229]->NotButton.LogicalMax                = 255
+pp_data->cap[229]->NotButton.PhysicalMin               = 0
+pp_data->cap[229]->NotButton.PhysicalMax               = 0
+pp_data->cap[229]->Units                    = 0
+pp_data->cap[229]->UnitsExp                 = 0
+
+pp_data->cap[230]->UsagePage                    = 0xFF01
+pp_data->cap[230]->ReportID                     = 0xF1
+pp_data->cap[230]->BitPosition                  = 0
+pp_data->cap[230]->BitSize                      = 8
+pp_data->cap[230]->ReportCount                  = 2
+pp_data->cap[230]->BytePosition                 = 0x0001
+pp_data->cap[230]->BitCount                     = 16
+pp_data->cap[230]->BitField                     = 0x82
+pp_data->cap[230]->NextBytePosition             = 0x0003
+pp_data->cap[230]->LinkCollection               = 0x000E
+pp_data->cap[230]->LinkUsagePage                = 0xFF01
+pp_data->cap[230]->LinkUsage                    = 0x00D0
+pp_data->cap[230]->IsMultipleItemsForArray      = 0
+pp_data->cap[230]->IsButtonCap                  = 0
+pp_data->cap[230]->IsPadding                    = 0
+pp_data->cap[230]->IsAbsolute                   = 1
+pp_data->cap[230]->IsRange                      = 0
+pp_data->cap[230]->IsAlias                      = 0
+pp_data->cap[230]->IsStringRange                = 0
+pp_data->cap[230]->IsDesignatorRange            = 0
+pp_data->cap[230]->Reserved1                    = 0x000000
+pp_data->cap[230]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[230]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[230]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[230]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[230]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[230]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[230]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[230]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[230]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[230]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[230]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[230]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[230]->NotRange.Usage                        = 0x00D1
+pp_data->cap[230]->NotRange.Reserved1                    = 0x00D1
+pp_data->cap[230]->NotRange.StringIndex                  = 0
+pp_data->cap[230]->NotRange.Reserved2                    = 0
+pp_data->cap[230]->NotRange.DesignatorIndex              = 0
+pp_data->cap[230]->NotRange.Reserved3                    = 0
+pp_data->cap[230]->NotRange.DataIndex                    = 9
+pp_data->cap[230]->NotRange.Reserved4                    = 9
+pp_data->cap[230]->NotButton.HasNull                   = 0
+pp_data->cap[230]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[230]->NotButton.LogicalMin                = 0
+pp_data->cap[230]->NotButton.LogicalMax                = 255
+pp_data->cap[230]->NotButton.PhysicalMin               = 0
+pp_data->cap[230]->NotButton.PhysicalMax               = 0
+pp_data->cap[230]->Units                    = 0
+pp_data->cap[230]->UnitsExp                 = 0
+
+pp_data->cap[231]->UsagePage                    = 0xFF01
+pp_data->cap[231]->ReportID                     = 0xF3
+pp_data->cap[231]->BitPosition                  = 0
+pp_data->cap[231]->BitSize                      = 8
+pp_data->cap[231]->ReportCount                  = 2
+pp_data->cap[231]->BytePosition                 = 0x0001
+pp_data->cap[231]->BitCount                     = 16
+pp_data->cap[231]->BitField                     = 0x82
+pp_data->cap[231]->NextBytePosition             = 0x0003
+pp_data->cap[231]->LinkCollection               = 0x000F
+pp_data->cap[231]->LinkUsagePage                = 0xFF01
+pp_data->cap[231]->LinkUsage                    = 0x00D0
+pp_data->cap[231]->IsMultipleItemsForArray      = 0
+pp_data->cap[231]->IsButtonCap                  = 0
+pp_data->cap[231]->IsPadding                    = 0
+pp_data->cap[231]->IsAbsolute                   = 1
+pp_data->cap[231]->IsRange                      = 0
+pp_data->cap[231]->IsAlias                      = 0
+pp_data->cap[231]->IsStringRange                = 0
+pp_data->cap[231]->IsDesignatorRange            = 0
+pp_data->cap[231]->Reserved1                    = 0x000000
+pp_data->cap[231]->pp_cap->UnknownTokens[0].Token    = 0x00
+pp_data->cap[231]->pp_cap->UnknownTokens[0].Reserved = 0x000000
+pp_data->cap[231]->pp_cap->UnknownTokens[0].BitField = 0x00000000
+pp_data->cap[231]->pp_cap->UnknownTokens[1].Token    = 0x00
+pp_data->cap[231]->pp_cap->UnknownTokens[1].Reserved = 0x000000
+pp_data->cap[231]->pp_cap->UnknownTokens[1].BitField = 0x00000000
+pp_data->cap[231]->pp_cap->UnknownTokens[2].Token    = 0x00
+pp_data->cap[231]->pp_cap->UnknownTokens[2].Reserved = 0x000000
+pp_data->cap[231]->pp_cap->UnknownTokens[2].BitField = 0x00000000
+pp_data->cap[231]->pp_cap->UnknownTokens[3].Token    = 0x00
+pp_data->cap[231]->pp_cap->UnknownTokens[3].Reserved = 0x000000
+pp_data->cap[231]->pp_cap->UnknownTokens[3].BitField = 0x00000000
+pp_data->cap[231]->NotRange.Usage                        = 0x00D1
+pp_data->cap[231]->NotRange.Reserved1                    = 0x00D1
+pp_data->cap[231]->NotRange.StringIndex                  = 0
+pp_data->cap[231]->NotRange.Reserved2                    = 0
+pp_data->cap[231]->NotRange.DesignatorIndex              = 0
+pp_data->cap[231]->NotRange.Reserved3                    = 0
+pp_data->cap[231]->NotRange.DataIndex                    = 10
+pp_data->cap[231]->NotRange.Reserved4                    = 10
+pp_data->cap[231]->NotButton.HasNull                   = 0
+pp_data->cap[231]->NotButton.Reserved4                 = 0x000000
+pp_data->cap[231]->NotButton.LogicalMin                = 0
+pp_data->cap[231]->NotButton.LogicalMax                = 127
+pp_data->cap[231]->NotButton.PhysicalMin               = 0
+pp_data->cap[231]->NotButton.PhysicalMax               = 0
+pp_data->cap[231]->Units                    = 0
+pp_data->cap[231]->UnitsExp                 = 0
+
+# Link Collections:
+pp_data->LinkCollectionArray[0]->LinkUsage          = 0x0000
+pp_data->LinkCollectionArray[0]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[0]->Parent             = 0
+pp_data->LinkCollectionArray[0]->NumberOfChildren   = 15
+pp_data->LinkCollectionArray[0]->NextSibling        = 0
+pp_data->LinkCollectionArray[0]->FirstChild         = 15
+pp_data->LinkCollectionArray[0]->CollectionType     = 1
+pp_data->LinkCollectionArray[0]->IsAlias            = 0
+pp_data->LinkCollectionArray[0]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[1]->LinkUsage          = 0x0001
+pp_data->LinkCollectionArray[1]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[1]->Parent             = 0
+pp_data->LinkCollectionArray[1]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[1]->NextSibling        = 0
+pp_data->LinkCollectionArray[1]->FirstChild         = 0
+pp_data->LinkCollectionArray[1]->CollectionType     = 2
+pp_data->LinkCollectionArray[1]->IsAlias            = 0
+pp_data->LinkCollectionArray[1]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[2]->LinkUsage          = 0x0002
+pp_data->LinkCollectionArray[2]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[2]->Parent             = 0
+pp_data->LinkCollectionArray[2]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[2]->NextSibling        = 1
+pp_data->LinkCollectionArray[2]->FirstChild         = 0
+pp_data->LinkCollectionArray[2]->CollectionType     = 2
+pp_data->LinkCollectionArray[2]->IsAlias            = 0
+pp_data->LinkCollectionArray[2]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[3]->LinkUsage          = 0x0080
+pp_data->LinkCollectionArray[3]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[3]->Parent             = 0
+pp_data->LinkCollectionArray[3]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[3]->NextSibling        = 2
+pp_data->LinkCollectionArray[3]->FirstChild         = 0
+pp_data->LinkCollectionArray[3]->CollectionType     = 2
+pp_data->LinkCollectionArray[3]->IsAlias            = 0
+pp_data->LinkCollectionArray[3]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[4]->LinkUsage          = 0x0080
+pp_data->LinkCollectionArray[4]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[4]->Parent             = 0
+pp_data->LinkCollectionArray[4]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[4]->NextSibling        = 3
+pp_data->LinkCollectionArray[4]->FirstChild         = 0
+pp_data->LinkCollectionArray[4]->CollectionType     = 2
+pp_data->LinkCollectionArray[4]->IsAlias            = 0
+pp_data->LinkCollectionArray[4]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[5]->LinkUsage          = 0x00D0
+pp_data->LinkCollectionArray[5]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[5]->Parent             = 0
+pp_data->LinkCollectionArray[5]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[5]->NextSibling        = 4
+pp_data->LinkCollectionArray[5]->FirstChild         = 0
+pp_data->LinkCollectionArray[5]->CollectionType     = 2
+pp_data->LinkCollectionArray[5]->IsAlias            = 0
+pp_data->LinkCollectionArray[5]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[6]->LinkUsage          = 0x00D0
+pp_data->LinkCollectionArray[6]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[6]->Parent             = 0
+pp_data->LinkCollectionArray[6]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[6]->NextSibling        = 5
+pp_data->LinkCollectionArray[6]->FirstChild         = 0
+pp_data->LinkCollectionArray[6]->CollectionType     = 2
+pp_data->LinkCollectionArray[6]->IsAlias            = 0
+pp_data->LinkCollectionArray[6]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[7]->LinkUsage          = 0x00D0
+pp_data->LinkCollectionArray[7]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[7]->Parent             = 0
+pp_data->LinkCollectionArray[7]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[7]->NextSibling        = 6
+pp_data->LinkCollectionArray[7]->FirstChild         = 0
+pp_data->LinkCollectionArray[7]->CollectionType     = 2
+pp_data->LinkCollectionArray[7]->IsAlias            = 0
+pp_data->LinkCollectionArray[7]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[8]->LinkUsage          = 0x00D0
+pp_data->LinkCollectionArray[8]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[8]->Parent             = 0
+pp_data->LinkCollectionArray[8]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[8]->NextSibling        = 7
+pp_data->LinkCollectionArray[8]->FirstChild         = 0
+pp_data->LinkCollectionArray[8]->CollectionType     = 2
+pp_data->LinkCollectionArray[8]->IsAlias            = 0
+pp_data->LinkCollectionArray[8]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[9]->LinkUsage          = 0x00D0
+pp_data->LinkCollectionArray[9]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[9]->Parent             = 0
+pp_data->LinkCollectionArray[9]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[9]->NextSibling        = 8
+pp_data->LinkCollectionArray[9]->FirstChild         = 0
+pp_data->LinkCollectionArray[9]->CollectionType     = 2
+pp_data->LinkCollectionArray[9]->IsAlias            = 0
+pp_data->LinkCollectionArray[9]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[10]->LinkUsage          = 0x00D0
+pp_data->LinkCollectionArray[10]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[10]->Parent             = 0
+pp_data->LinkCollectionArray[10]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[10]->NextSibling        = 9
+pp_data->LinkCollectionArray[10]->FirstChild         = 0
+pp_data->LinkCollectionArray[10]->CollectionType     = 2
+pp_data->LinkCollectionArray[10]->IsAlias            = 0
+pp_data->LinkCollectionArray[10]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[11]->LinkUsage          = 0x00D0
+pp_data->LinkCollectionArray[11]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[11]->Parent             = 0
+pp_data->LinkCollectionArray[11]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[11]->NextSibling        = 10
+pp_data->LinkCollectionArray[11]->FirstChild         = 0
+pp_data->LinkCollectionArray[11]->CollectionType     = 2
+pp_data->LinkCollectionArray[11]->IsAlias            = 0
+pp_data->LinkCollectionArray[11]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[12]->LinkUsage          = 0x00D0
+pp_data->LinkCollectionArray[12]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[12]->Parent             = 0
+pp_data->LinkCollectionArray[12]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[12]->NextSibling        = 11
+pp_data->LinkCollectionArray[12]->FirstChild         = 0
+pp_data->LinkCollectionArray[12]->CollectionType     = 2
+pp_data->LinkCollectionArray[12]->IsAlias            = 0
+pp_data->LinkCollectionArray[12]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[13]->LinkUsage          = 0x00D0
+pp_data->LinkCollectionArray[13]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[13]->Parent             = 0
+pp_data->LinkCollectionArray[13]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[13]->NextSibling        = 12
+pp_data->LinkCollectionArray[13]->FirstChild         = 0
+pp_data->LinkCollectionArray[13]->CollectionType     = 2
+pp_data->LinkCollectionArray[13]->IsAlias            = 0
+pp_data->LinkCollectionArray[13]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[14]->LinkUsage          = 0x00D0
+pp_data->LinkCollectionArray[14]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[14]->Parent             = 0
+pp_data->LinkCollectionArray[14]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[14]->NextSibling        = 13
+pp_data->LinkCollectionArray[14]->FirstChild         = 0
+pp_data->LinkCollectionArray[14]->CollectionType     = 2
+pp_data->LinkCollectionArray[14]->IsAlias            = 0
+pp_data->LinkCollectionArray[14]->Reserved           = 0x00000000
+pp_data->LinkCollectionArray[15]->LinkUsage          = 0x00D0
+pp_data->LinkCollectionArray[15]->LinkUsagePage      = 0xFF01
+pp_data->LinkCollectionArray[15]->Parent             = 0
+pp_data->LinkCollectionArray[15]->NumberOfChildren   = 0
+pp_data->LinkCollectionArray[15]->NextSibling        = 14
+pp_data->LinkCollectionArray[15]->FirstChild         = 0
+pp_data->LinkCollectionArray[15]->CollectionType     = 2
+pp_data->LinkCollectionArray[15]->IsAlias            = 0
+pp_data->LinkCollectionArray[15]->Reserved           = 0x00000000
diff --git a/src/hidapi/windows/test/data/17CC_1130_0000_FF01_expected.rpt_desc b/src/hidapi/windows/test/data/17CC_1130_0000_FF01_expected.rpt_desc
new file mode 100644
index 0000000..9bcc814
--- /dev/null
+++ b/src/hidapi/windows/test/data/17CC_1130_0000_FF01_expected.rpt_desc
@@ -0,0 +1,75 @@
+0x06, 0x01, 0xFF, 0x09, 0x00, 0xA1, 0x01, 0x09, 0x01, 0xA1, 
+0x02, 0x85, 0x01, 0x09, 0x03, 0x09, 0x03, 0x09, 0x03, 0x09, 
+0x03, 0x15, 0x00, 0x25, 0x0F, 0x75, 0x04, 0x95, 0x04, 0x81, 
+0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 
+0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 
+0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 
+0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 
+0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 
+0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 
+0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 
+0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 
+0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 
+0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x02, 0x09, 0x0B, 0x09, 
+0x0B, 0x09, 0x0B, 0x09, 0x0B, 0x09, 0x0B, 0x09, 0x0B, 0x09, 
+0x0B, 0x09, 0x0B, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 
+0x38, 0x81, 0x02, 0xC0, 0x09, 0x02, 0xA1, 0x02, 0x85, 0x02, 
+0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 
+0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 
+0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 
+0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 
+0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 0x09, 0x04, 
+0x09, 0x04, 0x15, 0x00, 0x26, 0xFF, 0x0F, 0x75, 0x10, 0x95, 
+0x1A, 0x81, 0x02, 0xC0, 0x09, 0x80, 0xA1, 0x02, 0x85, 0x80, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 
+0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x15, 0x00, 
+0x25, 0x7F, 0x75, 0x08, 0x95, 0x5E, 0x91, 0x02, 0xC0, 0x09, 
+0x80, 0xA1, 0x02, 0x85, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 
+0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 
+0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 
+0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 
+0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 
+0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 
+0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 
+0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 0x81, 0x09, 
+0x81, 0x09, 0x81, 0x09, 0x81, 0x15, 0x00, 0x25, 0x7F, 0x75, 
+0x08, 0x95, 0x28, 0x91, 0x02, 0xC0, 0x09, 0xD0, 0xA1, 0x02, 
+0x85, 0xD0, 0x09, 0xD1, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x20, 0xB1, 0x82, 0xC0, 0x09, 0xD0, 0xA1, 0x02, 
+0x85, 0xD1, 0x09, 0xD1, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x20, 0xB1, 0x82, 0xC0, 0x09, 0xD0, 0xA1, 0x02, 
+0x85, 0xD2, 0x09, 0xD1, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x20, 0xB1, 0x82, 0xC0, 0x09, 0xD0, 0xA1, 0x02, 
+0x85, 0xD3, 0x09, 0xD1, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x20, 0xB1, 0x82, 0xC0, 0x09, 0xD0, 0xA1, 0x02, 
+0x85, 0xD4, 0x09, 0xD1, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x20, 0xB1, 0x82, 0xC0, 0x09, 0xD0, 0xA1, 0x02, 
+0x85, 0xD5, 0x09, 0xD1, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x20, 0xB1, 0x82, 0xC0, 0x09, 0xD0, 0xA1, 0x02, 
+0x85, 0xD6, 0x09, 0xD1, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x20, 0xB1, 0x82, 0xC0, 0x09, 0xD0, 0xA1, 0x02, 
+0x85, 0xD8, 0x09, 0xD1, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x20, 0xB1, 0x82, 0xC0, 0x09, 0xD0, 0xA1, 0x02, 
+0x85, 0xD9, 0x09, 0xD1, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x20, 0xB1, 0x82, 0xC0, 0x09, 0xD0, 0xA1, 0x02, 
+0x85, 0xF1, 0x09, 0xD1, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x75, 
+0x08, 0x95, 0x02, 0xB1, 0x82, 0xC0, 0x09, 0xD0, 0xA1, 0x02, 
+0x85, 0xF3, 0x09, 0xD1, 0x15, 0x00, 0x25, 0x7F, 0x75, 0x08, 
+0x95, 0x02, 0xB1, 0x82, 0xC0, 0xC0, 
\ No newline at end of file
diff --git a/src/hidapi/windows/test/data/17CC_1130_0000_FF01_real.rpt_desc b/src/hidapi/windows/test/data/17CC_1130_0000_FF01_real.rpt_desc
new file mode 100644
index 0000000..7f908f8
--- /dev/null
+++ b/src/hidapi/windows/test/data/17CC_1130_0000_FF01_real.rpt_desc
@@ -0,0 +1,381 @@
+Usage Page (Vendor-Defined 2) 06 01 FF  
+Usage (Undefined) 09 00  
+Collection (Application) A1 01  
+    Usage (Vendor-Defined 1) 09 01  
+    Collection (Logical) A1 02  
+        Report ID (1) 85 01  
+        Usage (Vendor-Defined 3) 09 03  
+        Usage (Vendor-Defined 3) 09 03  
+        Usage (Vendor-Defined 3) 09 03  
+        Usage (Vendor-Defined 3) 09 03  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (15) 25 0F  
+        Report Size (4) 75 04  
+        Report Count (4) 95 04  
+        Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Usage (Vendor-Defined 2) 09 02  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (1) 25 01  
+        Report Size (1) 75 01  
+        Report Count (48) 95 30  
+        Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02  
+        Usage (Vendor-Defined 11) 09 0B  
+        Usage (Vendor-Defined 11) 09 0B  
+        Usage (Vendor-Defined 11) 09 0B  
+        Usage (Vendor-Defined 11) 09 0B  
+        Usage (Vendor-Defined 11) 09 0B  
+        Usage (Vendor-Defined 11) 09 0B  
+        Usage (Vendor-Defined 11) 09 0B  
+        Usage (Vendor-Defined 11) 09 0B  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (1) 25 01  
+        Report Size (1) 75 01  
+        Report Count (8) 95 08  
+        Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02  
+    End Collection C0  
+    Usage (Vendor-Defined 2) 09 02  
+    Collection (Logical) A1 02  
+        Report ID (2) 85 02  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Usage (Vendor-Defined 4) 09 04  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (4095) 26 FF 0F  
+        Report Size (16) 75 10  
+        Report Count (26) 95 1A  
+        Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02  
+    End Collection C0  
+    Usage (Vendor-Defined 128) 09 80  
+    Collection (Logical) A1 02  
+        Report ID (128) 85 80  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (127) 25 7F  
+        Report Count (94) 95 5E  
+        Report Size (8) 75 08  
+        Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 02  
+    End Collection C0  
+    Usage (Vendor-Defined 128) 09 80  
+    Collection (Logical) A1 02  
+        Report ID (129) 85 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Usage (Vendor-Defined 129) 09 81  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (127) 25 7F  
+        Report Count (40) 95 28  
+        Report Size (8) 75 08  
+        Output (Data,Var,Abs,NWrp,Lin,Pref,NNul,NVol,Bit) 91 02  
+    End Collection C0  
+    Usage (Vendor-Defined 208) 09 D0  
+    Collection (Logical) A1 02  
+        Report ID (208) 85 D0  
+        Usage (Vendor-Defined 209) 09 D1  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (255) 26 FF 00  
+        Report Size (8) 75 08  
+        Report Count (32) 95 20  
+        Feature (Data,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) B1 82  
+    End Collection C0  
+    Usage (Vendor-Defined 208) 09 D0  
+    Collection (Logical) A1 02  
+        Report ID (209) 85 D1  
+        Usage (Vendor-Defined 209) 09 D1  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (255) 26 FF 00  
+        Report Size (8) 75 08  
+        Report Count (32) 95 20  
+        Feature (Data,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) B1 82  
+    End Collection C0  
+    Usage (Vendor-Defined 208) 09 D0  
+    Collection (Logical) A1 02  
+        Report ID (210) 85 D2  
+        Usage (Vendor-Defined 209) 09 D1  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (255) 26 FF 00  
+        Report Size (8) 75 08  
+        Report Count (32) 95 20  
+        Feature (Data,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) B1 82  
+    End Collection C0  
+    Usage (Vendor-Defined 208) 09 D0  
+    Collection (Logical) A1 02  
+        Report ID (211) 85 D3  
+        Usage (Vendor-Defined 209) 09 D1  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (255) 26 FF 00  
+        Report Size (8) 75 08  
+        Report Count (32) 95 20  
+        Feature (Data,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) B1 82  
+    End Collection C0  
+    Usage (Vendor-Defined 208) 09 D0  
+    Collection (Logical) A1 02  
+        Report ID (212) 85 D4  
+        Usage (Vendor-Defined 209) 09 D1  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (255) 26 FF 00  
+        Report Size (8) 75 08  
+        Report Count (32) 95 20  
+        Feature (Data,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) B1 82  
+    End Collection C0  
+    Usage (Vendor-Defined 208) 09 D0  
+    Collection (Logical) A1 02  
+        Report ID (213) 85 D5  
+        Usage (Vendor-Defined 209) 09 D1  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (255) 26 FF 00  
+        Report Size (8) 75 08  
+        Report Count (32) 95 20  
+        Feature (Data,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) B1 82  
+    End Collection C0  
+    Usage (Vendor-Defined 208) 09 D0  
+    Collection (Logical) A1 02  
+        Report ID (214) 85 D6  
+        Usage (Vendor-Defined 209) 09 D1  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (255) 26 FF 00  
+        Report Size (8) 75 08  
+        Report Count (32) 95 20  
+        Feature (Data,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) B1 82  
+    End Collection C0  
+    Usage (Vendor-Defined 208) 09 D0  
+    Collection (Logical) A1 02  
+        Report ID (216) 85 D8  
+        Usage (Vendor-Defined 209) 09 D1  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (255) 26 FF 00  
+        Report Size (8) 75 08  
+        Report Count (32) 95 20  
+        Feature (Data,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) B1 82  
+    End Collection C0  
+    Usage (Vendor-Defined 208) 09 D0  
+    Collection (Logical) A1 02  
+        Report ID (217) 85 D9  
+        Usage (Vendor-Defined 209) 09 D1  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (255) 26 FF 00  
+        Report Size (8) 75 08  
+        Report Count (32) 95 20  
+        Feature (Data,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) B1 82  
+    End Collection C0  
+    Usage (Vendor-Defined 208) 09 D0  
+    Collection (Logical) A1 02  
+        Report ID (241) 85 F1  
+        Usage (Vendor-Defined 209) 09 D1  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (255) 26 FF 00  
+        Report Size (8) 75 08  
+        Report Count (2) 95 02  
+        Feature (Data,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) B1 82  
+    End Collection C0  
+    Usage (Vendor-Defined 208) 09 D0  
+    Collection (Logical) A1 02  
+        Report ID (243) 85 F3  
+        Usage (Vendor-Defined 209) 09 D1  
+        Logical Minimum (0) 15 00  
+        Logical Maximum (127) 25 7F  
+        Report Size (8) 75 08  
+        Report Count (2) 95 02  
+        Feature (Data,Var,Abs,NWrp,Lin,Pref,NNul,Vol,Bit) B1 82  
+    End Collection C0  
+End Collection C0 
diff --git a/src/hidapi/windows/test/hid_report_reconstructor_test.c b/src/hidapi/windows/test/hid_report_reconstructor_test.c
new file mode 100644
index 0000000..bcd7cd4
--- /dev/null
+++ b/src/hidapi/windows/test/hid_report_reconstructor_test.c
@@ -0,0 +1,561 @@
+#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, "Ignorring 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, "Ignorring 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, "Ignorring 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, "Ignorring 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;
+}