Browse Source

Updated hidapi to 0.14.0 release

Upstream: https://github.com/libusb/hidapi/releases/tag/hidapi-0.14.0
Sam Lantinga 2 years ago
parent
commit
3b7b8f3c09
100 changed files with 8295 additions and 6094 deletions
  1. 31 0
      src/hidapi/.appveyor.yml
  2. 34 0
      src/hidapi/.builds/freebsd.yml
  3. 18 0
      src/hidapi/.builds/netbsd.yml
  4. 19 0
      src/hidapi/.builds/openbsd.yml
  5. 33 0
      src/hidapi/.cirrus.yml
  6. 7 0
      src/hidapi/.gitattributes
  7. 540 0
      src/hidapi/.github/workflows/builds.yml
  8. 196 0
      src/hidapi/.github/workflows/checks.yml
  9. 58 0
      src/hidapi/.github/workflows/docs.yaml
  10. 32 0
      src/hidapi/.gitignore
  11. 3 1
      src/hidapi/AUTHORS.txt
  12. 114 0
      src/hidapi/BUILD.autotools.md
  13. 280 0
      src/hidapi/BUILD.cmake.md
  14. 127 0
      src/hidapi/BUILD.md
  15. 105 0
      src/hidapi/CMakeLists.txt
  16. 15 11
      src/hidapi/HACKING.txt
  17. 5 5
      src/hidapi/Makefile.am
  18. 196 0
      src/hidapi/README.md
  19. 0 339
      src/hidapi/README.txt
  20. 1 0
      src/hidapi/VERSION
  21. 0 1443
      src/hidapi/android/hid.cpp
  22. 0 39
      src/hidapi/android/hid.h
  23. 0 16
      src/hidapi/android/jni/Android.mk
  24. 0 2
      src/hidapi/android/jni/Application.mk
  25. 0 14
      src/hidapi/android/project.properties
  26. 44 24
      src/hidapi/configure.ac
  27. 31 0
      src/hidapi/dist/hidapi.podspec
  28. BIN
      src/hidapi/documentation/cmake-gui-drop-down.png
  29. BIN
      src/hidapi/documentation/cmake-gui-highlights.png
  30. 682 327
      src/hidapi/doxygen/Doxyfile
  31. 13 0
      src/hidapi/doxygen/main_page.md
  32. 261 58
      src/hidapi/hidapi/hidapi.h
  33. 17 0
      src/hidapi/hidtest/.gitignore
  34. 40 0
      src/hidapi/hidtest/CMakeLists.txt
  35. 11 3
      src/hidapi/hidtest/Makefile.am
  36. 0 194
      src/hidapi/hidtest/hidtest.cpp
  37. 316 0
      src/hidapi/hidtest/test.c
  38. 0 32
      src/hidapi/ios/Makefile-manual
  39. 0 9
      src/hidapi/ios/Makefile.am
  40. 0 996
      src/hidapi/ios/hid.m
  41. 8 0
      src/hidapi/libusb/.gitignore
  42. 107 0
      src/hidapi/libusb/CMakeLists.txt
  43. 4 0
      src/hidapi/libusb/Makefile-manual
  44. 8 1
      src/hidapi/libusb/Makefile.am
  45. 4 11
      src/hidapi/libusb/Makefile.freebsd
  46. 39 0
      src/hidapi/libusb/Makefile.haiku
  47. 5 12
      src/hidapi/libusb/Makefile.linux
  48. 357 451
      src/hidapi/libusb/hid.c
  49. 56 0
      src/hidapi/libusb/hidapi_libusb.h
  50. 0 3
      src/hidapi/libusb/hidusb.cpp
  51. 18 0
      src/hidapi/linux/.gitignore
  52. 38 0
      src/hidapi/linux/CMakeLists.txt
  53. 5 12
      src/hidapi/linux/Makefile-manual
  54. 0 59
      src/hidapi/linux/README.txt
  55. 631 263
      src/hidapi/linux/hid.c
  56. 0 3
      src/hidapi/linux/hidraw.cpp
  57. 5 0
      src/hidapi/m4/.gitignore
  58. 17 0
      src/hidapi/mac/.gitignore
  59. 48 0
      src/hidapi/mac/CMakeLists.txt
  60. 6 11
      src/hidapi/mac/Makefile-manual
  61. 504 345
      src/hidapi/mac/hid.c
  62. 98 0
      src/hidapi/mac/hidapi_darwin.h
  63. 22 0
      src/hidapi/meson.build
  64. 1 0
      src/hidapi/pc/.gitignore
  65. 1 0
      src/hidapi/pc/hidapi-hidraw.pc.in
  66. 1 0
      src/hidapi/pc/hidapi-libusb.pc.in
  67. 1 0
      src/hidapi/pc/hidapi.pc.in
  68. 193 0
      src/hidapi/src/CMakeLists.txt
  69. 61 0
      src/hidapi/src/cmake/hidapi-config.cmake.in
  70. 2 0
      src/hidapi/subprojects/README.md
  71. 10 0
      src/hidapi/subprojects/hidapi_build_cmake/CMakeLists.txt
  72. 20 0
      src/hidapi/testgui/.gitignore
  73. 1 1
      src/hidapi/testgui/Makefile.mingw
  74. 2 1
      src/hidapi/testgui/copy_to_bundle.sh
  75. 0 134
      src/hidapi/testgui/mac_support.cpp
  76. 11 2
      src/hidapi/testgui/mac_support_cocoa.m
  77. 0 2
      src/hidapi/testgui/start.sh
  78. 20 20
      src/hidapi/testgui/testgui.sln
  79. 217 217
      src/hidapi/testgui/testgui.vcproj
  80. 36 0
      src/hidapi/udev/69-hid.rules
  81. 0 33
      src/hidapi/udev/99-hid.rules
  82. 17 0
      src/hidapi/windows/.gitignore
  83. 63 0
      src/hidapi/windows/CMakeLists.txt
  84. 0 1
      src/hidapi/windows/Makefile.am
  85. 6 11
      src/hidapi/windows/Makefile.mingw
  86. 0 17
      src/hidapi/windows/ddk_build/hidapi.def
  87. 0 49
      src/hidapi/windows/ddk_build/makefile
  88. 0 23
      src/hidapi/windows/ddk_build/sources
  89. 429 456
      src/hidapi/windows/hid.c
  90. 35 0
      src/hidapi/windows/hidapi.rc
  91. 41 29
      src/hidapi/windows/hidapi.sln
  92. 200 201
      src/hidapi/windows/hidapi.vcproj
  93. 200 0
      src/hidapi/windows/hidapi.vcxproj
  94. 14 16
      src/hidapi/windows/hidapi_cfgmgr32.h
  95. 987 0
      src/hidapi/windows/hidapi_descriptor_reconstruct.c
  96. 238 0
      src/hidapi/windows/hidapi_descriptor_reconstruct.h
  97. 7 0
      src/hidapi/windows/hidapi_hidpi.h
  98. 2 1
      src/hidapi/windows/hidapi_hidsdi.h
  99. 74 0
      src/hidapi/windows/hidapi_winapi.h
  100. 196 196
      src/hidapi/windows/hidtest.vcproj

+ 31 - 0
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"

+ 34 - 0
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

+ 18 - 0
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

+ 19 - 0
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

+ 33 - 0
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

+ 7 - 0
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

+ 540 - 0
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/[email protected]
+    - 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

+ 196 - 0
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/[email protected]
+      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 [email protected] \
+          --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

+ 58 - 0
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

+ 32 - 0
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/

+ 3 - 1
src/hidapi/AUTHORS.txt

@@ -10,7 +10,9 @@ Ludovic Rousseau <[email protected]>:
 	Bug fixes
 	Bug fixes
 	Correctness fixes
 	Correctness fixes
 
 
+libusb/hidapi Team:
+	Development/maintainance since June 4th 2019
 
 
 For a comprehensive list of contributions, see the commit list at github:
 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
 
 

+ 114 - 0
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
+```

+ 280 - 0
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"
+
+```

+ 127 - 0
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.

+ 105 - 0
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()

+ 15 - 11
src/hidapi/HACKING.txt

@@ -1,15 +1,19 @@
 This file is mostly for the maintainer.
 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.

+ 5 - 5
src/hidapi/Makefile.am

@@ -23,10 +23,6 @@ if OS_DARWIN
 SUBDIRS += mac
 SUBDIRS += mac
 endif
 endif
 
 
-if OS_IOS
-SUBDIRS += ios
-endif
-
 if OS_FREEBSD
 if OS_FREEBSD
 SUBDIRS += libusb
 SUBDIRS += libusb
 endif
 endif
@@ -35,6 +31,10 @@ if OS_KFREEBSD
 SUBDIRS += libusb
 SUBDIRS += libusb
 endif
 endif
 
 
+if OS_HAIKU
+SUBDIRS += libusb
+endif
+
 if OS_WINDOWS
 if OS_WINDOWS
 SUBDIRS += windows
 SUBDIRS += windows
 endif
 endif
@@ -48,7 +48,7 @@ endif
 EXTRA_DIST = udev doxygen
 EXTRA_DIST = udev doxygen
 
 
 dist_doc_DATA = \
 dist_doc_DATA = \
- README.txt \
+ README.md \
  AUTHORS.txt \
  AUTHORS.txt \
  LICENSE-bsd.txt \
  LICENSE-bsd.txt \
  LICENSE-gpl3.txt \
  LICENSE-gpl3.txt \

+ 196 - 0
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.

+ 0 - 339
src/hidapi/README.txt

@@ -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

+ 1 - 0
src/hidapi/VERSION

@@ -0,0 +1 @@
+0.14.0

+ 0 - 1443
src/hidapi/android/hid.cpp

@@ -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) }
-};

+ 0 - 39
src/hidapi/android/hid.h

@@ -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

+ 0 - 16
src/hidapi/android/jni/Android.mk

@@ -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)

+ 0 - 2
src/hidapi/android/jni/Application.mk

@@ -1,2 +0,0 @@
-APP_STL := gnustl_static
-APP_ABI := armeabi-v7a

+ 0 - 14
src/hidapi/android/project.properties

@@ -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

+ 44 - 24
src/hidapi/configure.ac

@@ -1,13 +1,9 @@
 AC_PREREQ(2.63)
 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],[[email protected]])
+echo "This build script for HIDAPI is deprecated."
+echo "Consider using CMake instead."
 
 
 # Library soname version
 # Library soname version
 # Follow the following rules (particularly the ones in the second link):
 # Follow the following rules (particularly the ones in the second link):
@@ -20,7 +16,6 @@ LTLDFLAGS="-version-info ${lt_current}:${lt_revision}:${lt_age}"
 
 
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_MACRO_DIR([m4])
 AM_INIT_AUTOMAKE([foreign -Wall -Werror])
 AM_INIT_AUTOMAKE([foreign -Wall -Werror])
-AC_CONFIG_MACRO_DIR([m4])
 
 
 m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
 m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
 LT_INIT
 LT_INIT
@@ -63,14 +58,14 @@ case $host in
 
 
 	# HIDAPI/hidraw libs
 	# HIDAPI/hidraw libs
 	PKG_CHECK_MODULES([libudev], [libudev], true, [hidapi_lib_error libudev])
 	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
 	# 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])
 	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*)
 *-darwin*)
 	AC_MSG_RESULT([ (Mac OS X back-end)])
 	AC_MSG_RESULT([ (Mac OS X back-end)])
@@ -79,7 +74,7 @@ case $host in
 	backend="mac"
 	backend="mac"
 	os="darwin"
 	os="darwin"
 	threads="pthreads"
 	threads="pthreads"
-	LIBS="${LIBS} -framework IOKit -framework CoreFoundation"
+	LIBS="${LIBS} -framework IOKit -framework CoreFoundation -framework AppKit"
 	;;
 	;;
 *-freebsd*)
 *-freebsd*)
 	AC_MSG_RESULT([ (FreeBSD back-end)])
 	AC_MSG_RESULT([ (FreeBSD back-end)])
@@ -92,9 +87,10 @@ case $host in
 	CFLAGS="$CFLAGS -I/usr/local/include"
 	CFLAGS="$CFLAGS -I/usr/local/include"
 	LDFLAGS="$LDFLAGS -L/usr/local/lib"
 	LDFLAGS="$LDFLAGS -L/usr/local/lib"
 	LIBS="${LIBS}"
 	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])
 	AC_CHECK_LIB([iconv], [iconv_open], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -liconv"], [hidapi_lib_error libiconv])
-	echo libs_priv: $LIBS_LIBUSB_PRIVATE
 	;;
 	;;
 *-kfreebsd*)
 *-kfreebsd*)
 	AC_MSG_RESULT([ (kFreeBSD back-end)])
 	AC_MSG_RESULT([ (kFreeBSD back-end)])
@@ -104,8 +100,22 @@ case $host in
 	os="kfreebsd"
 	os="kfreebsd"
 	threads="pthreads"
 	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*)
 *-mingw*)
 	AC_MSG_RESULT([ (Windows back-end, using MinGW)])
 	AC_MSG_RESULT([ (Windows back-end, using MinGW)])
@@ -113,6 +123,15 @@ case $host in
 	os="windows"
 	os="windows"
 	threads="windows"
 	threads="windows"
 	win_implementation="mingw"
 	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*)
 *-cygwin*)
 	AC_MSG_RESULT([ (Windows back-end, using Cygwin)])
 	AC_MSG_RESULT([ (Windows back-end, using Cygwin)])
@@ -136,7 +155,7 @@ if test "x$os" = xwindows; then
 	AC_DEFINE(OS_WINDOWS, 1, [Windows implementations])
 	AC_DEFINE(OS_WINDOWS, 1, [Windows implementations])
 	AC_SUBST(OS_WINDOWS)
 	AC_SUBST(OS_WINDOWS)
 	LDFLAGS="${LDFLAGS} -no-undefined"
 	LDFLAGS="${LDFLAGS} -no-undefined"
-	LIBS="${LIBS} -lsetupapi"
+	LIBS="${LIBS}"
 fi
 fi
 
 
 if test "x$threads" = xpthreads; then
 if test "x$threads" = xpthreads; then
@@ -175,15 +194,15 @@ mkdir testgui/TestGUI.app/Contents/MacOS/
 
 
 if test "x$testgui_enabled" != "xno"; then
 if test "x$testgui_enabled" != "xno"; then
 	if test "x$os" = xdarwin; 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)
 		AC_CHECK_PROG([foxconfig], [fox-config], [fox-config], false)
 		if test "x$foxconfig" = "xfalse"; then
 		if test "x$foxconfig" = "xfalse"; then
 			hidapi_prog_error fox-config "FOX Toolkit"
 			hidapi_prog_error fox-config "FOX Toolkit"
 		fi
 		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
 	elif test "x$os" = xwindows; then
 		# On Windows, just set the paths for Fox toolkit
 		# On Windows, just set the paths for Fox toolkit
 		if test "x$win_implementation" = xmingw; then
 		if test "x$win_implementation" = xmingw; then
@@ -213,6 +232,7 @@ AM_CONDITIONAL(OS_LINUX, test "x$os" = xlinux)
 AM_CONDITIONAL(OS_DARWIN, test "x$os" = xdarwin)
 AM_CONDITIONAL(OS_DARWIN, test "x$os" = xdarwin)
 AM_CONDITIONAL(OS_FREEBSD, test "x$os" = xfreebsd)
 AM_CONDITIONAL(OS_FREEBSD, test "x$os" = xfreebsd)
 AM_CONDITIONAL(OS_KFREEBSD, test "x$os" = xkfreebsd)
 AM_CONDITIONAL(OS_KFREEBSD, test "x$os" = xkfreebsd)
+AM_CONDITIONAL(OS_HAIKU, test "x$os" = xhaiku)
 AM_CONDITIONAL(OS_WINDOWS, test "x$os" = xwindows)
 AM_CONDITIONAL(OS_WINDOWS, test "x$os" = xwindows)
 
 
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_HEADERS([config.h])

+ 31 - 0
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" => "[email protected]",
+                        "Ludovic Rousseau" => "[email protected]",
+                        "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

BIN
src/hidapi/documentation/cmake-gui-drop-down.png


BIN
src/hidapi/documentation/cmake-gui-highlights.png


File diff suppressed because it is too large
+ 682 - 327
src/hidapi/doxygen/Doxyfile


+ 13 - 0
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.

+ 261 - 58
src/hidapi/hidapi/hidapi.h

@@ -5,9 +5,9 @@
  Alan Ott
  Alan Ott
  Signal 11 Software
  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,
  At the discretion of the user of this library,
  this software may be licensed under the terms of the
  this software may be licensed under the terms of the
@@ -29,36 +29,123 @@
 
 
 #include <wchar.h>
 #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_EXPORT __declspec(dllexport)
-      #define HID_API_CALL
-#else
-#ifndef HID_API_EXPORT
-      #define HID_API_EXPORT /**< API export macro */
-#endif
-#ifndef HID_API_CALL
-      #define HID_API_CALL /**< API call macro */
+   #endif
 #endif
 #endif
+#ifndef HID_API_EXPORT
+   #define HID_API_EXPORT /**< API export 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*/
 #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" {
 extern "C" {
 #endif
 #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_;
 		struct hid_device_;
 		typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
 		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 */
 		/** hidapi info structure */
 		struct hid_device_info {
 		struct hid_device_info {
 			/** Platform-specific device path */
 			/** Platform-specific device path */
@@ -77,29 +164,27 @@ namespace NAMESPACE {
 			/** Product string */
 			/** Product string */
 			wchar_t *product_string;
 			wchar_t *product_string;
 			/** Usage Page for this Device/Interface
 			/** Usage Page for this Device/Interface
-			    (Windows/Mac only). */
+			    (Windows/Mac/hidraw only) */
 			unsigned short usage_page;
 			unsigned short usage_page;
 			/** Usage for this Device/Interface
 			/** Usage for this Device/Interface
-			    (Windows/Mac only).*/
+			    (Windows/Mac/hidraw only) */
 			unsigned short usage;
 			unsigned short usage;
 			/** The USB interface which this logical device
 			/** The USB interface which this logical device
 			    represents.
 			    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;
 			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 */
 			/** Pointer to the next device */
 			struct hid_device_info *next;
 			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.
 		/** @brief Initialize the HIDAPI library.
@@ -115,6 +200,7 @@ namespace NAMESPACE {
 
 
 			@returns
 			@returns
 				This function returns 0 on success and -1 on error.
 				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);
 		int HID_API_EXPORT HID_API_CALL hid_init(void);
 
 
@@ -126,7 +212,7 @@ namespace NAMESPACE {
 
 
 			@ingroup API
 			@ingroup API
 
 
-		    @returns
+			@returns
 				This function returns 0 on success and -1 on error.
 				This function returns 0 on success and -1 on error.
 		*/
 		*/
 		int HID_API_EXPORT HID_API_CALL hid_exit(void);
 		int HID_API_EXPORT HID_API_CALL hid_exit(void);
@@ -146,21 +232,25 @@ namespace NAMESPACE {
 			@param product_id The Product ID (PID) of the types of
 			@param product_id The Product ID (PID) of the types of
 				device to open.
 				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);
 		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
 		/** @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
 			@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);
 		void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
 
 
@@ -174,11 +264,15 @@ namespace NAMESPACE {
 			@param vendor_id The Vendor ID (VID) of the device to open.
 			@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 product_id The Product ID (PID) of the device to open.
 			@param serial_number The Serial Number of the device to open
 			@param serial_number The Serial Number of the device to open
-				               (Optionally NULL).
+			                     (Optionally NULL).
 
 
 			@returns
 			@returns
 				This function returns a pointer to a #hid_device object on
 				This function returns a pointer to a #hid_device object on
 				success or NULL on failure.
 				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);
 		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 @@ namespace NAMESPACE {
 			Linux).
 			Linux).
 
 
 			@ingroup API
 			@ingroup API
-		    @param path The path name of the device to open
+			@param path The path name of the device to open
 
 
 			@returns
 			@returns
 				This function returns a pointer to a #hid_device object on
 				This function returns a pointer to a #hid_device object on
 				success or NULL on failure.
 				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.
 		/** @brief Write an Output report to a HID device.
 
 
@@ -222,6 +320,7 @@ namespace NAMESPACE {
 			@returns
 			@returns
 				This function returns the actual number of bytes written and
 				This function returns the actual number of bytes written and
 				-1 on error.
 				-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);
 		int  HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length);
 
 
@@ -241,7 +340,9 @@ namespace NAMESPACE {
 
 
 			@returns
 			@returns
 				This function returns the actual number of bytes read and
 				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.
 				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);
 		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 @@ namespace NAMESPACE {
 		/** @brief Read an Input report from a HID device.
 		/** @brief Read an Input report from a HID device.
 
 
 			Input reports are returned
 			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.
 			contain the Report number if the device uses numbered reports.
 
 
 			@ingroup API
 			@ingroup API
@@ -261,7 +362,9 @@ namespace NAMESPACE {
 
 
 			@returns
 			@returns
 				This function returns the actual number of bytes read and
 				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.
 				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);
 		int  HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length);
@@ -283,6 +386,7 @@ namespace NAMESPACE {
 
 
 			@returns
 			@returns
 				This function returns 0 on success and -1 on error.
 				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);
 		int  HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock);
 
 
@@ -311,6 +415,7 @@ namespace NAMESPACE {
 			@returns
 			@returns
 				This function returns the actual number of bytes written and
 				This function returns the actual number of bytes written and
 				-1 on error.
 				-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);
 		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 @@ namespace NAMESPACE {
 				This function returns the number of bytes read plus
 				This function returns the number of bytes read plus
 				one for the report ID (which is still in the first
 				one for the report ID (which is still in the first
 				byte), or -1 on error.
 				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);
 		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.
 		/** @brief Close a HID device.
 
 
 			@ingroup API
 			@ingroup API
@@ -355,6 +489,7 @@ namespace NAMESPACE {
 
 
 			@returns
 			@returns
 				This function returns 0 on success and -1 on error.
 				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);
 		int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen);
 
 
@@ -367,6 +502,7 @@ namespace NAMESPACE {
 
 
 			@returns
 			@returns
 				This function returns 0 on success and -1 on error.
 				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);
 		int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen);
 
 
@@ -379,9 +515,27 @@ namespace NAMESPACE {
 
 
 			@returns
 			@returns
 				This function returns 0 on success and -1 on error.
 				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);
 		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.
 		/** @brief Get a string from a HID device, based on its string index.
 
 
 			@ingroup API
 			@ingroup API
@@ -392,30 +546,79 @@ namespace NAMESPACE {
 
 
 			@returns
 			@returns
 				This function returns 0 on success and -1 on error.
 				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);
 		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
 			@ingroup API
 			@param dev A device handle returned from hid_open().
 			@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
 			@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);
 		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
 
 
 #endif
 #endif
-

+ 17 - 0
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

+ 40 - 0
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}"
+)

+ 11 - 3
src/hidapi/hidtest/Makefile.am

@@ -4,17 +4,25 @@ AM_CPPFLAGS = -I$(top_srcdir)/hidapi/
 if OS_LINUX
 if OS_LINUX
 noinst_PROGRAMS = hidtest-libusb hidtest-hidraw
 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_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
 hidtest_libusb_LDADD = $(top_builddir)/libusb/libhidapi-libusb.la
 else
 else
 
 
 # Other OS's
 # Other OS's
 noinst_PROGRAMS = hidtest
 noinst_PROGRAMS = hidtest
 
 
-hidtest_SOURCES = hidtest.cpp
+hidtest_SOURCES = test.c
 hidtest_LDADD = $(top_builddir)/$(backend)/libhidapi.la
 hidtest_LDADD = $(top_builddir)/$(backend)/libhidapi.la
 
 
 endif
 endif
+
+if OS_DARWIN
+AM_CPPFLAGS += -I$(top_srcdir)/mac/
+endif
+
+if OS_WINDOWS
+AM_CPPFLAGS += -I$(top_srcdir)/windows/
+endif

+ 0 - 194
src/hidapi/hidtest/hidtest.cpp

@@ -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;
-}

+ 316 - 0
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;
+}

+ 0 - 32
src/hidapi/ios/Makefile-manual

@@ -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

+ 0 - 9
src/hidapi/ios/Makefile.am

@@ -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

+ 0 - 996
src/hidapi/ios/hid.m

@@ -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 */

+ 8 - 0
src/hidapi/libusb/.gitignore

@@ -0,0 +1,8 @@
+*.o
+*.so
+*.la
+*.lo
+*.a
+.libs
+.deps
+hidtest-libusb

+ 107 - 0
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")

+ 4 - 0
src/hidapi/libusb/Makefile-manual

@@ -10,6 +10,10 @@ ifeq ($(OS), FreeBSD)
 	FILE=Makefile.freebsd
 	FILE=Makefile.freebsd
 endif
 endif
 
 
+ifeq ($(OS), Haiku)
+	FILE=Makefile.haiku
+endif
+
 ifeq ($(FILE), )
 ifeq ($(FILE), )
 all:
 all:
 	$(error Your platform ${OS} is not supported by hidapi/libusb at this time.)
 	$(error Your platform ${OS} is not supported by hidapi/libusb at this time.)

+ 8 - 1
src/hidapi/libusb/Makefile.am

@@ -21,7 +21,14 @@ libhidapi_la_LDFLAGS = $(LTLDFLAGS)
 libhidapi_la_LIBADD = $(LIBS_LIBUSB)
 libhidapi_la_LIBADD = $(LIBS_LIBUSB)
 endif
 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
 hdrdir = $(includedir)/hidapi
-hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h
+hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h hidapi_libusb.h
 
 
 EXTRA_DIST = Makefile-manual
 EXTRA_DIST = Makefile-manual

+ 4 - 11
src/hidapi/libusb/Makefile.freebsd

@@ -13,20 +13,16 @@ libs: libhidapi.so
 CC       ?= cc
 CC       ?= cc
 CFLAGS   ?= -Wall -g -fPIC
 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
 LDFLAGS   = -L/usr/local/lib
 LIBS      = -lusb -liconv -pthread
 LIBS      = -lusb -liconv -pthread
 
 
 
 
 # Console Test Program
 # Console Test Program
 hidtest: $(OBJS)
 hidtest: $(OBJS)
-	$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
+	$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS)
 
 
 # Shared Libs
 # Shared Libs
 libhidapi.so: $(COBJS)
 libhidapi.so: $(COBJS)
@@ -36,9 +32,6 @@ libhidapi.so: $(COBJS)
 $(COBJS): %.o: %.c
 $(COBJS): %.o: %.c
 	$(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@
 	$(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@
 
 
-$(CPPOBJS): %.o: %.cpp
-	$(CXX) $(CXXFLAGS) -c $(INCLUDES) $< -o $@
-
 
 
 clean:
 clean:
 	rm -f $(OBJS) hidtest libhidapi.so ../hidtest/hidtest.o
 	rm -f $(OBJS) hidtest libhidapi.so ../hidtest/hidtest.o

+ 39 - 0
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,[email protected] $^ -o $@ $(LIBS)
+
+# Objects
+$(COBJS): %.o: %.c
+    $(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@
+
+
+clean:
+    rm -f $(OBJS) hidtest libhidapi.so ../hidtest/hidtest.o
+
+.PHONY: clean libs

+ 5 - 12
src/hidapi/libusb/Makefile.linux

@@ -13,23 +13,19 @@ libs: libhidapi-libusb.so
 CC       ?= gcc
 CC       ?= gcc
 CFLAGS   ?= -Wall -g -fpic
 CFLAGS   ?= -Wall -g -fpic
 
 
-CXX      ?= g++
-CXXFLAGS ?= -Wall -g -fpic
-
 LDFLAGS  ?= -Wall -g
 LDFLAGS  ?= -Wall -g
 
 
 COBJS_LIBUSB = hid.o
 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_USB  = `pkg-config libusb-1.0 --libs` -lrt -lpthread
 LIBS      = $(LIBS_USB)
 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
 # Console Test Program
-hidtest-libusb: $(COBJS_LIBUSB) $(CPPOBJS)
-	$(CXX) $(LDFLAGS) $^ $(LIBS_USB) -o $@
+hidtest-libusb: $(COBJS)
+	$(CC) $(LDFLAGS) $^ $(LIBS_USB) -o $@
 
 
 # Shared Libs
 # Shared Libs
 libhidapi-libusb.so: $(COBJS_LIBUSB)
 libhidapi-libusb.so: $(COBJS_LIBUSB)
@@ -39,9 +35,6 @@ libhidapi-libusb.so: $(COBJS_LIBUSB)
 $(COBJS): %.o: %.c
 $(COBJS): %.o: %.c
 	$(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@
 	$(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@
 
 
-$(CPPOBJS): %.o: %.cpp
-	$(CXX) $(CXXFLAGS) -c $(INCLUDES) $< -o $@
-
 
 
 clean:
 clean:
 	rm -f $(OBJS) hidtest-libusb libhidapi-libusb.so ../hidtest/hidtest.o
 	rm -f $(OBJS) hidtest-libusb libhidapi-libusb.so ../hidtest/hidtest.o

File diff suppressed because it is too large
+ 357 - 451
src/hidapi/libusb/hid.c


+ 56 - 0
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

+ 0 - 3
src/hidapi/libusb/hidusb.cpp

@@ -1,3 +0,0 @@
-
-#define NAMESPACE HIDUSB
-#include "hid.c"

+ 18 - 0
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

+ 38 - 0
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")

+ 5 - 12
src/hidapi/linux/Makefile-manual

@@ -13,23 +13,19 @@ libs: libhidapi-hidraw.so
 CC       ?= gcc
 CC       ?= gcc
 CFLAGS   ?= -Wall -g -fpic
 CFLAGS   ?= -Wall -g -fpic
 
 
-CXX      ?= g++
-CXXFLAGS ?= -Wall -g -fpic
-
 LDFLAGS  ?= -Wall -g
 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_UDEV = `pkg-config libudev --libs` -lrt
 LIBS      = $(LIBS_UDEV)
 LIBS      = $(LIBS_UDEV)
 INCLUDES ?= -I../hidapi `pkg-config libusb-1.0 --cflags`
 INCLUDES ?= -I../hidapi `pkg-config libusb-1.0 --cflags`
 
 
 
 
 # Console Test Program
 # Console Test Program
-hidtest-hidraw: $(COBJS) $(CPPOBJS)
-	$(CXX) $(LDFLAGS) $^ $(LIBS_UDEV) -o $@
+hidtest-hidraw: $(COBJS)
+	$(CC) $(LDFLAGS) $^ $(LIBS_UDEV) -o $@
 
 
 # Shared Libs
 # Shared Libs
 libhidapi-hidraw.so: $(COBJS)
 libhidapi-hidraw.so: $(COBJS)
@@ -39,11 +35,8 @@ libhidapi-hidraw.so: $(COBJS)
 $(COBJS): %.o: %.c
 $(COBJS): %.o: %.c
 	$(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@
 	$(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@
 
 
-$(CPPOBJS): %.o: %.cpp
-	$(CXX) $(CXXFLAGS) -c $(INCLUDES) $< -o $@
-
 
 
 clean:
 clean:
-	rm -f $(OBJS) hidtest-hidraw libhidapi-hidraw.so ../hidtest/hidtest.o
+	rm -f $(OBJS) hidtest-hidraw libhidapi-hidraw.so $(COBJS)
 
 
 .PHONY: clean libs
 .PHONY: clean libs

+ 0 - 59
src/hidapi/linux/README.txt

@@ -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).

File diff suppressed because it is too large
+ 631 - 263
src/hidapi/linux/hid.c


+ 0 - 3
src/hidapi/linux/hidraw.cpp

@@ -1,3 +0,0 @@
-
-#define NAMESPACE HIDRAW
-#include "hid.c"

+ 5 - 0
src/hidapi/m4/.gitignore

@@ -0,0 +1,5 @@
+# Ignore All, except pkg.m4, and of course this file.
+*
+!.gitignore
+!pkg.m4
+!ax_pthread.m4

+ 17 - 0
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

+ 48 - 0
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")

+ 6 - 11
src/hidapi/mac/Makefile-manual

@@ -9,24 +9,19 @@
 all: hidtest
 all: hidtest
 
 
 CC=gcc
 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)
 hidtest: $(OBJS)
-	g++ -Wall -g $^ $(LIBS) -o hidtest
+	$(CC) -Wall -g $^ $(LIBS) -o hidtest
 
 
 $(COBJS): %.o: %.c
 $(COBJS): %.o: %.c
 	$(CC) $(CFLAGS) $< -o $@
 	$(CC) $(CFLAGS) $< -o $@
 
 
-$(CPPOBJS): %.o: %.cpp
-	$(CXX) $(CFLAGS) $< -o $@
-
 clean:
 clean:
-	rm -f *.o hidtest $(CPPOBJS)
+	rm -f *.o hidtest
 
 
 .PHONY: clean
 .PHONY: clean

File diff suppressed because it is too large
+ 504 - 345
src/hidapi/mac/hid.c


+ 98 - 0
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

+ 22 - 0
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

+ 1 - 0
src/hidapi/pc/.gitignore

@@ -0,0 +1 @@
+*.pc

+ 1 - 0
src/hidapi/pc/hidapi-hidraw.pc.in

@@ -5,6 +5,7 @@ includedir=@includedir@
 
 
 Name: hidapi-hidraw
 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.
 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@
 Version: @VERSION@
 Libs: -L${libdir} -lhidapi-hidraw
 Libs: -L${libdir} -lhidapi-hidraw
 Cflags: -I${includedir}/hidapi
 Cflags: -I${includedir}/hidapi

+ 1 - 0
src/hidapi/pc/hidapi-libusb.pc.in

@@ -5,6 +5,7 @@ includedir=@includedir@
 
 
 Name: hidapi-libusb
 Name: hidapi-libusb
 Description: C Library for USB HID device access from Linux, Mac OS X, FreeBSD, and Windows. This is the libusb implementation.
 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@
 Version: @VERSION@
 Libs: -L${libdir} -lhidapi-libusb
 Libs: -L${libdir} -lhidapi-libusb
 Cflags: -I${includedir}/hidapi
 Cflags: -I${includedir}/hidapi

+ 1 - 0
src/hidapi/pc/hidapi.pc.in

@@ -5,6 +5,7 @@ includedir=@includedir@
 
 
 Name: hidapi
 Name: hidapi
 Description: C Library for USB/Bluetooth HID device access from Linux, Mac OS X, FreeBSD, and Windows.
 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@
 Version: @VERSION@
 Libs: -L${libdir} -lhidapi
 Libs: -L${libdir} -lhidapi
 Cflags: -I${includedir}/hidapi
 Cflags: -I${includedir}/hidapi

+ 193 - 0
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()

+ 61 - 0
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()

+ 2 - 0
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.

+ 10 - 0
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)

+ 20 - 0
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

+ 1 - 1
src/hidapi/testgui/Makefile.mingw

@@ -14,7 +14,7 @@ COBJS=../windows/hid.o
 CPPOBJS=test.o
 CPPOBJS=test.o
 OBJS=$(COBJS) $(CPPOBJS)
 OBJS=$(COBJS) $(CPPOBJS)
 CFLAGS=-I../hidapi -I../../hidapi-externals/fox/include -g -c
 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)
 hidapi-testgui: $(OBJS)

+ 2 - 1
src/hidapi/testgui/copy_to_bundle.sh

@@ -77,9 +77,10 @@ function copydeps {
 }
 }
 
 
 rm -f $EXEPATH/*
 rm -f $EXEPATH/*
+mkdir -p $EXEPATH
 
 
 # Copy the binary into the bundle. Use ../libtool to do this if it's
 # 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
 # necessary.  If ../libtool not available, just use cp to do the copy, but
 # only if $EXE_NAME is a binary.
 # only if $EXE_NAME is a binary.
 if [ -x ../libtool ]; then
 if [ -x ../libtool ]; then

+ 0 - 134
src/hidapi/testgui/mac_support.cpp

@@ -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); 
-		} 
-	}
-}

+ 11 - 2
src/hidapi/testgui/mac_support_cocoa.m

@@ -8,10 +8,19 @@
 #include <fx.h>
 #include <fx.h>
 #import <Cocoa/Cocoa.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;
 extern FXMainWindow *g_main_window;
 
 
 
 
-@interface MyAppDelegate : NSObject
+@interface MyAppDelegate : NSObject<NSApplicationDelegate>
 {
 {
 } 
 } 
 @end
 @end
@@ -77,7 +86,7 @@ check_apple_events()
 
 
 	NSAutoreleasePool *pool = [NSAutoreleasePool new];
 	NSAutoreleasePool *pool = [NSAutoreleasePool new];
 	while (1) {
 	while (1) {
-		NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
+		NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
 		                        untilDate:nil
 		                        untilDate:nil
                                         inMode:NSDefaultRunLoopMode
                                         inMode:NSDefaultRunLoopMode
                                         dequeue:YES];
                                         dequeue:YES];

+ 0 - 2
src/hidapi/testgui/start.sh

@@ -1,2 +0,0 @@
-#!/bin/bash
-xterm -e /Users/alan/work/hidapi/testgui/TestGUI.app/Contents/MacOS/tg

+ 20 - 20
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

+ 217 - 217
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>

+ 36 - 0
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).

+ 0 - 33
src/hidapi/udev/99-hid.rules

@@ -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).

+ 17 - 0
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

+ 63 - 0
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()

+ 0 - 1
src/hidapi/windows/Makefile.am

@@ -8,7 +8,6 @@ hdrdir = $(includedir)/hidapi
 hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h
 hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h
 
 
 EXTRA_DIST = \
 EXTRA_DIST = \
-  ddk_build \
   hidapi.vcproj \
   hidapi.vcproj \
   hidtest.vcproj \
   hidtest.vcproj \
   Makefile-manual \
   Makefile-manual \

+ 6 - 11
src/hidapi/windows/Makefile.mingw

@@ -9,16 +9,14 @@
 all: hidtest libhidapi.dll
 all: hidtest libhidapi.dll
 
 
 CC=gcc
 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)
 hidtest: $(OBJS)
-	g++ -g $^ $(LIBS) -o hidtest
+	$(CC) -g $^ $(LIBS) -o hidtest
 
 
 libhidapi.dll: $(OBJS)
 libhidapi.dll: $(OBJS)
 	$(CC) -g $^ $(DLL_LDFLAGS) -o libhidapi.dll
 	$(CC) -g $^ $(DLL_LDFLAGS) -o libhidapi.dll
@@ -26,9 +24,6 @@ libhidapi.dll: $(OBJS)
 $(COBJS): %.o: %.c
 $(COBJS): %.o: %.c
 	$(CC) $(CFLAGS) $< -o $@
 	$(CC) $(CFLAGS) $< -o $@
 
 
-$(CPPOBJS): %.o: %.cpp
-	$(CXX) $(CFLAGS) $< -o $@
-
 clean:
 clean:
 	rm *.o ../hidtest/*.o hidtest.exe
 	rm *.o ../hidtest/*.o hidtest.exe
 
 

+ 0 - 17
src/hidapi/windows/ddk_build/hidapi.def

@@ -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
-   

+ 0 - 49
src/hidapi/windows/ddk_build/makefile

@@ -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
-

+ 0 - 23
src/hidapi/windows/ddk_build/sources

@@ -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"
-

File diff suppressed because it is too large
+ 429 - 456
src/hidapi/windows/hid.c


+ 35 - 0
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

+ 41 - 29
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

+ 200 - 201
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>

+ 200 - 0
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>

+ 14 - 16
src/hidapi/windows/hidapi_cfgmgr32.h

@@ -28,18 +28,14 @@
 #include <propkey.h>
 #include <propkey.h>
 
 
 #else
 #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,
 /* This part of the header mimics cfgmgr32.h,
     but only what is used by HIDAPI */
     but only what is used by HIDAPI */
 
 
+#include <initguid.h>
+#include <devpropdef.h>
+#include <propkeydef.h>
+
 typedef DWORD RETURN_TYPE;
 typedef DWORD RETURN_TYPE;
 typedef RETURN_TYPE CONFIGRET;
 typedef RETURN_TYPE CONFIGRET;
 typedef DWORD DEVNODE, DEVINST;
 typedef DWORD DEVNODE, DEVINST;
@@ -59,18 +55,20 @@ typedef CONFIGRET(__stdcall* CM_Get_Parent_)(PDEVINST pdnDevInst, DEVINST dnDevI
 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_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_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_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
 // 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
 // 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
 #endif
 
 

+ 987 - 0
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;
+}

+ 238 - 0
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

+ 7 - 0
src/hidapi/windows/hidapi_hidpi.h

@@ -29,6 +29,13 @@
 /* This part of the header mimics hidpi.h,
 /* This part of the header mimics hidpi.h,
     but only what is used by HIDAPI */
     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_PREPARSED_DATA * PHIDP_PREPARSED_DATA;
 
 
 typedef struct _HIDP_CAPS
 typedef struct _HIDP_CAPS

+ 2 - 1
src/hidapi/windows/hidapi_hidsdi.h

@@ -40,6 +40,8 @@ typedef struct _HIDD_ATTRIBUTES{
 	USHORT VersionNumber;
 	USHORT VersionNumber;
 } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
 } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
 
 
+typedef struct _HIDP_PREPARSED_DATA * PHIDP_PREPARSED_DATA;
+
 typedef void (__stdcall *HidD_GetHidGuid_)(LPGUID hid_guid);
 typedef void (__stdcall *HidD_GetHidGuid_)(LPGUID hid_guid);
 typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);
 typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);
 typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);
 typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);
@@ -52,7 +54,6 @@ typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_
 typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);
 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_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);
 typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
 typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
-typedef BOOLEAN (__stdcall *HidD_SetOutputReport_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
 
 
 #endif
 #endif
 
 

+ 74 - 0
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

+ 196 - 196
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>

Some files were not shown because too many files changed in this diff