From 5a079a2d114f96d4847d1ee305d5b7c16eeec50e Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 27 Dec 2025 12:03:39 -0800 Subject: Initial commit --- contrib/SDL-3.2.8/src/hidapi/AUTHORS.txt | 18 + contrib/SDL-3.2.8/src/hidapi/BUILD.autotools.md | 114 + contrib/SDL-3.2.8/src/hidapi/BUILD.cmake.md | 280 + contrib/SDL-3.2.8/src/hidapi/BUILD.md | 127 + contrib/SDL-3.2.8/src/hidapi/CMakeLists.txt | 108 + contrib/SDL-3.2.8/src/hidapi/HACKING.txt | 19 + contrib/SDL-3.2.8/src/hidapi/LICENSE-bsd.txt | 26 + contrib/SDL-3.2.8/src/hidapi/LICENSE-gpl3.txt | 674 ++ contrib/SDL-3.2.8/src/hidapi/LICENSE-orig.txt | 9 + contrib/SDL-3.2.8/src/hidapi/LICENSE.txt | 13 + contrib/SDL-3.2.8/src/hidapi/Makefile.am | 85 + contrib/SDL-3.2.8/src/hidapi/README.md | 196 + contrib/SDL-3.2.8/src/hidapi/SDL_hidapi.c | 1750 +++ contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_android.h | 26 + contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_c.h | 35 + contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_ios.h | 26 + contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_libusb.h | 134 + contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_linux.h | 47 + contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_mac.h | 25 + contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_netbsd.h | 25 + .../SDL-3.2.8/src/hidapi/SDL_hidapi_steamxbox.h | 23 + contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_windows.h | 82 + contrib/SDL-3.2.8/src/hidapi/VERSION | 1 + contrib/SDL-3.2.8/src/hidapi/android/hid.cpp | 1477 +++ contrib/SDL-3.2.8/src/hidapi/android/hid.h | 39 + contrib/SDL-3.2.8/src/hidapi/bootstrap | 2 + contrib/SDL-3.2.8/src/hidapi/configure.ac | 256 + contrib/SDL-3.2.8/src/hidapi/dist/hidapi.podspec | 31 + .../hidapi/documentation/cmake-gui-drop-down.png | Bin 0 -> 22316 bytes .../hidapi/documentation/cmake-gui-highlights.png | Bin 0 -> 77327 bytes contrib/SDL-3.2.8/src/hidapi/doxygen/Doxyfile | 2724 +++++ contrib/SDL-3.2.8/src/hidapi/doxygen/main_page.md | 13 + contrib/SDL-3.2.8/src/hidapi/hidapi/hidapi.h | 634 + .../SDL-3.2.8/src/hidapi/hidtest/CMakeLists.txt | 40 + contrib/SDL-3.2.8/src/hidapi/hidtest/Makefile.am | 28 + contrib/SDL-3.2.8/src/hidapi/hidtest/test.c | 316 + contrib/SDL-3.2.8/src/hidapi/ios/hid.m | 1038 ++ contrib/SDL-3.2.8/src/hidapi/libusb/CMakeLists.txt | 107 + .../SDL-3.2.8/src/hidapi/libusb/Makefile-manual | 22 + contrib/SDL-3.2.8/src/hidapi/libusb/Makefile.am | 34 + .../SDL-3.2.8/src/hidapi/libusb/Makefile.freebsd | 39 + contrib/SDL-3.2.8/src/hidapi/libusb/Makefile.haiku | 39 + contrib/SDL-3.2.8/src/hidapi/libusb/Makefile.linux | 42 + contrib/SDL-3.2.8/src/hidapi/libusb/hid.c | 2144 ++++ .../SDL-3.2.8/src/hidapi/libusb/hidapi_libusb.h | 56 + .../src/hidapi/libusb/hidapi_thread_pthread.h | 174 + .../src/hidapi/libusb/hidapi_thread_sdl.h | 202 + contrib/SDL-3.2.8/src/hidapi/linux/CMakeLists.txt | 38 + contrib/SDL-3.2.8/src/hidapi/linux/Makefile-manual | 42 + contrib/SDL-3.2.8/src/hidapi/linux/Makefile.am | 10 + contrib/SDL-3.2.8/src/hidapi/linux/hid.c | 1492 +++ contrib/SDL-3.2.8/src/hidapi/m4/ax_pthread.m4 | 309 + contrib/SDL-3.2.8/src/hidapi/m4/pkg.m4 | 157 + contrib/SDL-3.2.8/src/hidapi/mac/CMakeLists.txt | 48 + contrib/SDL-3.2.8/src/hidapi/mac/Makefile-manual | 27 + contrib/SDL-3.2.8/src/hidapi/mac/Makefile.am | 9 + contrib/SDL-3.2.8/src/hidapi/mac/hid.c | 1594 +++ contrib/SDL-3.2.8/src/hidapi/mac/hidapi_darwin.h | 98 + contrib/SDL-3.2.8/src/hidapi/meson.build | 22 + contrib/SDL-3.2.8/src/hidapi/netbsd/CMakeLists.txt | 35 + contrib/SDL-3.2.8/src/hidapi/netbsd/README.md | 29 + contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c | 1173 ++ .../SDL-3.2.8/src/hidapi/pc/hidapi-hidraw.pc.in | 11 + .../SDL-3.2.8/src/hidapi/pc/hidapi-libusb.pc.in | 11 + .../SDL-3.2.8/src/hidapi/pc/hidapi-netbsd.pc.in | 11 + contrib/SDL-3.2.8/src/hidapi/pc/hidapi.pc.in | 11 + contrib/SDL-3.2.8/src/hidapi/src/CMakeLists.txt | 206 + .../src/hidapi/src/cmake/hidapi-config.cmake.in | 61 + contrib/SDL-3.2.8/src/hidapi/subprojects/README.md | 2 + .../subprojects/hidapi_build_cmake/CMakeLists.txt | 10 + .../SDL-3.2.8/src/hidapi/testgui/Makefile-manual | 26 + contrib/SDL-3.2.8/src/hidapi/testgui/Makefile.am | 43 + .../SDL-3.2.8/src/hidapi/testgui/Makefile.freebsd | 33 + .../SDL-3.2.8/src/hidapi/testgui/Makefile.linux | 32 + contrib/SDL-3.2.8/src/hidapi/testgui/Makefile.mac | 46 + .../SDL-3.2.8/src/hidapi/testgui/Makefile.mingw | 32 + .../testgui/TestGUI.app.in/Contents/Info.plist | 28 + .../hidapi/testgui/TestGUI.app.in/Contents/PkgInfo | 1 + .../Resources/English.lproj/InfoPlist.strings | Bin 0 -> 92 bytes .../Contents/Resources/Signal11.icns | Bin 0 -> 21918 bytes .../SDL-3.2.8/src/hidapi/testgui/copy_to_bundle.sh | 98 + contrib/SDL-3.2.8/src/hidapi/testgui/mac_support.h | 17 + .../src/hidapi/testgui/mac_support_cocoa.m | 103 + contrib/SDL-3.2.8/src/hidapi/testgui/test.cpp | 532 + contrib/SDL-3.2.8/src/hidapi/testgui/testgui.sln | 20 + .../SDL-3.2.8/src/hidapi/testgui/testgui.vcproj | 217 + contrib/SDL-3.2.8/src/hidapi/udev/69-hid.rules | 36 + .../SDL-3.2.8/src/hidapi/windows/CMakeLists.txt | 63 + .../SDL-3.2.8/src/hidapi/windows/Makefile-manual | 14 + contrib/SDL-3.2.8/src/hidapi/windows/Makefile.am | 15 + .../SDL-3.2.8/src/hidapi/windows/Makefile.mingw | 30 + contrib/SDL-3.2.8/src/hidapi/windows/hid.c | 1728 +++ contrib/SDL-3.2.8/src/hidapi/windows/hidapi.rc | 35 + contrib/SDL-3.2.8/src/hidapi/windows/hidapi.sln | 41 + contrib/SDL-3.2.8/src/hidapi/windows/hidapi.vcproj | 200 + .../SDL-3.2.8/src/hidapi/windows/hidapi.vcxproj | 200 + .../SDL-3.2.8/src/hidapi/windows/hidapi_cfgmgr32.h | 86 + .../hidapi/windows/hidapi_descriptor_reconstruct.c | 990 ++ .../hidapi/windows/hidapi_descriptor_reconstruct.h | 254 + .../SDL-3.2.8/src/hidapi/windows/hidapi_hidclass.h | 40 + .../SDL-3.2.8/src/hidapi/windows/hidapi_hidpi.h | 72 + .../SDL-3.2.8/src/hidapi/windows/hidapi_hidsdi.h | 59 + .../SDL-3.2.8/src/hidapi/windows/hidapi_winapi.h | 74 + .../SDL-3.2.8/src/hidapi/windows/hidtest.vcproj | 196 + .../SDL-3.2.8/src/hidapi/windows/hidtest.vcxproj | 176 + .../src/hidapi/windows/pp_data_dump/CMakeLists.txt | 15 + .../src/hidapi/windows/pp_data_dump/README.md | 122 + .../src/hidapi/windows/pp_data_dump/pp_data_dump.c | 238 + .../src/hidapi/windows/test/CMakeLists.txt | 76 + .../windows/test/data/045E_02FF_0005_0001.pp_data | 420 + .../data/045E_02FF_0005_0001_expected.rpt_desc | 12 + .../test/data/045E_02FF_0005_0001_real.rpt_desc | 64 + .../windows/test/data/046A_0011_0006_0001.pp_data | 183 + .../data/046A_0011_0006_0001_expected.rpt_desc | 7 + .../test/data/046A_0011_0006_0001_real.rpt_desc | 7 + .../windows/test/data/046D_0A37_0001_000C.pp_data | 532 + .../data/046D_0A37_0001_000C_expected.rpt_desc | 16 + .../test/data/046D_0A37_0001_000C_real.rpt_desc | 61 + .../windows/test/data/046D_B010_0001_000C.pp_data | 97 + .../data/046D_B010_0001_000C_expected.rpt_desc | 3 + .../test/data/046D_B010_0001_000C_real.rpt_desc | 38 + .../windows/test/data/046D_B010_0001_FF00.pp_data | 139 + .../data/046D_B010_0001_FF00_expected.rpt_desc | 4 + .../test/data/046D_B010_0001_FF00_real.rpt_desc | 39 + .../windows/test/data/046D_B010_0002_0001.pp_data | 302 + .../data/046D_B010_0002_0001_expected.rpt_desc | 8 + .../test/data/046D_B010_0002_0001_real.rpt_desc | 61 + .../windows/test/data/046D_B010_0002_FF00.pp_data | 139 + .../data/046D_B010_0002_FF00_expected.rpt_desc | 4 + .../test/data/046D_B010_0002_FF00_real.rpt_desc | 39 + .../windows/test/data/046D_B010_0006_0001.pp_data | 185 + .../data/046D_B010_0006_0001_expected.rpt_desc | 7 + .../test/data/046D_B010_0006_0001_real.rpt_desc | 58 + .../windows/test/data/046D_C077_0002_0001.pp_data | 252 + .../data/046D_C077_0002_0001_expected.rpt_desc | 5 + .../test/data/046D_C077_0002_0001_real.rpt_desc | 24 + .../windows/test/data/046D_C283_0004_0001.pp_data | 520 + .../data/046D_C283_0004_0001_expected.rpt_desc | 18 + .../test/data/046D_C283_0004_0001_real.rpt_desc | 18 + .../windows/test/data/046D_C52F_0001_000C.pp_data | 93 + .../data/046D_C52F_0001_000C_expected.rpt_desc | 3 + .../test/data/046D_C52F_0001_000C_real.rpt_desc | 12 + .../windows/test/data/046D_C52F_0001_FF00.pp_data | 139 + .../data/046D_C52F_0001_FF00_expected.rpt_desc | 4 + .../test/data/046D_C52F_0001_FF00_real.rpt_desc | 13 + .../windows/test/data/046D_C52F_0002_0001.pp_data | 302 + .../data/046D_C52F_0002_0001_expected.rpt_desc | 8 + .../test/data/046D_C52F_0002_0001_real.rpt_desc | 33 + .../windows/test/data/046D_C52F_0002_FF00.pp_data | 139 + .../data/046D_C52F_0002_FF00_expected.rpt_desc | 4 + .../test/data/046D_C52F_0002_FF00_real.rpt_desc | 13 + .../windows/test/data/046D_C534_0001_000C.pp_data | 93 + .../data/046D_C534_0001_000C_expected.rpt_desc | 3 + .../test/data/046D_C534_0001_000C_real.rpt_desc | 18 + .../windows/test/data/046D_C534_0001_FF00.pp_data | 139 + .../data/046D_C534_0001_FF00_expected.rpt_desc | 4 + .../test/data/046D_C534_0001_FF00_real.rpt_desc | 20 + .../windows/test/data/046D_C534_0002_0001.pp_data | 302 + .../data/046D_C534_0002_0001_expected.rpt_desc | 8 + .../test/data/046D_C534_0002_0001_real.rpt_desc | 44 + .../windows/test/data/046D_C534_0002_FF00.pp_data | 139 + .../data/046D_C534_0002_FF00_expected.rpt_desc | 4 + .../test/data/046D_C534_0002_FF00_real.rpt_desc | 22 + .../windows/test/data/046D_C534_0006_0001.pp_data | 185 + .../data/046D_C534_0006_0001_expected.rpt_desc | 7 + .../test/data/046D_C534_0006_0001_real.rpt_desc | 42 + .../windows/test/data/046D_C534_0080_0001.pp_data | 185 + .../data/046D_C534_0080_0001_expected.rpt_desc | 4 + .../test/data/046D_C534_0080_0001_real.rpt_desc | 22 + .../windows/test/data/047F_C056_0001_000C.pp_data | 385 + .../data/047F_C056_0001_000C_expected.rpt_desc | 10 + .../test/data/047F_C056_0001_000C_real.rpt_desc | 47 + .../windows/test/data/047F_C056_0003_FFA0.pp_data | 1255 ++ .../data/047F_C056_0003_FFA0_expected.rpt_desc | 24 + .../test/data/047F_C056_0003_FFA0_real.rpt_desc | 113 + .../windows/test/data/047F_C056_0005_000B.pp_data | 461 + .../data/047F_C056_0005_000B_expected.rpt_desc | 17 + .../test/data/047F_C056_0005_000B_real.rpt_desc | 68 + .../windows/test/data/17CC_1130_0000_FF01.pp_data | 11508 +++++++++++++++++++ .../data/17CC_1130_0000_FF01_expected.rpt_desc | 75 + .../test/data/17CC_1130_0000_FF01_real.rpt_desc | 381 + .../windows/test/hid_report_reconstructor_test.c | 563 + 182 files changed, 44867 insertions(+) create mode 100644 contrib/SDL-3.2.8/src/hidapi/AUTHORS.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/BUILD.autotools.md create mode 100644 contrib/SDL-3.2.8/src/hidapi/BUILD.cmake.md create mode 100644 contrib/SDL-3.2.8/src/hidapi/BUILD.md create mode 100644 contrib/SDL-3.2.8/src/hidapi/CMakeLists.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/HACKING.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/LICENSE-bsd.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/LICENSE-gpl3.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/LICENSE-orig.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/LICENSE.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/Makefile.am create mode 100644 contrib/SDL-3.2.8/src/hidapi/README.md create mode 100644 contrib/SDL-3.2.8/src/hidapi/SDL_hidapi.c create mode 100644 contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_android.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_c.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_ios.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_libusb.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_linux.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_mac.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_netbsd.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_steamxbox.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_windows.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/VERSION create mode 100644 contrib/SDL-3.2.8/src/hidapi/android/hid.cpp create mode 100644 contrib/SDL-3.2.8/src/hidapi/android/hid.h create mode 100755 contrib/SDL-3.2.8/src/hidapi/bootstrap create mode 100644 contrib/SDL-3.2.8/src/hidapi/configure.ac create mode 100644 contrib/SDL-3.2.8/src/hidapi/dist/hidapi.podspec create mode 100644 contrib/SDL-3.2.8/src/hidapi/documentation/cmake-gui-drop-down.png create mode 100644 contrib/SDL-3.2.8/src/hidapi/documentation/cmake-gui-highlights.png create mode 100644 contrib/SDL-3.2.8/src/hidapi/doxygen/Doxyfile create mode 100644 contrib/SDL-3.2.8/src/hidapi/doxygen/main_page.md create mode 100644 contrib/SDL-3.2.8/src/hidapi/hidapi/hidapi.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/hidtest/CMakeLists.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/hidtest/Makefile.am create mode 100644 contrib/SDL-3.2.8/src/hidapi/hidtest/test.c create mode 100644 contrib/SDL-3.2.8/src/hidapi/ios/hid.m create mode 100644 contrib/SDL-3.2.8/src/hidapi/libusb/CMakeLists.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/libusb/Makefile-manual create mode 100644 contrib/SDL-3.2.8/src/hidapi/libusb/Makefile.am create mode 100644 contrib/SDL-3.2.8/src/hidapi/libusb/Makefile.freebsd create mode 100644 contrib/SDL-3.2.8/src/hidapi/libusb/Makefile.haiku create mode 100644 contrib/SDL-3.2.8/src/hidapi/libusb/Makefile.linux create mode 100644 contrib/SDL-3.2.8/src/hidapi/libusb/hid.c create mode 100644 contrib/SDL-3.2.8/src/hidapi/libusb/hidapi_libusb.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/libusb/hidapi_thread_pthread.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/libusb/hidapi_thread_sdl.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/linux/CMakeLists.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/linux/Makefile-manual create mode 100644 contrib/SDL-3.2.8/src/hidapi/linux/Makefile.am create mode 100644 contrib/SDL-3.2.8/src/hidapi/linux/hid.c create mode 100644 contrib/SDL-3.2.8/src/hidapi/m4/ax_pthread.m4 create mode 100644 contrib/SDL-3.2.8/src/hidapi/m4/pkg.m4 create mode 100644 contrib/SDL-3.2.8/src/hidapi/mac/CMakeLists.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/mac/Makefile-manual create mode 100644 contrib/SDL-3.2.8/src/hidapi/mac/Makefile.am create mode 100644 contrib/SDL-3.2.8/src/hidapi/mac/hid.c create mode 100644 contrib/SDL-3.2.8/src/hidapi/mac/hidapi_darwin.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/meson.build create mode 100644 contrib/SDL-3.2.8/src/hidapi/netbsd/CMakeLists.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/netbsd/README.md create mode 100644 contrib/SDL-3.2.8/src/hidapi/netbsd/hid.c create mode 100644 contrib/SDL-3.2.8/src/hidapi/pc/hidapi-hidraw.pc.in create mode 100644 contrib/SDL-3.2.8/src/hidapi/pc/hidapi-libusb.pc.in create mode 100644 contrib/SDL-3.2.8/src/hidapi/pc/hidapi-netbsd.pc.in create mode 100644 contrib/SDL-3.2.8/src/hidapi/pc/hidapi.pc.in create mode 100644 contrib/SDL-3.2.8/src/hidapi/src/CMakeLists.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/src/cmake/hidapi-config.cmake.in create mode 100644 contrib/SDL-3.2.8/src/hidapi/subprojects/README.md create mode 100644 contrib/SDL-3.2.8/src/hidapi/subprojects/hidapi_build_cmake/CMakeLists.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/Makefile-manual create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/Makefile.am create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/Makefile.freebsd create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/Makefile.linux create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/Makefile.mac create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/Makefile.mingw create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/TestGUI.app.in/Contents/Info.plist create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/TestGUI.app.in/Contents/PkgInfo create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/TestGUI.app.in/Contents/Resources/English.lproj/InfoPlist.strings create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/TestGUI.app.in/Contents/Resources/Signal11.icns create mode 100755 contrib/SDL-3.2.8/src/hidapi/testgui/copy_to_bundle.sh create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/mac_support.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/mac_support_cocoa.m create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/test.cpp create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/testgui.sln create mode 100644 contrib/SDL-3.2.8/src/hidapi/testgui/testgui.vcproj create mode 100644 contrib/SDL-3.2.8/src/hidapi/udev/69-hid.rules create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/CMakeLists.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/Makefile-manual create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/Makefile.am create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/Makefile.mingw create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/hid.c create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/hidapi.rc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/hidapi.sln create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/hidapi.vcproj create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/hidapi.vcxproj create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/hidapi_cfgmgr32.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/hidapi_descriptor_reconstruct.c create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/hidapi_descriptor_reconstruct.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/hidapi_hidclass.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/hidapi_hidpi.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/hidapi_hidsdi.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/hidapi_winapi.h create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/hidtest.vcproj create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/hidtest.vcxproj create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/CMakeLists.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/README.md create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/pp_data_dump/pp_data_dump.c create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/CMakeLists.txt create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/045E_02FF_0005_0001.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/045E_02FF_0005_0001_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/045E_02FF_0005_0001_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046A_0011_0006_0001.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046A_0011_0006_0001_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046A_0011_0006_0001_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_0A37_0001_000C.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_0A37_0001_000C_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_0A37_0001_000C_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0001_000C.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0001_000C_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0001_000C_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0001_FF00.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0001_FF00_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0001_FF00_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0002_0001.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0002_0001_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0002_0001_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0002_FF00.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0002_FF00_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0002_FF00_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0006_0001.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0006_0001_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_B010_0006_0001_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C077_0002_0001.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C077_0002_0001_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C077_0002_0001_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C283_0004_0001.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C283_0004_0001_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C283_0004_0001_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C52F_0001_000C.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C52F_0001_000C_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C52F_0001_000C_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C52F_0001_FF00.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C52F_0001_FF00_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C52F_0001_FF00_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C52F_0002_0001.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C52F_0002_0001_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C52F_0002_0001_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C52F_0002_FF00.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C52F_0002_FF00_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C52F_0002_FF00_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0001_000C.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0001_000C_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0001_000C_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0001_FF00.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0001_FF00_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0001_FF00_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0002_0001.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0002_0001_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0002_0001_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0002_FF00.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0002_FF00_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0002_FF00_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0006_0001.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0006_0001_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0006_0001_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0080_0001.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0080_0001_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/046D_C534_0080_0001_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/047F_C056_0001_000C.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/047F_C056_0001_000C_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/047F_C056_0001_000C_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/047F_C056_0003_FFA0.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/047F_C056_0003_FFA0_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/047F_C056_0003_FFA0_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/047F_C056_0005_000B.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/047F_C056_0005_000B_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/047F_C056_0005_000B_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/17CC_1130_0000_FF01.pp_data create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/17CC_1130_0000_FF01_expected.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/data/17CC_1130_0000_FF01_real.rpt_desc create mode 100644 contrib/SDL-3.2.8/src/hidapi/windows/test/hid_report_reconstructor_test.c (limited to 'contrib/SDL-3.2.8/src/hidapi') diff --git a/contrib/SDL-3.2.8/src/hidapi/AUTHORS.txt b/contrib/SDL-3.2.8/src/hidapi/AUTHORS.txt new file mode 100644 index 0000000..7c2a035 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/AUTHORS.txt @@ -0,0 +1,18 @@ + +HIDAPI Authors: + +Alan Ott : + Original Author and Maintainer + Linux, Windows, and Mac implementations + +Ludovic Rousseau : + Formatting for Doxygen documentation + Bug fixes + Correctness fixes + +libusb/hidapi Team: + Development/maintenance since June 4th 2019 + +For a comprehensive list of contributions, see the commit list at github: + https://github.com/libusb/hidapi/graphs/contributors + diff --git a/contrib/SDL-3.2.8/src/hidapi/BUILD.autotools.md b/contrib/SDL-3.2.8/src/hidapi/BUILD.autotools.md new file mode 100644 index 0000000..24b20a5 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/BUILD.autotools.md @@ -0,0 +1,114 @@ +# Building HIDAPI using Autotools (deprecated) + +--- +**NOTE**: for all intentions and purposes the Autotools build scripts for HIDAPI are _deprecated_ and going to be obsolete in the future. +HIDAPI Team recommends using CMake build for HIDAPI. +If you are already using Autotools build scripts provided by HIDAPI, +consider switching to CMake build scripts as soon as possible. + +--- + +To be able to use Autotools to build HIDAPI, it has to be [installed](#installing-autotools)/available in the system. + +Make sure you've checked [prerequisites](BUILD.md#prerequisites) and installed all required dependencies. + +## Installing Autotools + +HIDAPI uses few specific tools/packages from Autotools: `autoconf`, `automake`, `libtool`. + +On different platforms or package managers, those could be named a bit differently or packaged together. +You'll have to check the documentation/package list for your specific package manager. + +### Linux + +On Ubuntu the tools are available via APT: + +```sh +sudo apt install autoconf automake libtool +``` + +### FreeBSD + +FreeBSD Autotools can be installed as: + +```sh +pkg_add -r autotools +``` + +Additionally, on FreeBSD you will need to install GNU make: +```sh +pkg_add -r gmake +``` + +## Building HIDAPI with Autotools + +A simple command list, to build HIDAPI with Autotools as a _shared library_ and install in into your system: + +```sh +./bootstrap # this prepares the configure script +./configure +make # build the library +make install # as root, or using sudo, this will install hidapi into your system +``` + +`./configure` can take several arguments which control the build. A few commonly used options: +```sh + --enable-testgui + # Enable the build of Foxit-based Test GUI. This requires Fox toolkit to + # be installed/available. See README.md#test-gui for remarks. + + --prefix=/usr + # Specify where you want the output headers and libraries to + # be installed. The example above will put the headers in + # /usr/include and the binaries in /usr/lib. The default is to + # install into /usr/local which is fine on most systems. + + --disable-shared + # By default, both shared and static libraries are going to be built/installed. + # This option disables shared library build, if only static library is required. +``` + + +## Cross Compiling + +This section talks about cross compiling HIDAPI for Linux using Autotools. +This is useful for using HIDAPI on embedded Linux targets. These +instructions assume the most raw kind of embedded Linux build, where all +prerequisites will need to be built first. This process will of course vary +based on your embedded Linux build system if you are using one, such as +OpenEmbedded or Buildroot. + +For the purpose of this section, it will be assumed that the following +environment variables are exported. +```sh +$ export STAGING=$HOME/out +$ export HOST=arm-linux +``` + +`STAGING` and `HOST` can be modified to suit your setup. + +### Prerequisites + +Depending on what backend you want to cross-compile, you also need to prepare the dependencies: +`libusb` for libusb HIDAPI backend, or `libudev` for hidraw HIDAPI backend. + +An example of cross-compiling `libusb`. From `libusb` source directory, run: +```sh +./configure --host=$HOST --prefix=$STAGING +make +make install +``` + +An example of cross-comping `libudev` is not covered by this section. +Check `libudev`'s documentation for details. + +### Building HIDAPI + +Build HIDAPI: +```sh +PKG_CONFIG_DIR= \ +PKG_CONFIG_LIBDIR=$STAGING/lib/pkgconfig:$STAGING/share/pkgconfig \ +PKG_CONFIG_SYSROOT_DIR=$STAGING \ +./configure --host=$HOST --prefix=$STAGING +# make / make install - same as for a regular build +``` diff --git a/contrib/SDL-3.2.8/src/hidapi/BUILD.cmake.md b/contrib/SDL-3.2.8/src/hidapi/BUILD.cmake.md new file mode 100644 index 0000000..573f910 --- /dev/null +++ b/contrib/SDL-3.2.8/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 preferred way to install CMake is via package manager, +e.g. `sudo apt install cmake`. + +On Windows CMake could be provided by your development environment (e.g. by Visual Studio Installer or MinGW installer), +or you may install it system-wise using the installer from the official website. + +On macOS CMake may be installed by Homebrew/MacPorts or using the installer from the official website. + +## Standalone package build + +To build HIDAPI as a standalone package, you follow [general steps](https://cmake.org/runningcmake/) of building any CMake project. + +An example of building HIDAPI with CMake: +```sh +# precondition: create a 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 +# configure the build +cmake +# 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=value`. +E.g.: +```sh +# install command now would install things into /usr +cmake -DCMAKE_INSTALL_PREFIX=/usr +``` + +
+ Using a specific CMake generator + +An example of using `Ninja` as a CMake generator: + +```sh +cd +# configure the build +cmake -GNinja +# 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). + +

+ +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; + +
+ macOS-specific variables + + - [`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; + +

+ +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; + +
+ Linux-specific variables + + - `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. + +

+ +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;
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=`. + +_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 `` 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...3.25 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) +``` + +
+ NOTE + + 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. +

+ +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")
+E.g.2:
+![an example of drop-down menu in cmake-gui](documentation/cmake-gui-drop-down.png "cmake-gui drop-down menu")
+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::include` 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 -B "/static" -DCMAKE_INSTALL_PREFIX= -DBUILD_SHARED_LIBS=FALSE +cmake --build "/static" +# Shared libraries +cmake -S -B "/shared" -DCMAKE_INSTALL_PREFIX= -DBUILD_SHARED_LIBS=TRUE +cmake --build "/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 "/static" +# Shared libraries +cmake --install "/shared" + +``` diff --git a/contrib/SDL-3.2.8/src/hidapi/BUILD.md b/contrib/SDL-3.2.8/src/hidapi/BUILD.md new file mode 100644 index 0000000..d7a3546 --- /dev/null +++ b/contrib/SDL-3.2.8/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).
+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.
+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 `/hid.c` and `hidapi/hidapi.h` is enough to build HIDAPI. +The only guarantee that `/hid.c` includes all necessary sources to compile it as a single file. + +Check the manual makefiles for a simple example/reference of what are the dependencies of each specific backend. + +## Building the manual way on Unix platforms + +Manual Makefiles are provided mostly to give the user an idea what it takes +to build a program which embeds HIDAPI directly inside of it. These should +really be used as examples only. If you want to build a system-wide shared +library, use one of the build systems mentioned above. + +To build HIDAPI using the manual Makefiles, change the directory +of your platform and run make. For example, on Linux run: +```sh +cd linux/ +make -f Makefile-manual +``` + +## Building on Windows + +To build the HIDAPI DLL on Windows using Visual Studio, build the `.sln` file +in the `windows/` directory. + +To build HIDAPI using MinGW or Cygwin using Autotools, use general Autotools + [instruction](BUILD.autotools.md). + +Any windows builds (MSVC or MinGW/Cygwin) are also supported by [CMake](BUILD.cmake.md). + +If you are looking for information regarding DDK build of HIDAPI: +- the build has been broken for a while and now the support files are obsolete. diff --git a/contrib/SDL-3.2.8/src/hidapi/CMakeLists.txt b/contrib/SDL-3.2.8/src/hidapi/CMakeLists.txt new file mode 100644 index 0000000..d708681 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/CMakeLists.txt @@ -0,0 +1,108 @@ +cmake_minimum_required(VERSION 3.1.3...3.25 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() + if(CMAKE_SYSTEM_NAME MATCHES "NetBSD") + option(HIDAPI_WITH_NETBSD "Build NetBSD/UHID implementation of HIDAPI" ON) + endif() +endif() + +option(BUILD_SHARED_LIBS "Build shared version of the libraries, otherwise build statically" ON) + +set(HIDAPI_INSTALL_TARGETS ON) +set(HIDAPI_PRINT_VERSION ON) + +set(IS_DEBUG_BUILD OFF) +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(IS_DEBUG_BUILD ON) +endif() + +option(HIDAPI_ENABLE_ASAN "Build HIDAPI with ASAN address sanitizer instrumentation" OFF) + +if(HIDAPI_ENABLE_ASAN) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") + if(MSVC) + # the default is to have "/INCREMENTAL" which causes a warning when "-fsanitize=address" is present + set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /INCREMENTAL:NO") + set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /INCREMENTAL:NO") + set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /INCREMENTAL:NO") + set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /INCREMENTAL:NO") + endif() +endif() + +if(WIN32) + # so far only Windows has tests + option(HIDAPI_WITH_TESTS "Build HIDAPI (unit-)tests" ${IS_DEBUG_BUILD}) +else() + set(HIDAPI_WITH_TESTS OFF) +endif() + +if(HIDAPI_WITH_TESTS) + enable_testing() +endif() + +if(WIN32) + option(HIDAPI_BUILD_PP_DATA_DUMP "Build small Windows console application pp_data_dump.exe" ${IS_DEBUG_BUILD}) +endif() + +add_subdirectory(src) + +option(HIDAPI_BUILD_HIDTEST "Build small console test application hidtest" ${IS_DEBUG_BUILD}) +if(HIDAPI_BUILD_HIDTEST) + add_subdirectory(hidtest) +endif() + +if(HIDAPI_ENABLE_ASAN) + if(NOT MSVC) + # MSVC doesn't recognize those options, other compilers - requiring it + foreach(HIDAPI_TARGET hidapi_winapi hidapi_darwin hidapi_hidraw hidapi_libusb hidtest_hidraw hidtest_libusb hidtest) + if(TARGET ${HIDAPI_TARGET}) + if(BUILD_SHARED_LIBS) + target_link_options(${HIDAPI_TARGET} PRIVATE -fsanitize=address) + else() + target_link_options(${HIDAPI_TARGET} PUBLIC -fsanitize=address) + endif() + endif() + endforeach() + endif() +endif() diff --git a/contrib/SDL-3.2.8/src/hidapi/HACKING.txt b/contrib/SDL-3.2.8/src/hidapi/HACKING.txt new file mode 100644 index 0000000..e06b533 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/HACKING.txt @@ -0,0 +1,19 @@ +This file is mostly for the maintainer. + +Updating a Version: +1. Update VERSION file. +2. HID_API_VERSION_MAJOR/HID_API_VERSION_MINOR/HID_API_VERSION_PATCH in hidapi.h. + +Before firing a new release: +1. Run the "Checks" Githtub Action +2. Make sure no defects are found at: https://scan.coverity.com/projects/hidapi +3. Fix if any + +Firing a new release: +1. Update the Version (if not yet updated). +2. Prepare the Release Notes. +3. Store the Release Notes into a file. +4. Create locally an annotated git tag with release notes attached, e.g.: `git tag -aF ../hidapi_release_notes hidapi-` +5. Push newly created tag: `git push origin hidapi-` +6. Grab the hidapi-win.zip from Summary page of "GitHub Builds" Action for latest master build. +7. Create a Github Release with hidapi-win.zip attached, for newly created tag. diff --git a/contrib/SDL-3.2.8/src/hidapi/LICENSE-bsd.txt b/contrib/SDL-3.2.8/src/hidapi/LICENSE-bsd.txt new file mode 100644 index 0000000..538cdf9 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/LICENSE-bsd.txt @@ -0,0 +1,26 @@ +Copyright (c) 2010, Alan Ott, Signal 11 Software +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Signal 11 Software nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/contrib/SDL-3.2.8/src/hidapi/LICENSE-gpl3.txt b/contrib/SDL-3.2.8/src/hidapi/LICENSE-gpl3.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/LICENSE-gpl3.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/contrib/SDL-3.2.8/src/hidapi/LICENSE-orig.txt b/contrib/SDL-3.2.8/src/hidapi/LICENSE-orig.txt new file mode 100644 index 0000000..e3f3380 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/LICENSE-orig.txt @@ -0,0 +1,9 @@ + HIDAPI - Multi-Platform library for + communication with HID devices. + + Copyright 2009, Alan Ott, Signal 11 Software. + All Rights Reserved. + + This software may be used by anyone for any reason so + long as the copyright notice in the source files + remains intact. diff --git a/contrib/SDL-3.2.8/src/hidapi/LICENSE.txt b/contrib/SDL-3.2.8/src/hidapi/LICENSE.txt new file mode 100644 index 0000000..e1676d4 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/LICENSE.txt @@ -0,0 +1,13 @@ +HIDAPI can be used under one of three licenses. + +1. The GNU General Public License, version 3.0, in LICENSE-gpl3.txt +2. A BSD-Style License, in LICENSE-bsd.txt. +3. The more liberal original HIDAPI license. LICENSE-orig.txt + +The license chosen is at the discretion of the user of HIDAPI. For example: +1. An author of GPL software would likely use HIDAPI under the terms of the +GPL. + +2. An author of commercial closed-source software would likely use HIDAPI +under the terms of the BSD-style license or the original HIDAPI license. + diff --git a/contrib/SDL-3.2.8/src/hidapi/Makefile.am b/contrib/SDL-3.2.8/src/hidapi/Makefile.am new file mode 100644 index 0000000..00bcb73 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/Makefile.am @@ -0,0 +1,85 @@ + +ACLOCAL_AMFLAGS = -I m4 + +if OS_FREEBSD +pkgconfigdir=$(prefix)/libdata/pkgconfig +else +pkgconfigdir=$(libdir)/pkgconfig +endif + +if OS_LINUX +pkgconfig_DATA=pc/hidapi-hidraw.pc pc/hidapi-libusb.pc +else +pkgconfig_DATA=pc/hidapi.pc +endif + +SUBDIRS= + +if OS_LINUX +SUBDIRS += linux libusb +endif + +if OS_DARWIN +SUBDIRS += mac +endif + +if OS_FREEBSD +SUBDIRS += libusb +endif + +if OS_KFREEBSD +SUBDIRS += libusb +endif + +if OS_HAIKU +SUBDIRS += libusb +endif + +if OS_WINDOWS +SUBDIRS += windows +endif + +SUBDIRS += hidtest + +if BUILD_TESTGUI +SUBDIRS += testgui +endif + +EXTRA_DIST = udev doxygen + +dist_doc_DATA = \ + README.md \ + AUTHORS.txt \ + LICENSE-bsd.txt \ + LICENSE-gpl3.txt \ + LICENSE-orig.txt \ + LICENSE.txt + +SCMCLEAN_TARGETS= \ + aclocal.m4 \ + config.guess \ + config.sub \ + configure \ + config.h.in \ + depcomp \ + install-sh \ + ltmain.sh \ + missing \ + mac/Makefile.in \ + testgui/Makefile.in \ + libusb/Makefile.in \ + Makefile.in \ + linux/Makefile.in \ + windows/Makefile.in \ + m4/libtool.m4 \ + m4/lt~obsolete.m4 \ + m4/ltoptions.m4 \ + m4/ltsugar.m4 \ + m4/ltversion.m4 + +SCMCLEAN_DIR_TARGETS = \ + autom4te.cache + +scm-clean: distclean + rm -f $(SCMCLEAN_TARGETS) + rm -Rf $(SCMCLEAN_DIR_TARGETS) diff --git a/contrib/SDL-3.2.8/src/hidapi/README.md b/contrib/SDL-3.2.8/src/hidapi/README.md new file mode 100644 index 0000000..257b9f3 --- /dev/null +++ b/contrib/SDL-3.2.8/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.
+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 . 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 // printf +#include // wchar_t + +#include + +#define MAX_STR 255 + +int main(int argc, char* argv[]) +{ + int res; + unsigned char buf[65]; + wchar_t wstr[MAX_STR]; + hid_device *handle; + int i; + + // Initialize the hidapi library + res = hid_init(); + + // Open the device using the VID, PID, + // and optionally the Serial number. + handle = hid_open(0x4d8, 0x3f, NULL); + if (!handle) { + printf("Unable to open device\n"); + hid_exit(); + return 1; + } + + // Read the Manufacturer String + res = hid_get_manufacturer_string(handle, wstr, MAX_STR); + printf("Manufacturer String: %ls\n", wstr); + + // Read the Product String + res = hid_get_product_string(handle, wstr, MAX_STR); + printf("Product String: %ls\n", wstr); + + // Read the Serial Number String + res = hid_get_serial_number_string(handle, wstr, MAX_STR); + printf("Serial Number String: (%d) %ls\n", wstr[0], wstr); + + // Read Indexed String 1 + res = hid_get_indexed_string(handle, 1, wstr, MAX_STR); + printf("Indexed String 1: %ls\n", wstr); + + // Toggle LED (cmd 0x80). The first byte is the report number (0x0). + buf[0] = 0x0; + buf[1] = 0x80; + res = hid_write(handle, buf, 65); + + // Request state (cmd 0x81). The first byte is the report number (0x0). + buf[0] = 0x0; + buf[1] = 0x81; + res = hid_write(handle, buf, 65); + + // Read requested state + res = hid_read(handle, buf, 65); + + // Print out the returned buffer. + for (i = 0; i < 4; i++) + printf("buf[%d]: %d\n", i, buf[i]); + + // Close the device + hid_close(handle); + + // Finalize the hidapi library + res = hid_exit(); + + return 0; +} +``` + +You can also use [hidtest/test.c](hidtest/test.c) +as a starting point for your applications. + + +## License + +HIDAPI may be used by one of three licenses as outlined in [LICENSE.txt](LICENSE.txt). + +## Installing HIDAPI + +If you want to build your own application that uses HID devices with HIDAPI, +you need to get HIDAPI development package. + +Depending on what your development environment is, HIDAPI likely to be provided +by your package manager. + +For instance on Ubuntu, HIDAPI is available via APT: +```sh +sudo apt install libhidapi-dev +``` + +HIDAPI package name for other systems/package managers may differ. +Check the documentation/package list of your package manager. + +## Build from Source + +Check [BUILD.md](BUILD.md) for details. diff --git a/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi.c b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi.c new file mode 100644 index 0000000..b14b75e --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi.c @@ -0,0 +1,1750 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + 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. +*/ + +/* Original hybrid wrapper for Linux by Valve Software. Their original notes: + * + * The libusb version doesn't support Bluetooth, but not all Linux + * distributions allow access to /dev/hidraw* + * + * This merges the two, at a small performance cost, until distributions + * have granted access to /dev/hidraw* + */ + +#include "SDL_internal.h" + +#include "SDL_hidapi_c.h" +#include "../joystick/usb_ids.h" +#include "../SDL_hints_c.h" + +// Initial type declarations +#define HID_API_NO_EXPORT_DEFINE // do not export hidapi procedures +#include "hidapi/hidapi.h" + +#ifndef SDL_HIDAPI_DISABLED + +#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) +#include "../core/windows/SDL_windows.h" +#endif + +#ifdef SDL_PLATFORM_MACOS +#include +#include +#include +#include +#include +#include +// Things named "Master" were renamed to "Main" in macOS 12.0's SDK. +#if MAC_OS_X_VERSION_MIN_REQUIRED < 120000 +#define kIOMainPortDefault kIOMasterPortDefault +#endif +#endif + +#include "../core/linux/SDL_udev.h" +#ifdef SDL_USE_LIBUDEV +#include +#endif + +#ifdef HAVE_INOTIFY +#include // strerror +#include // errno +#include +#include // For the definition of NAME_MAX +#include +#endif + +#if defined(SDL_USE_LIBUDEV) || defined(HAVE_INOTIFY) +#include +#endif + +#ifdef SDL_USE_LIBUDEV +typedef enum +{ + ENUMERATION_UNSET, + ENUMERATION_LIBUDEV, + ENUMERATION_FALLBACK +} LinuxEnumerationMethod; + +static LinuxEnumerationMethod linux_enumeration_method = ENUMERATION_UNSET; +#endif + +#ifdef HAVE_INOTIFY +static int inotify_fd = -1; +#endif + +#ifdef SDL_USE_LIBUDEV +static const SDL_UDEV_Symbols *usyms = NULL; +#endif + +static struct +{ + bool m_bInitialized; + Uint32 m_unDeviceChangeCounter; + bool m_bCanGetNotifications; + Uint64 m_unLastDetect; + +#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) + SDL_ThreadID m_nThreadID; + WNDCLASSEXA m_wndClass; + HWND m_hwndMsg; + HDEVNOTIFY m_hNotify; + double m_flLastWin32MessageCheck; +#endif + +#ifdef SDL_PLATFORM_MACOS + IONotificationPortRef m_notificationPort; + mach_port_t m_notificationMach; +#endif + +#ifdef SDL_USE_LIBUDEV + struct udev *m_pUdev; + struct udev_monitor *m_pUdevMonitor; + int m_nUdevFd; +#endif +} SDL_HIDAPI_discovery; + +#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) +struct _DEV_BROADCAST_HDR +{ + DWORD dbch_size; + DWORD dbch_devicetype; + DWORD dbch_reserved; +}; + +typedef struct _DEV_BROADCAST_DEVICEINTERFACE_A +{ + DWORD dbcc_size; + DWORD dbcc_devicetype; + DWORD dbcc_reserved; + GUID dbcc_classguid; + char dbcc_name[1]; +} DEV_BROADCAST_DEVICEINTERFACE_A, *PDEV_BROADCAST_DEVICEINTERFACE_A; + +typedef struct _DEV_BROADCAST_HDR DEV_BROADCAST_HDR; +#define DBT_DEVICEARRIVAL 0x8000 // system detected a new device +#define DBT_DEVICEREMOVECOMPLETE 0x8004 // device was removed from the system +#define DBT_DEVTYP_DEVICEINTERFACE 0x00000005 // device interface class +#define DBT_DEVNODES_CHANGED 0x0007 +#define DBT_CONFIGCHANGED 0x0018 +#define DBT_DEVICETYPESPECIFIC 0x8005 // type specific event +#define DBT_DEVINSTSTARTED 0x8008 // device installed and started + +#include +DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED); + +static LRESULT CALLBACK ControllerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_DEVICECHANGE: + switch (wParam) { + case DBT_DEVICEARRIVAL: + case DBT_DEVICEREMOVECOMPLETE: + if (((DEV_BROADCAST_HDR *)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) { + ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter; + } + break; + } + return TRUE; + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} +#endif // defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) + +#ifdef SDL_PLATFORM_MACOS +static void CallbackIOServiceFunc(void *context, io_iterator_t portIterator) +{ + // Must drain the iterator, or we won't receive new notifications + io_object_t entry; + while ((entry = IOIteratorNext(portIterator)) != 0) { + IOObjectRelease(entry); + ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter; + } +} +#endif // SDL_PLATFORM_MACOS + +#ifdef HAVE_INOTIFY +#ifdef HAVE_INOTIFY_INIT1 +static int SDL_inotify_init1(void) +{ + return inotify_init1(IN_NONBLOCK | IN_CLOEXEC); +} +#else +static int SDL_inotify_init1(void) +{ + int fd = inotify_init(); + if (fd < 0) { + return -1; + } + fcntl(fd, F_SETFL, O_NONBLOCK); + fcntl(fd, F_SETFD, FD_CLOEXEC); + return fd; +} +#endif + +static int StrHasPrefix(const char *string, const char *prefix) +{ + return SDL_strncmp(string, prefix, SDL_strlen(prefix)) == 0; +} + +static int StrIsInteger(const char *string) +{ + const char *p; + + if (*string == '\0') { + return 0; + } + + for (p = string; *p != '\0'; p++) { + if (*p < '0' || *p > '9') { + return 0; + } + } + + return 1; +} +#endif // HAVE_INOTIFY + +static void HIDAPI_InitializeDiscovery(void) +{ + SDL_HIDAPI_discovery.m_bInitialized = true; + SDL_HIDAPI_discovery.m_unDeviceChangeCounter = 1; + SDL_HIDAPI_discovery.m_bCanGetNotifications = false; + SDL_HIDAPI_discovery.m_unLastDetect = 0; + +#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) + SDL_HIDAPI_discovery.m_nThreadID = SDL_GetCurrentThreadID(); + + SDL_zero(SDL_HIDAPI_discovery.m_wndClass); + SDL_HIDAPI_discovery.m_wndClass.hInstance = GetModuleHandle(NULL); + SDL_HIDAPI_discovery.m_wndClass.lpszClassName = "SDL_HIDAPI_DEVICE_DETECTION"; + SDL_HIDAPI_discovery.m_wndClass.lpfnWndProc = ControllerWndProc; // This function is called by windows + SDL_HIDAPI_discovery.m_wndClass.cbSize = sizeof(WNDCLASSEX); + + RegisterClassExA(&SDL_HIDAPI_discovery.m_wndClass); + SDL_HIDAPI_discovery.m_hwndMsg = CreateWindowExA(0, "SDL_HIDAPI_DEVICE_DETECTION", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); + + { + DEV_BROADCAST_DEVICEINTERFACE_A devBroadcast; + + SDL_zero(devBroadcast); + devBroadcast.dbcc_size = sizeof(devBroadcast); + devBroadcast.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + devBroadcast.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE; + + /* DEVICE_NOTIFY_ALL_INTERFACE_CLASSES is important, makes GUID_DEVINTERFACE_USB_DEVICE ignored, + * but that seems to be necessary to get a notice after each individual usb input device actually + * installs, rather than just as the composite device is seen. + */ + SDL_HIDAPI_discovery.m_hNotify = RegisterDeviceNotification(SDL_HIDAPI_discovery.m_hwndMsg, &devBroadcast, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES); + SDL_HIDAPI_discovery.m_bCanGetNotifications = (SDL_HIDAPI_discovery.m_hNotify != 0); + } +#endif // defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) + +#ifdef SDL_PLATFORM_MACOS + SDL_HIDAPI_discovery.m_notificationPort = IONotificationPortCreate(kIOMainPortDefault); + if (SDL_HIDAPI_discovery.m_notificationPort) { + { + io_iterator_t portIterator = 0; + io_object_t entry; + IOReturn result = IOServiceAddMatchingNotification( + SDL_HIDAPI_discovery.m_notificationPort, + kIOFirstMatchNotification, + IOServiceMatching(kIOHIDDeviceKey), + CallbackIOServiceFunc, NULL, &portIterator); + + if (result == 0) { + // Must drain the existing iterator, or we won't receive new notifications + while ((entry = IOIteratorNext(portIterator)) != 0) { + IOObjectRelease(entry); + } + } else { + IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort); + SDL_HIDAPI_discovery.m_notificationPort = nil; + } + } + { + io_iterator_t portIterator = 0; + io_object_t entry; + IOReturn result = IOServiceAddMatchingNotification( + SDL_HIDAPI_discovery.m_notificationPort, + kIOTerminatedNotification, + IOServiceMatching(kIOHIDDeviceKey), + CallbackIOServiceFunc, NULL, &portIterator); + + if (result == 0) { + // Must drain the existing iterator, or we won't receive new notifications + while ((entry = IOIteratorNext(portIterator)) != 0) { + IOObjectRelease(entry); + } + } else { + IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort); + SDL_HIDAPI_discovery.m_notificationPort = nil; + } + } + } + + SDL_HIDAPI_discovery.m_notificationMach = MACH_PORT_NULL; + if (SDL_HIDAPI_discovery.m_notificationPort) { + SDL_HIDAPI_discovery.m_notificationMach = IONotificationPortGetMachPort(SDL_HIDAPI_discovery.m_notificationPort); + } + + SDL_HIDAPI_discovery.m_bCanGetNotifications = (SDL_HIDAPI_discovery.m_notificationMach != MACH_PORT_NULL); + +#endif // SDL_PLATFORM_MACOS + +#ifdef SDL_USE_LIBUDEV + if (linux_enumeration_method == ENUMERATION_LIBUDEV) { + SDL_HIDAPI_discovery.m_pUdev = NULL; + SDL_HIDAPI_discovery.m_pUdevMonitor = NULL; + SDL_HIDAPI_discovery.m_nUdevFd = -1; + + usyms = SDL_UDEV_GetUdevSyms(); + if (usyms != NULL) { + SDL_HIDAPI_discovery.m_pUdev = usyms->udev_new(); + if (SDL_HIDAPI_discovery.m_pUdev != NULL) { + SDL_HIDAPI_discovery.m_pUdevMonitor = usyms->udev_monitor_new_from_netlink(SDL_HIDAPI_discovery.m_pUdev, "udev"); + if (SDL_HIDAPI_discovery.m_pUdevMonitor != NULL) { + usyms->udev_monitor_enable_receiving(SDL_HIDAPI_discovery.m_pUdevMonitor); + SDL_HIDAPI_discovery.m_nUdevFd = usyms->udev_monitor_get_fd(SDL_HIDAPI_discovery.m_pUdevMonitor); + SDL_HIDAPI_discovery.m_bCanGetNotifications = true; + } + } + } + } else +#endif // SDL_USE_LIBUDEV + { +#ifdef HAVE_INOTIFY + inotify_fd = SDL_inotify_init1(); + + if (inotify_fd < 0) { + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, + "Unable to initialize inotify, falling back to polling: %s", + strerror(errno)); + return; + } + + /* We need to watch for attribute changes in addition to + * creation, because when a device is first created, it has + * permissions that we can't read. When udev chmods it to + * something that we maybe *can* read, we'll get an + * IN_ATTRIB event to tell us. */ + if (inotify_add_watch(inotify_fd, "/dev", + IN_CREATE | IN_DELETE | IN_MOVE | IN_ATTRIB) < 0) { + close(inotify_fd); + inotify_fd = -1; + SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, + "Unable to add inotify watch, falling back to polling: %s", + strerror(errno)); + return; + } + + SDL_HIDAPI_discovery.m_bCanGetNotifications = true; +#endif // HAVE_INOTIFY + } +} + +static void HIDAPI_UpdateDiscovery(void) +{ + if (!SDL_HIDAPI_discovery.m_bInitialized) { + HIDAPI_InitializeDiscovery(); + } + + if (!SDL_HIDAPI_discovery.m_bCanGetNotifications) { + const Uint32 SDL_HIDAPI_DETECT_INTERVAL_MS = 3000; // Update every 3 seconds + Uint64 now = SDL_GetTicks(); + if (!SDL_HIDAPI_discovery.m_unLastDetect || now >= (SDL_HIDAPI_discovery.m_unLastDetect + SDL_HIDAPI_DETECT_INTERVAL_MS)) { + ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter; + SDL_HIDAPI_discovery.m_unLastDetect = now; + } + return; + } + +#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) +#if 0 // just let the usual SDL_PumpEvents loop dispatch these, fixing bug 4286. --ryan. + // We'll only get messages on the same thread that created the window + if (SDL_GetCurrentThreadID() == SDL_HIDAPI_discovery.m_nThreadID) { + MSG msg; + while (PeekMessage(&msg, SDL_HIDAPI_discovery.m_hwndMsg, 0, 0, PM_NOREMOVE)) { + if (GetMessageA(&msg, SDL_HIDAPI_discovery.m_hwndMsg, 0, 0) != 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + } +#endif +#endif // defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) + +#ifdef SDL_PLATFORM_MACOS + if (SDL_HIDAPI_discovery.m_notificationPort) { + struct + { + mach_msg_header_t hdr; + char payload[4096]; + } msg; + while (mach_msg(&msg.hdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, sizeof(msg), SDL_HIDAPI_discovery.m_notificationMach, 0, MACH_PORT_NULL) == KERN_SUCCESS) { + IODispatchCalloutFromMessage(NULL, &msg.hdr, SDL_HIDAPI_discovery.m_notificationPort); + } + } +#endif + +#ifdef SDL_USE_LIBUDEV + if (linux_enumeration_method == ENUMERATION_LIBUDEV) { + if (SDL_HIDAPI_discovery.m_nUdevFd >= 0) { + /* Drain all notification events. + * We don't expect a lot of device notifications so just + * do a new discovery on any kind or number of notifications. + * This could be made more restrictive if necessary. + */ + for (;;) { + struct pollfd PollUdev; + struct udev_device *pUdevDevice; + + PollUdev.fd = SDL_HIDAPI_discovery.m_nUdevFd; + PollUdev.events = POLLIN; + if (poll(&PollUdev, 1, 0) != 1) { + break; + } + + pUdevDevice = usyms->udev_monitor_receive_device(SDL_HIDAPI_discovery.m_pUdevMonitor); + if (pUdevDevice) { + const char *action = NULL; + action = usyms->udev_device_get_action(pUdevDevice); + if (action == NULL || SDL_strcmp(action, "add") == 0 || SDL_strcmp(action, "remove") == 0) { + ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter; + } + usyms->udev_device_unref(pUdevDevice); + } + } + } + } else +#endif // SDL_USE_LIBUDEV + { +#ifdef HAVE_INOTIFY + if (inotify_fd >= 0) { + union + { + struct inotify_event event; + char storage[4096]; + char enough_for_inotify[sizeof(struct inotify_event) + NAME_MAX + 1]; + } buf; + ssize_t bytes; + size_t remain = 0; + size_t len; + + bytes = read(inotify_fd, &buf, sizeof(buf)); + + if (bytes > 0) { + remain = (size_t)bytes; + } + + while (remain > 0) { + if (buf.event.len > 0) { + if (StrHasPrefix(buf.event.name, "hidraw") && + StrIsInteger(buf.event.name + SDL_strlen("hidraw"))) { + ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter; + /* We found an hidraw change. We still continue to + * drain the inotify fd to avoid leaving old + * notifications in the queue. */ + } + } + + len = sizeof(struct inotify_event) + buf.event.len; + remain -= len; + + if (remain != 0) { + SDL_memmove(&buf.storage[0], &buf.storage[len], remain); + } + } + } +#endif // HAVE_INOTIFY + } +} + +static void HIDAPI_ShutdownDiscovery(void) +{ + if (!SDL_HIDAPI_discovery.m_bInitialized) { + return; + } + +#if defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) + if (SDL_HIDAPI_discovery.m_hNotify) { + UnregisterDeviceNotification(SDL_HIDAPI_discovery.m_hNotify); + } + + if (SDL_HIDAPI_discovery.m_hwndMsg) { + DestroyWindow(SDL_HIDAPI_discovery.m_hwndMsg); + } + + UnregisterClassA(SDL_HIDAPI_discovery.m_wndClass.lpszClassName, SDL_HIDAPI_discovery.m_wndClass.hInstance); +#endif + +#ifdef SDL_PLATFORM_MACOS + if (SDL_HIDAPI_discovery.m_notificationPort) { + IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort); + } +#endif + +#ifdef SDL_USE_LIBUDEV + if (linux_enumeration_method == ENUMERATION_LIBUDEV) { + if (usyms) { + if (SDL_HIDAPI_discovery.m_pUdevMonitor) { + usyms->udev_monitor_unref(SDL_HIDAPI_discovery.m_pUdevMonitor); + } + if (SDL_HIDAPI_discovery.m_pUdev) { + usyms->udev_unref(SDL_HIDAPI_discovery.m_pUdev); + } + SDL_UDEV_ReleaseUdevSyms(); + usyms = NULL; + } + } else +#endif // SDL_USE_LIBUDEV + { +#ifdef HAVE_INOTIFY + if (inotify_fd >= 0) { + close(inotify_fd); + inotify_fd = -1; + } +#endif + } + + SDL_HIDAPI_discovery.m_bInitialized = false; +} + +// Platform HIDAPI Implementation + +#define HIDAPI_USING_SDL_RUNTIME +#define HIDAPI_IGNORE_DEVICE(BUS, VID, PID, USAGE_PAGE, USAGE) \ + SDL_HIDAPI_ShouldIgnoreDevice(BUS, VID, PID, USAGE_PAGE, USAGE) + +struct PLATFORM_hid_device_; +typedef struct PLATFORM_hid_device_ PLATFORM_hid_device; + +#define api_version PLATFORM_api_version +#define create_device_info_for_device PLATFORM_create_device_info_for_device +#define free_hid_device PLATFORM_free_hid_device +#define hid_close PLATFORM_hid_close +#define hid_device PLATFORM_hid_device +#define hid_device_ PLATFORM_hid_device_ +#define hid_enumerate PLATFORM_hid_enumerate +#define hid_error PLATFORM_hid_error +#define hid_exit PLATFORM_hid_exit +#define hid_free_enumeration PLATFORM_hid_free_enumeration +#define hid_get_device_info PLATFORM_hid_get_device_info +#define hid_get_feature_report PLATFORM_hid_get_feature_report +#define hid_get_indexed_string PLATFORM_hid_get_indexed_string +#define hid_get_input_report PLATFORM_hid_get_input_report +#define hid_get_manufacturer_string PLATFORM_hid_get_manufacturer_string +#define hid_get_product_string PLATFORM_hid_get_product_string +#define hid_get_report_descriptor PLATFORM_hid_get_report_descriptor +#define hid_get_serial_number_string PLATFORM_hid_get_serial_number_string +#define hid_init PLATFORM_hid_init +#define hid_open_path PLATFORM_hid_open_path +#define hid_open PLATFORM_hid_open +#define hid_read PLATFORM_hid_read +#define hid_read_timeout PLATFORM_hid_read_timeout +#define hid_send_feature_report PLATFORM_hid_send_feature_report +#define hid_set_nonblocking PLATFORM_hid_set_nonblocking +#define hid_version PLATFORM_hid_version +#define hid_version_str PLATFORM_hid_version_str +#define hid_write PLATFORM_hid_write +#define input_report PLATFORM_input_report +#define make_path PLATFORM_make_path +#define new_hid_device PLATFORM_new_hid_device +#define read_thread PLATFORM_read_thread +#define return_data PLATFORM_return_data + +#ifdef SDL_PLATFORM_LINUX +#include "SDL_hidapi_linux.h" +#elif defined(SDL_PLATFORM_NETBSD) +#include "SDL_hidapi_netbsd.h" +#elif defined(SDL_PLATFORM_MACOS) +#include "SDL_hidapi_mac.h" +#elif defined(SDL_PLATFORM_WIN32) || defined(SDL_PLATFORM_WINGDK) +#include "SDL_hidapi_windows.h" +#elif defined(SDL_PLATFORM_ANDROID) +#include "SDL_hidapi_android.h" +#elif defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS) +#include "SDL_hidapi_ios.h" +#endif + +#undef api_version +#undef create_device_info_for_device +#undef free_hid_device +#undef hid_close +#undef hid_device +#undef hid_device_ +#undef hid_enumerate +#undef hid_error +#undef hid_exit +#undef hid_free_enumeration +#undef hid_get_device_info +#undef hid_get_feature_report +#undef hid_get_indexed_string +#undef hid_get_input_report +#undef hid_get_manufacturer_string +#undef hid_get_product_string +#undef hid_get_report_descriptor +#undef hid_get_serial_number_string +#undef hid_init +#undef hid_open +#undef hid_open_path +#undef hid_read +#undef hid_read_timeout +#undef hid_send_feature_report +#undef hid_set_nonblocking +#undef hid_version +#undef hid_version_str +#undef hid_write +#undef input_report +#undef make_path +#undef new_hid_device +#undef read_thread +#undef return_data + +#ifdef SDL_JOYSTICK_HIDAPI_STEAMXBOX +#define HAVE_DRIVER_BACKEND 1 +#endif + +#ifdef HAVE_DRIVER_BACKEND + +// DRIVER HIDAPI Implementation + +struct DRIVER_hid_device_; +typedef struct DRIVER_hid_device_ DRIVER_hid_device; + +#define hid_close DRIVER_hid_close +#define hid_device DRIVER_hid_device +#define hid_device_ DRIVER_hid_device_ +#define hid_enumerate DRIVER_hid_enumerate +#define hid_error DRIVER_hid_error +#define hid_exit DRIVER_hid_exit +#define hid_free_enumeration DRIVER_hid_free_enumeration +#define hid_get_device_info DRIVER_hid_get_device_info +#define hid_get_feature_report DRIVER_hid_get_feature_report +#define hid_get_indexed_string DRIVER_hid_get_indexed_string +#define hid_get_input_report DRIVER_hid_get_input_report +#define hid_get_manufacturer_string DRIVER_hid_get_manufacturer_string +#define hid_get_product_string DRIVER_hid_get_product_string +#define hid_get_report_descriptor DRIVER_hid_get_report_descriptor +#define hid_get_serial_number_string DRIVER_hid_get_serial_number_string +#define hid_init DRIVER_hid_init +#define hid_open DRIVER_hid_open +#define hid_open_path DRIVER_hid_open_path +#define hid_read DRIVER_hid_read +#define hid_read_timeout DRIVER_hid_read_timeout +#define hid_send_feature_report DRIVER_hid_send_feature_report +#define hid_set_nonblocking DRIVER_hid_set_nonblocking +#define hid_write DRIVER_hid_write + +#ifdef SDL_JOYSTICK_HIDAPI_STEAMXBOX +#include "SDL_hidapi_steamxbox.h" +#else +#error Need a driver hid.c for this platform! +#endif + +#undef hid_close +#undef hid_device +#undef hid_device_ +#undef hid_enumerate +#undef hid_error +#undef hid_exit +#undef hid_free_enumeration +#undef hid_get_device_info +#undef hid_get_feature_report +#undef hid_get_indexed_string +#undef hid_get_input_report +#undef hid_get_manufacturer_string +#undef hid_get_product_string +#undef hid_get_report_descriptor +#undef hid_get_serial_number_string +#undef hid_init +#undef hid_open +#undef hid_open_path +#undef hid_read +#undef hid_read_timeout +#undef hid_send_feature_report +#undef hid_set_nonblocking +#undef hid_write + +#endif // HAVE_DRIVER_BACKEND + +#ifdef HAVE_LIBUSB +// libusb HIDAPI Implementation + +// Include this now, for our dynamically-loaded libusb context +#include + +static struct +{ + SDL_SharedObject *libhandle; + + /* *INDENT-OFF* */ // clang-format off + int (LIBUSB_CALL *init)(libusb_context **ctx); + void (LIBUSB_CALL *exit)(libusb_context *ctx); + ssize_t (LIBUSB_CALL *get_device_list)(libusb_context *ctx, libusb_device ***list); + void (LIBUSB_CALL *free_device_list)(libusb_device **list, int unref_devices); + int (LIBUSB_CALL *get_device_descriptor)(libusb_device *dev, struct libusb_device_descriptor *desc); + int (LIBUSB_CALL *get_active_config_descriptor)(libusb_device *dev, struct libusb_config_descriptor **config); + int (LIBUSB_CALL *get_config_descriptor)( + libusb_device *dev, + uint8_t config_index, + struct libusb_config_descriptor **config + ); + void (LIBUSB_CALL *free_config_descriptor)(struct libusb_config_descriptor *config); + uint8_t (LIBUSB_CALL *get_bus_number)(libusb_device *dev); + int (LIBUSB_CALL *get_port_numbers)(libusb_device *dev, uint8_t *port_numbers, int port_numbers_len); + uint8_t (LIBUSB_CALL *get_device_address)(libusb_device *dev); + int (LIBUSB_CALL *open)(libusb_device *dev, libusb_device_handle **dev_handle); + void (LIBUSB_CALL *close)(libusb_device_handle *dev_handle); + libusb_device *(LIBUSB_CALL *get_device)(libusb_device_handle *dev_handle); + int (LIBUSB_CALL *claim_interface)(libusb_device_handle *dev_handle, int interface_number); + int (LIBUSB_CALL *release_interface)(libusb_device_handle *dev_handle, int interface_number); + int (LIBUSB_CALL *kernel_driver_active)(libusb_device_handle *dev_handle, int interface_number); + int (LIBUSB_CALL *detach_kernel_driver)(libusb_device_handle *dev_handle, int interface_number); + int (LIBUSB_CALL *attach_kernel_driver)(libusb_device_handle *dev_handle, int interface_number); + int (LIBUSB_CALL *set_interface_alt_setting)(libusb_device_handle *dev, int interface_number, int alternate_setting); + struct libusb_transfer * (LIBUSB_CALL *alloc_transfer)(int iso_packets); + int (LIBUSB_CALL *submit_transfer)(struct libusb_transfer *transfer); + int (LIBUSB_CALL *cancel_transfer)(struct libusb_transfer *transfer); + void (LIBUSB_CALL *free_transfer)(struct libusb_transfer *transfer); + int (LIBUSB_CALL *control_transfer)( + libusb_device_handle *dev_handle, + uint8_t request_type, + uint8_t bRequest, + uint16_t wValue, + uint16_t wIndex, + unsigned char *data, + uint16_t wLength, + unsigned int timeout + ); + int (LIBUSB_CALL *interrupt_transfer)( + libusb_device_handle *dev_handle, + unsigned char endpoint, + unsigned char *data, + int length, + int *actual_length, + unsigned int timeout + ); + int (LIBUSB_CALL *handle_events)(libusb_context *ctx); + int (LIBUSB_CALL *handle_events_completed)(libusb_context *ctx, int *completed); + const char * (LIBUSB_CALL *error_name)(int errcode); +/* *INDENT-ON* */ // clang-format on + +} libusb_ctx; + +#define libusb_init libusb_ctx.init +#define libusb_exit libusb_ctx.exit +#define libusb_get_device_list libusb_ctx.get_device_list +#define libusb_free_device_list libusb_ctx.free_device_list +#define libusb_get_device_descriptor libusb_ctx.get_device_descriptor +#define libusb_get_active_config_descriptor libusb_ctx.get_active_config_descriptor +#define libusb_get_config_descriptor libusb_ctx.get_config_descriptor +#define libusb_free_config_descriptor libusb_ctx.free_config_descriptor +#define libusb_get_bus_number libusb_ctx.get_bus_number +#define libusb_get_port_numbers libusb_ctx.get_port_numbers +#define libusb_get_device_address libusb_ctx.get_device_address +#define libusb_open libusb_ctx.open +#define libusb_close libusb_ctx.close +#define libusb_get_device libusb_ctx.get_device +#define libusb_claim_interface libusb_ctx.claim_interface +#define libusb_release_interface libusb_ctx.release_interface +#define libusb_kernel_driver_active libusb_ctx.kernel_driver_active +#define libusb_detach_kernel_driver libusb_ctx.detach_kernel_driver +#define libusb_attach_kernel_driver libusb_ctx.attach_kernel_driver +#define libusb_set_interface_alt_setting libusb_ctx.set_interface_alt_setting +#define libusb_alloc_transfer libusb_ctx.alloc_transfer +#define libusb_submit_transfer libusb_ctx.submit_transfer +#define libusb_cancel_transfer libusb_ctx.cancel_transfer +#define libusb_free_transfer libusb_ctx.free_transfer +#define libusb_control_transfer libusb_ctx.control_transfer +#define libusb_interrupt_transfer libusb_ctx.interrupt_transfer +#define libusb_handle_events libusb_ctx.handle_events +#define libusb_handle_events_completed libusb_ctx.handle_events_completed +#define libusb_error_name libusb_ctx.error_name + +struct LIBUSB_hid_device_; +typedef struct LIBUSB_hid_device_ LIBUSB_hid_device; + +#define free_hid_device LIBUSB_free_hid_device +#define hid_close LIBUSB_hid_close +#define hid_device LIBUSB_hid_device +#define hid_device_ LIBUSB_hid_device_ +#define hid_enumerate LIBUSB_hid_enumerate +#define hid_error LIBUSB_hid_error +#define hid_exit LIBUSB_hid_exit +#define hid_free_enumeration LIBUSB_hid_free_enumeration +#define hid_get_device_info LIBUSB_hid_get_device_info +#define hid_get_feature_report LIBUSB_hid_get_feature_report +#define hid_get_indexed_string LIBUSB_hid_get_indexed_string +#define hid_get_input_report LIBUSB_hid_get_input_report +#define hid_get_manufacturer_string LIBUSB_hid_get_manufacturer_string +#define hid_get_product_string LIBUSB_hid_get_product_string +#define hid_get_report_descriptor LIBUSB_hid_get_report_descriptor +#define hid_get_serial_number_string LIBUSB_hid_get_serial_number_string +#define hid_init LIBUSB_hid_init +#define hid_open LIBUSB_hid_open +#define hid_open_path LIBUSB_hid_open_path +#define hid_read LIBUSB_hid_read +#define hid_read_timeout LIBUSB_hid_read_timeout +#define hid_send_feature_report LIBUSB_hid_send_feature_report +#define hid_set_nonblocking LIBUSB_hid_set_nonblocking +#define hid_write LIBUSB_hid_write +#define input_report LIBUSB_input_report +#define make_path LIBUSB_make_path +#define new_hid_device LIBUSB_new_hid_device +#define read_thread LIBUSB_read_thread +#define return_data LIBUSB_return_data + +#include "SDL_hidapi_libusb.h" + +#undef libusb_init +#undef libusb_exit +#undef libusb_get_device_list +#undef libusb_free_device_list +#undef libusb_get_device_descriptor +#undef libusb_get_active_config_descriptor +#undef libusb_get_config_descriptor +#undef libusb_free_config_descriptor +#undef libusb_get_bus_number +#undef libusb_get_port_numbers +#undef libusb_get_device_address +#undef libusb_open +#undef libusb_close +#undef libusb_get_device +#undef libusb_claim_interface +#undef libusb_release_interface +#undef libusb_kernel_driver_active +#undef libusb_detach_kernel_driver +#undef libusb_attach_kernel_driver +#undef libusb_set_interface_alt_setting +#undef libusb_alloc_transfer +#undef libusb_submit_transfer +#undef libusb_cancel_transfer +#undef libusb_free_transfer +#undef libusb_control_transfer +#undef libusb_interrupt_transfer +#undef libusb_handle_events +#undef libusb_handle_events_completed +#undef libusb_error_name + +#undef free_hid_device +#undef hid_close +#undef hid_device +#undef hid_device_ +#undef hid_enumerate +#undef hid_error +#undef hid_exit +#undef hid_free_enumeration +#undef hid_get_device_info +#undef hid_get_feature_report +#undef hid_get_indexed_string +#undef hid_get_input_report +#undef hid_get_manufacturer_string +#undef hid_get_product_string +#undef hid_get_report_descriptor +#undef hid_get_serial_number_string +#undef hid_init +#undef hid_open +#undef hid_open_path +#undef hid_read +#undef hid_read_timeout +#undef hid_send_feature_report +#undef hid_set_nonblocking +#undef hid_write +#undef input_report +#undef make_path +#undef new_hid_device +#undef read_thread +#undef return_data + +/* If the platform has any backend other than libusb, try to avoid using + * libusb as the main backend for devices, since it detaches drivers and + * therefore makes devices inaccessible to the rest of the OS. + * + * We do this by whitelisting devices we know to be accessible _exclusively_ + * via libusb; these are typically devices that look like HIDs but have a + * quirk that requires direct access to the hardware. + */ +static const struct { + Uint16 vendor; + Uint16 product; +} SDL_libusb_whitelist[] = { + { 0x057e, 0x0337 } // Nintendo WUP-028, Wii U/Switch GameCube Adapter +}; + +static bool IsInWhitelist(Uint16 vendor, Uint16 product) +{ + int i; + for (i = 0; i < SDL_arraysize(SDL_libusb_whitelist); i += 1) { + if (vendor == SDL_libusb_whitelist[i].vendor && + product == SDL_libusb_whitelist[i].product) { + return true; + } + } + return false; +} + +#endif // HAVE_LIBUSB + +#endif // !SDL_HIDAPI_DISABLED + +#if defined(HAVE_PLATFORM_BACKEND) || defined(HAVE_DRIVER_BACKEND) +// We have another way to get HID devices, so use the whitelist to get devices where libusb is preferred +#define SDL_HINT_HIDAPI_LIBUSB_WHITELIST_DEFAULT true +#else +// libusb is the only way to get HID devices, so don't use the whitelist, get them all +#define SDL_HINT_HIDAPI_LIBUSB_WHITELIST_DEFAULT false +#endif // HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND + +static bool use_libusb_whitelist = SDL_HINT_HIDAPI_LIBUSB_WHITELIST_DEFAULT; + +// Shared HIDAPI Implementation + +struct hidapi_backend +{ + int (*hid_write)(void *device, const unsigned char *data, size_t length); + int (*hid_read_timeout)(void *device, unsigned char *data, size_t length, int milliseconds); + int (*hid_read)(void *device, unsigned char *data, size_t length); + int (*hid_set_nonblocking)(void *device, int nonblock); + int (*hid_send_feature_report)(void *device, const unsigned char *data, size_t length); + int (*hid_get_feature_report)(void *device, unsigned char *data, size_t length); + int (*hid_get_input_report)(void *device, unsigned char *data, size_t length); + void (*hid_close)(void *device); + int (*hid_get_manufacturer_string)(void *device, wchar_t *string, size_t maxlen); + int (*hid_get_product_string)(void *device, wchar_t *string, size_t maxlen); + int (*hid_get_serial_number_string)(void *device, wchar_t *string, size_t maxlen); + int (*hid_get_indexed_string)(void *device, int string_index, wchar_t *string, size_t maxlen); + struct hid_device_info *(*hid_get_device_info)(void *device); + int (*hid_get_report_descriptor)(void *device, unsigned char *buf, size_t buf_size); + const wchar_t *(*hid_error)(void *device); +}; + +#ifdef HAVE_PLATFORM_BACKEND +static const struct hidapi_backend PLATFORM_Backend = { + (void *)PLATFORM_hid_write, + (void *)PLATFORM_hid_read_timeout, + (void *)PLATFORM_hid_read, + (void *)PLATFORM_hid_set_nonblocking, + (void *)PLATFORM_hid_send_feature_report, + (void *)PLATFORM_hid_get_feature_report, + (void *)PLATFORM_hid_get_input_report, + (void *)PLATFORM_hid_close, + (void *)PLATFORM_hid_get_manufacturer_string, + (void *)PLATFORM_hid_get_product_string, + (void *)PLATFORM_hid_get_serial_number_string, + (void *)PLATFORM_hid_get_indexed_string, + (void *)PLATFORM_hid_get_device_info, + (void *)PLATFORM_hid_get_report_descriptor, + (void *)PLATFORM_hid_error +}; +#endif // HAVE_PLATFORM_BACKEND + +#ifdef HAVE_DRIVER_BACKEND +static const struct hidapi_backend DRIVER_Backend = { + (void *)DRIVER_hid_write, + (void *)DRIVER_hid_read_timeout, + (void *)DRIVER_hid_read, + (void *)DRIVER_hid_set_nonblocking, + (void *)DRIVER_hid_send_feature_report, + (void *)DRIVER_hid_get_feature_report, + (void *)DRIVER_hid_get_input_report, + (void *)DRIVER_hid_close, + (void *)DRIVER_hid_get_manufacturer_string, + (void *)DRIVER_hid_get_product_string, + (void *)DRIVER_hid_get_serial_number_string, + (void *)DRIVER_hid_get_indexed_string, + (void *)DRIVER_hid_get_device_info, + (void *)DRIVER_hid_get_report_descriptor, + (void *)DRIVER_hid_error +}; +#endif // HAVE_DRIVER_BACKEND + +#ifdef HAVE_LIBUSB +static const struct hidapi_backend LIBUSB_Backend = { + (void *)LIBUSB_hid_write, + (void *)LIBUSB_hid_read_timeout, + (void *)LIBUSB_hid_read, + (void *)LIBUSB_hid_set_nonblocking, + (void *)LIBUSB_hid_send_feature_report, + (void *)LIBUSB_hid_get_feature_report, + (void *)LIBUSB_hid_get_input_report, + (void *)LIBUSB_hid_close, + (void *)LIBUSB_hid_get_manufacturer_string, + (void *)LIBUSB_hid_get_product_string, + (void *)LIBUSB_hid_get_serial_number_string, + (void *)LIBUSB_hid_get_indexed_string, + (void *)LIBUSB_hid_get_device_info, + (void *)LIBUSB_hid_get_report_descriptor, + (void *)LIBUSB_hid_error +}; +#endif // HAVE_LIBUSB + +struct SDL_hid_device +{ + void *device; + const struct hidapi_backend *backend; + SDL_hid_device_info info; +}; + +#if defined(HAVE_PLATFORM_BACKEND) || defined(HAVE_DRIVER_BACKEND) || defined(HAVE_LIBUSB) + +static SDL_hid_device *CreateHIDDeviceWrapper(void *device, const struct hidapi_backend *backend) +{ + SDL_hid_device *wrapper = (SDL_hid_device *)SDL_malloc(sizeof(*wrapper)); + SDL_SetObjectValid(wrapper, SDL_OBJECT_TYPE_HIDAPI_DEVICE, true); + wrapper->device = device; + wrapper->backend = backend; + SDL_zero(wrapper->info); + return wrapper; +} + +#endif // HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || HAVE_LIBUSB + +static void DeleteHIDDeviceWrapper(SDL_hid_device *wrapper) +{ + SDL_SetObjectValid(wrapper, SDL_OBJECT_TYPE_HIDAPI_DEVICE, false); + SDL_free(wrapper->info.path); + SDL_free(wrapper->info.serial_number); + SDL_free(wrapper->info.manufacturer_string); + SDL_free(wrapper->info.product_string); + SDL_free(wrapper); +} + +#define CHECK_DEVICE_MAGIC(device, result) \ + if (!SDL_ObjectValid(device, SDL_OBJECT_TYPE_HIDAPI_DEVICE)) { \ + SDL_SetError("Invalid device"); \ + return result; \ + } + +#define COPY_IF_EXISTS(var) \ + if (pSrc->var != NULL) { \ + pDst->var = SDL_strdup(pSrc->var); \ + } else { \ + pDst->var = NULL; \ + } +#define WCOPY_IF_EXISTS(var) \ + if (pSrc->var != NULL) { \ + pDst->var = SDL_wcsdup(pSrc->var); \ + } else { \ + pDst->var = NULL; \ + } + +static void CopyHIDDeviceInfo(struct hid_device_info *pSrc, struct SDL_hid_device_info *pDst) +{ + COPY_IF_EXISTS(path) + pDst->vendor_id = pSrc->vendor_id; + pDst->product_id = pSrc->product_id; + WCOPY_IF_EXISTS(serial_number) + pDst->release_number = pSrc->release_number; + WCOPY_IF_EXISTS(manufacturer_string) + WCOPY_IF_EXISTS(product_string) + pDst->usage_page = pSrc->usage_page; + pDst->usage = pSrc->usage; + pDst->interface_number = pSrc->interface_number; + pDst->interface_class = pSrc->interface_class; + pDst->interface_subclass = pSrc->interface_subclass; + pDst->interface_protocol = pSrc->interface_protocol; + pDst->bus_type = (SDL_hid_bus_type)pSrc->bus_type; + pDst->next = NULL; +} + +#undef COPY_IF_EXISTS +#undef WCOPY_IF_EXISTS + +static int SDL_hidapi_refcount = 0; +static bool SDL_hidapi_only_controllers; +static char *SDL_hidapi_ignored_devices = NULL; + +static void SDLCALL OnlyControllersChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + SDL_hidapi_only_controllers = SDL_GetStringBoolean(hint, true); +} + +static void SDLCALL IgnoredDevicesChanged(void *userdata, const char *name, const char *oldValue, const char *hint) +{ + if (SDL_hidapi_ignored_devices) { + SDL_free(SDL_hidapi_ignored_devices); + } + if (hint && *hint) { + SDL_hidapi_ignored_devices = SDL_strdup(hint); + } else { + SDL_hidapi_ignored_devices = NULL; + } +} + +bool SDL_HIDAPI_ShouldIgnoreDevice(int bus, Uint16 vendor_id, Uint16 product_id, Uint16 usage_page, Uint16 usage) +{ + // See if there are any devices we should skip in enumeration + if (SDL_hidapi_only_controllers && usage_page) { + if (vendor_id == USB_VENDOR_VALVE) { + // Ignore the mouse/keyboard interface on Steam Controllers + if ( +#ifdef SDL_PLATFORM_WIN32 + // Check the usage page and usage on both USB and Bluetooth +#else + // Only check the usage page and usage on USB + bus == HID_API_BUS_USB && +#endif + usage_page == USB_USAGEPAGE_GENERIC_DESKTOP && + (usage == USB_USAGE_GENERIC_KEYBOARD || usage == USB_USAGE_GENERIC_MOUSE)) { + return true; + } + } else if (usage_page == USB_USAGEPAGE_GENERIC_DESKTOP && + (usage == USB_USAGE_GENERIC_JOYSTICK || usage == USB_USAGE_GENERIC_GAMEPAD || usage == USB_USAGE_GENERIC_MULTIAXISCONTROLLER)) { + // This is a controller + } else { + return true; + } + } + if (SDL_hidapi_ignored_devices) { + char vendor_match[16], product_match[16]; + SDL_snprintf(vendor_match, sizeof(vendor_match), "0x%.4x/0x0000", vendor_id); + SDL_snprintf(product_match, sizeof(product_match), "0x%.4x/0x%.4x", vendor_id, product_id); + if (SDL_strcasestr(SDL_hidapi_ignored_devices, vendor_match) || + SDL_strcasestr(SDL_hidapi_ignored_devices, product_match)) { + return true; + } + } + return false; +} + +int SDL_hid_init(void) +{ + int attempts = 0, success = 0; + + if (SDL_hidapi_refcount > 0) { + ++SDL_hidapi_refcount; + return 0; + } + + SDL_AddHintCallback(SDL_HINT_HIDAPI_ENUMERATE_ONLY_CONTROLLERS, OnlyControllersChanged, NULL); + SDL_AddHintCallback(SDL_HINT_HIDAPI_IGNORE_DEVICES, IgnoredDevicesChanged, NULL); + +#ifdef SDL_USE_LIBUDEV + if (!SDL_GetHintBoolean(SDL_HINT_HIDAPI_UDEV, true)) { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "udev disabled by SDL_HINT_HIDAPI_UDEV"); + linux_enumeration_method = ENUMERATION_FALLBACK; + } else if (SDL_GetSandbox() != SDL_SANDBOX_NONE) { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "Container detected, disabling HIDAPI udev integration"); + linux_enumeration_method = ENUMERATION_FALLBACK; + } else { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "Using udev for HIDAPI joystick device discovery"); + linux_enumeration_method = ENUMERATION_LIBUDEV; + } +#endif + + use_libusb_whitelist = SDL_GetHintBoolean(SDL_HINT_HIDAPI_LIBUSB_WHITELIST, + SDL_HINT_HIDAPI_LIBUSB_WHITELIST_DEFAULT); +#ifdef HAVE_LIBUSB + if (!SDL_GetHintBoolean(SDL_HINT_HIDAPI_LIBUSB, true)) { + SDL_LogDebug(SDL_LOG_CATEGORY_INPUT, + "libusb disabled with SDL_HINT_HIDAPI_LIBUSB"); + libusb_ctx.libhandle = NULL; + } else { + ++attempts; +#ifdef SDL_LIBUSB_DYNAMIC + libusb_ctx.libhandle = SDL_LoadObject(SDL_LIBUSB_DYNAMIC); +#else + libusb_ctx.libhandle = (void *)1; +#endif + if (libusb_ctx.libhandle != NULL) { + bool loaded = true; +#ifdef SDL_LIBUSB_DYNAMIC +#define LOAD_LIBUSB_SYMBOL(type, func) \ + if (!(libusb_ctx.func = (type)SDL_LoadFunction(libusb_ctx.libhandle, "libusb_" #func))) { \ + loaded = false; \ + } +#else +#define LOAD_LIBUSB_SYMBOL(type, func) \ + libusb_ctx.func = libusb_##func; +#endif + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_context **), init) + LOAD_LIBUSB_SYMBOL(void (LIBUSB_CALL *)(libusb_context *), exit) + LOAD_LIBUSB_SYMBOL(ssize_t (LIBUSB_CALL *)(libusb_context *, libusb_device ***), get_device_list) + LOAD_LIBUSB_SYMBOL(void (LIBUSB_CALL *)(libusb_device **, int), free_device_list) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device *, struct libusb_device_descriptor *), get_device_descriptor) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device *, struct libusb_config_descriptor **), get_active_config_descriptor) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device *, uint8_t, struct libusb_config_descriptor **), get_config_descriptor) + LOAD_LIBUSB_SYMBOL(void (LIBUSB_CALL *)(struct libusb_config_descriptor *), free_config_descriptor) + LOAD_LIBUSB_SYMBOL(uint8_t (LIBUSB_CALL *)(libusb_device *), get_bus_number) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device *dev, uint8_t *port_numbers, int port_numbers_len), get_port_numbers) + LOAD_LIBUSB_SYMBOL(uint8_t (LIBUSB_CALL *)(libusb_device *), get_device_address) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device *, libusb_device_handle **), open) + LOAD_LIBUSB_SYMBOL(void (LIBUSB_CALL *)(libusb_device_handle *), close) + LOAD_LIBUSB_SYMBOL(libusb_device * (LIBUSB_CALL *)(libusb_device_handle *dev_handle), get_device) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, int), claim_interface) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, int), release_interface) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, int), kernel_driver_active) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, int), detach_kernel_driver) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, int), attach_kernel_driver) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, int, int), set_interface_alt_setting) + LOAD_LIBUSB_SYMBOL(struct libusb_transfer * (LIBUSB_CALL *)(int), alloc_transfer) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(struct libusb_transfer *), submit_transfer) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(struct libusb_transfer *), cancel_transfer) + LOAD_LIBUSB_SYMBOL(void (LIBUSB_CALL *)(struct libusb_transfer *), free_transfer) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, uint8_t, uint8_t, uint16_t, uint16_t, unsigned char *, uint16_t, unsigned int), control_transfer) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_device_handle *, unsigned char, unsigned char *, int, int *, unsigned int), interrupt_transfer) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_context *), handle_events) + LOAD_LIBUSB_SYMBOL(int (LIBUSB_CALL *)(libusb_context *, int *), handle_events_completed) + LOAD_LIBUSB_SYMBOL(const char * (LIBUSB_CALL *)(int), error_name) +#undef LOAD_LIBUSB_SYMBOL + + if (!loaded) { +#ifdef SDL_LIBUSB_DYNAMIC + SDL_UnloadObject(libusb_ctx.libhandle); +#endif + libusb_ctx.libhandle = NULL; + // SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, SDL_LIBUSB_DYNAMIC " found but could not load function"); + } else if (LIBUSB_hid_init() < 0) { +#ifdef SDL_LIBUSB_DYNAMIC + SDL_UnloadObject(libusb_ctx.libhandle); +#endif + libusb_ctx.libhandle = NULL; + } else { + ++success; + } + } + } +#endif // HAVE_LIBUSB + +#ifdef HAVE_PLATFORM_BACKEND + ++attempts; +#ifdef SDL_PLATFORM_LINUX + udev_ctx = SDL_UDEV_GetUdevSyms(); +#endif // __LINUX __ + if (udev_ctx && PLATFORM_hid_init() == 0) { + ++success; + } +#endif // HAVE_PLATFORM_BACKEND + + if (attempts > 0 && success == 0) { + return -1; + } + +#if defined(SDL_PLATFORM_MACOS) && !defined(SDL_HIDAPI_DISABLED) + hid_darwin_set_open_exclusive(0); +#endif + + ++SDL_hidapi_refcount; + return 0; +} + +int SDL_hid_exit(void) +{ + int result = 0; + + if (SDL_hidapi_refcount == 0) { + return 0; + } + --SDL_hidapi_refcount; + if (SDL_hidapi_refcount > 0) { + return 0; + } + SDL_hidapi_refcount = 0; + +#ifndef SDL_HIDAPI_DISABLED + HIDAPI_ShutdownDiscovery(); +#endif + +#ifdef HAVE_PLATFORM_BACKEND + if (udev_ctx) { + result |= PLATFORM_hid_exit(); + } +#ifdef SDL_PLATFORM_LINUX + SDL_UDEV_ReleaseUdevSyms(); +#endif // __LINUX __ +#endif // HAVE_PLATFORM_BACKEND + +#ifdef HAVE_LIBUSB + if (libusb_ctx.libhandle) { + result |= LIBUSB_hid_exit(); +#ifdef SDL_LIBUSB_DYNAMIC + SDL_UnloadObject(libusb_ctx.libhandle); +#endif + libusb_ctx.libhandle = NULL; + } +#endif // HAVE_LIBUSB + + SDL_RemoveHintCallback(SDL_HINT_HIDAPI_ENUMERATE_ONLY_CONTROLLERS, OnlyControllersChanged, NULL); + SDL_RemoveHintCallback(SDL_HINT_HIDAPI_IGNORE_DEVICES, IgnoredDevicesChanged, NULL); + + if (SDL_hidapi_ignored_devices) { + SDL_free(SDL_hidapi_ignored_devices); + SDL_hidapi_ignored_devices = NULL; + } + + return result; +} + +Uint32 SDL_hid_device_change_count(void) +{ + Uint32 counter = 0; + +#ifndef SDL_HIDAPI_DISABLED + if (SDL_hidapi_refcount == 0 && SDL_hid_init() < 0) { + return 0; + } + + HIDAPI_UpdateDiscovery(); + + if (SDL_HIDAPI_discovery.m_unDeviceChangeCounter == 0) { + // Counter wrapped! + ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter; + } + counter = SDL_HIDAPI_discovery.m_unDeviceChangeCounter; + +#endif // !SDL_HIDAPI_DISABLED + + return counter; +} + +static void AddDeviceToEnumeration(const char *driver_name, struct hid_device_info *dev, struct SDL_hid_device_info **devs, struct SDL_hid_device_info **last) +{ + struct SDL_hid_device_info *new_dev; + +#ifdef DEBUG_HIDAPI + SDL_Log("Adding %s device to enumeration: %ls %ls 0x%.4hx/0x%.4hx/%d", + driver_name, dev->manufacturer_string, dev->product_string, dev->vendor_id, dev->product_id, dev->interface_number); +#else + (void)driver_name; +#endif + + new_dev = (struct SDL_hid_device_info *)SDL_malloc(sizeof(struct SDL_hid_device_info)); + if (new_dev == NULL) { + // Don't bother returning an error, get as many devices as possible + return; + } + CopyHIDDeviceInfo(dev, new_dev); + + if ((*last) != NULL) { + (*last)->next = new_dev; + } else { + *devs = new_dev; + } + *last = new_dev; +} + +#if defined(HAVE_LIBUSB) || defined(HAVE_PLATFORM_BACKEND) +static void RemoveDeviceFromEnumeration(const char *driver_name, struct hid_device_info *dev, struct hid_device_info **devs, void (*free_device_info)(struct hid_device_info *)) +{ + struct hid_device_info *last = NULL, *curr, *next; + + for (curr = *devs; curr; curr = next) { + next = curr->next; + + if (dev->vendor_id == curr->vendor_id && + dev->product_id == curr->product_id && + (dev->interface_number < 0 || curr->interface_number < 0 || dev->interface_number == curr->interface_number)) { +#ifdef DEBUG_HIDAPI + SDL_Log("Skipping %s device: %ls %ls 0x%.4hx/0x%.4hx/%d", + driver_name, curr->manufacturer_string, curr->product_string, curr->vendor_id, curr->product_id, curr->interface_number); +#else + (void)driver_name; +#endif + if (last) { + last->next = next; + } else { + *devs = next; + } + + curr->next = NULL; + free_device_info(curr); + continue; + } + last = curr; + } +} +#endif // HAVE_LIBUSB || HAVE_PLATFORM_BACKEND + +#ifdef HAVE_LIBUSB +static void RemoveNonWhitelistedDevicesFromEnumeration(struct hid_device_info **devs, void (*free_device_info)(struct hid_device_info *)) +{ + struct hid_device_info *last = NULL, *curr, *next; + + for (curr = *devs; curr; curr = next) { + next = curr->next; + + if (!IsInWhitelist(curr->vendor_id, curr->product_id)) { +#ifdef DEBUG_HIDAPI + SDL_Log("Device was not in libusb whitelist, skipping: %ls %ls 0x%.4hx/0x%.4hx/%d", + curr->manufacturer_string, curr->product_string, curr->vendor_id, curr->product_id, curr->interface_number); +#endif + if (last) { + last->next = next; + } else { + *devs = next; + } + + curr->next = NULL; + free_device_info(curr); + continue; + } + last = curr; + } +} +#endif // HAVE_LIBUSB + +struct SDL_hid_device_info *SDL_hid_enumerate(unsigned short vendor_id, unsigned short product_id) +{ + struct hid_device_info *driver_devs = NULL; + struct hid_device_info *usb_devs = NULL; + struct hid_device_info *raw_devs = NULL; + struct hid_device_info *dev; + struct SDL_hid_device_info *devs = NULL, *last = NULL; + + if (SDL_hidapi_refcount == 0 && SDL_hid_init() < 0) { + return NULL; + } + + // Collect the available devices +#ifdef HAVE_DRIVER_BACKEND + driver_devs = DRIVER_hid_enumerate(vendor_id, product_id); +#endif + +#ifdef HAVE_LIBUSB + if (libusb_ctx.libhandle) { + usb_devs = LIBUSB_hid_enumerate(vendor_id, product_id); + + if (use_libusb_whitelist) { + RemoveNonWhitelistedDevicesFromEnumeration(&usb_devs, LIBUSB_hid_free_enumeration); + } + } +#endif // HAVE_LIBUSB + +#ifdef HAVE_PLATFORM_BACKEND + if (udev_ctx) { + raw_devs = PLATFORM_hid_enumerate(vendor_id, product_id); + } +#endif + + // Highest priority are custom driver devices + for (dev = driver_devs; dev; dev = dev->next) { + AddDeviceToEnumeration("driver", dev, &devs, &last); +#ifdef HAVE_LIBUSB + RemoveDeviceFromEnumeration("libusb", dev, &usb_devs, LIBUSB_hid_free_enumeration); +#endif +#ifdef HAVE_PLATFORM_BACKEND + RemoveDeviceFromEnumeration("raw", dev, &raw_devs, PLATFORM_hid_free_enumeration); +#endif + } + + // If whitelist is in effect, libusb has priority, otherwise raw devices do + if (use_libusb_whitelist) { + for (dev = usb_devs; dev; dev = dev->next) { + AddDeviceToEnumeration("libusb", dev, &devs, &last); +#ifdef HAVE_PLATFORM_BACKEND + RemoveDeviceFromEnumeration("raw", dev, &raw_devs, PLATFORM_hid_free_enumeration); +#endif + } + for (dev = raw_devs; dev; dev = dev->next) { + AddDeviceToEnumeration("platform", dev, &devs, &last); + } + } else { + for (dev = raw_devs; dev; dev = dev->next) { + AddDeviceToEnumeration("raw", dev, &devs, &last); +#ifdef HAVE_LIBUSB + RemoveDeviceFromEnumeration("libusb", dev, &usb_devs, LIBUSB_hid_free_enumeration); +#endif + } + for (dev = usb_devs; dev; dev = dev->next) { + AddDeviceToEnumeration("libusb", dev, &devs, &last); + } + } + +#ifdef HAVE_DRIVER_BACKEND + DRIVER_hid_free_enumeration(driver_devs); +#endif +#ifdef HAVE_LIBUSB + LIBUSB_hid_free_enumeration(usb_devs); +#endif +#ifdef HAVE_PLATFORM_BACKEND + PLATFORM_hid_free_enumeration(raw_devs); +#endif + + return devs; +} + +void SDL_hid_free_enumeration(struct SDL_hid_device_info *devs) +{ + while (devs) { + struct SDL_hid_device_info *next = devs->next; + SDL_free(devs->path); + SDL_free(devs->serial_number); + SDL_free(devs->manufacturer_string); + SDL_free(devs->product_string); + SDL_free(devs); + devs = next; + } +} + +SDL_hid_device *SDL_hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number) +{ +#if defined(HAVE_PLATFORM_BACKEND) || defined(HAVE_DRIVER_BACKEND) || defined(HAVE_LIBUSB) + void *pDevice = NULL; + + if (SDL_hidapi_refcount == 0 && SDL_hid_init() < 0) { + return NULL; + } + +#ifdef HAVE_PLATFORM_BACKEND + if (udev_ctx) { + pDevice = PLATFORM_hid_open(vendor_id, product_id, serial_number); + if (pDevice != NULL) { + return CreateHIDDeviceWrapper(pDevice, &PLATFORM_Backend); + } + } +#endif // HAVE_PLATFORM_BACKEND + +#ifdef HAVE_DRIVER_BACKEND + pDevice = DRIVER_hid_open(vendor_id, product_id, serial_number); + if (pDevice != NULL) { + return CreateHIDDeviceWrapper(pDevice, &DRIVER_Backend); + } +#endif // HAVE_DRIVER_BACKEND + +#ifdef HAVE_LIBUSB + if (libusb_ctx.libhandle != NULL) { + pDevice = LIBUSB_hid_open(vendor_id, product_id, serial_number); + if (pDevice != NULL) { + return CreateHIDDeviceWrapper(pDevice, &LIBUSB_Backend); + } + } +#endif // HAVE_LIBUSB + +#endif // HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || HAVE_LIBUSB + + return NULL; +} + +SDL_hid_device *SDL_hid_open_path(const char *path) +{ +#if defined(HAVE_PLATFORM_BACKEND) || defined(HAVE_DRIVER_BACKEND) || defined(HAVE_LIBUSB) + void *pDevice = NULL; + + if (SDL_hidapi_refcount == 0 && SDL_hid_init() < 0) { + return NULL; + } + +#ifdef HAVE_PLATFORM_BACKEND + if (udev_ctx) { + pDevice = PLATFORM_hid_open_path(path); + if (pDevice != NULL) { + return CreateHIDDeviceWrapper(pDevice, &PLATFORM_Backend); + } + } +#endif // HAVE_PLATFORM_BACKEND + +#ifdef HAVE_DRIVER_BACKEND + pDevice = DRIVER_hid_open_path(path); + if (pDevice != NULL) { + return CreateHIDDeviceWrapper(pDevice, &DRIVER_Backend); + } +#endif // HAVE_DRIVER_BACKEND + +#ifdef HAVE_LIBUSB + if (libusb_ctx.libhandle != NULL) { + pDevice = LIBUSB_hid_open_path(path); + if (pDevice != NULL) { + return CreateHIDDeviceWrapper(pDevice, &LIBUSB_Backend); + } + } +#endif // HAVE_LIBUSB + +#endif // HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || HAVE_LIBUSB + + return NULL; +} + +int SDL_hid_write(SDL_hid_device *device, const unsigned char *data, size_t length) +{ + CHECK_DEVICE_MAGIC(device, -1); + + return device->backend->hid_write(device->device, data, length); +} + +int SDL_hid_read_timeout(SDL_hid_device *device, unsigned char *data, size_t length, int milliseconds) +{ + CHECK_DEVICE_MAGIC(device, -1); + + return device->backend->hid_read_timeout(device->device, data, length, milliseconds); +} + +int SDL_hid_read(SDL_hid_device *device, unsigned char *data, size_t length) +{ + CHECK_DEVICE_MAGIC(device, -1); + + return device->backend->hid_read(device->device, data, length); +} + +int SDL_hid_set_nonblocking(SDL_hid_device *device, int nonblock) +{ + CHECK_DEVICE_MAGIC(device, -1); + + return device->backend->hid_set_nonblocking(device->device, nonblock); +} + +int SDL_hid_send_feature_report(SDL_hid_device *device, const unsigned char *data, size_t length) +{ + CHECK_DEVICE_MAGIC(device, -1); + + return device->backend->hid_send_feature_report(device->device, data, length); +} + +int SDL_hid_get_feature_report(SDL_hid_device *device, unsigned char *data, size_t length) +{ + CHECK_DEVICE_MAGIC(device, -1); + + return device->backend->hid_get_feature_report(device->device, data, length); +} + +int SDL_hid_get_input_report(SDL_hid_device *device, unsigned char *data, size_t length) +{ + CHECK_DEVICE_MAGIC(device, -1); + + return device->backend->hid_get_input_report(device->device, data, length); +} + +int SDL_hid_close(SDL_hid_device *device) +{ + CHECK_DEVICE_MAGIC(device, -1); + + device->backend->hid_close(device->device); + DeleteHIDDeviceWrapper(device); + return 0; +} + +int SDL_hid_get_manufacturer_string(SDL_hid_device *device, wchar_t *string, size_t maxlen) +{ + CHECK_DEVICE_MAGIC(device, -1); + + return device->backend->hid_get_manufacturer_string(device->device, string, maxlen); +} + +int SDL_hid_get_product_string(SDL_hid_device *device, wchar_t *string, size_t maxlen) +{ + CHECK_DEVICE_MAGIC(device, -1); + + return device->backend->hid_get_product_string(device->device, string, maxlen); +} + +int SDL_hid_get_serial_number_string(SDL_hid_device *device, wchar_t *string, size_t maxlen) +{ + CHECK_DEVICE_MAGIC(device, -1); + + return device->backend->hid_get_serial_number_string(device->device, string, maxlen); +} + +int SDL_hid_get_indexed_string(SDL_hid_device *device, int string_index, wchar_t *string, size_t maxlen) +{ + CHECK_DEVICE_MAGIC(device, -1); + + return device->backend->hid_get_indexed_string(device->device, string_index, string, maxlen); +} + +SDL_hid_device_info *SDL_hid_get_device_info(SDL_hid_device *device) +{ + struct hid_device_info *info; + + CHECK_DEVICE_MAGIC(device, NULL); + + info = device->backend->hid_get_device_info(device->device); + if (info) { + CopyHIDDeviceInfo(info, &device->info); + return &device->info; + } else { + return NULL; + } +} + +int SDL_hid_get_report_descriptor(SDL_hid_device *device, unsigned char *buf, size_t buf_size) +{ + CHECK_DEVICE_MAGIC(device, -1); + + return device->backend->hid_get_report_descriptor(device->device, buf, buf_size); +} + +void SDL_hid_ble_scan(bool active) +{ +#if !defined(SDL_HIDAPI_DISABLED) && (defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS)) + extern void hid_ble_scan(int bStart); + hid_ble_scan(active); +#endif +} + +#ifdef HAVE_ENABLE_GAMECUBE_ADAPTORS +// This is needed to enable input for Nyko and EVORETRO GameCube adaptors +void SDL_EnableGameCubeAdaptors(void) +{ +#ifdef HAVE_LIBUSB + libusb_context *context = NULL; + libusb_device **devs = NULL; + libusb_device_handle *handle = NULL; + struct libusb_device_descriptor desc; + ssize_t i, num_devs; + int kernel_detached = 0; + + if (libusb_ctx.libhandle == NULL) { + return; + } + + if (libusb_ctx.init(&context) == 0) { + num_devs = libusb_ctx.get_device_list(context, &devs); + for (i = 0; i < num_devs; ++i) { + if (libusb_ctx.get_device_descriptor(devs[i], &desc) != 0) { + continue; + } + + if (desc.idVendor != 0x057e || desc.idProduct != 0x0337) { + continue; + } + + if (libusb_ctx.open(devs[i], &handle) != 0) { + continue; + } + + if (libusb_ctx.kernel_driver_active(handle, 0)) { + if (libusb_ctx.detach_kernel_driver(handle, 0) == 0) { + kernel_detached = 1; + } + } + + if (libusb_ctx.claim_interface(handle, 0) == 0) { + libusb_ctx.control_transfer(handle, 0x21, 11, 0x0001, 0, NULL, 0, 1000); + libusb_ctx.release_interface(handle, 0); + } + + if (kernel_detached) { + libusb_ctx.attach_kernel_driver(handle, 0); + } + + libusb_ctx.close(handle); + } + + libusb_ctx.free_device_list(devs, 1); + + libusb_ctx.exit(context); + } +#endif // HAVE_LIBUSB +} +#endif // HAVE_ENABLE_GAMECUBE_ADAPTORS diff --git a/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_android.h b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_android.h new file mode 100644 index 0000000..2f3851f --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_android.h @@ -0,0 +1,26 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + 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. +*/ + +/* The implementation for Android is in a separate .cpp file */ +#undef HIDAPI_H__ +#include "hidapi/hidapi.h" +#define HAVE_PLATFORM_BACKEND 1 +#define udev_ctx 1 diff --git a/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_c.h b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_c.h new file mode 100644 index 0000000..6d94f77 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_c.h @@ -0,0 +1,35 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + 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" + + +/* Return true if the HIDAPI should ignore a device during enumeration */ +extern bool SDL_HIDAPI_ShouldIgnoreDevice(int bus_type, Uint16 vendor_id, Uint16 product_id, Uint16 usage_page, Uint16 usage); + +#ifdef SDL_JOYSTICK_HIDAPI +#ifdef HAVE_LIBUSB +#define HAVE_ENABLE_GAMECUBE_ADAPTORS +#endif + +#ifdef HAVE_ENABLE_GAMECUBE_ADAPTORS +extern void SDL_EnableGameCubeAdaptors(void); +#endif +#endif /* SDL_JOYSTICK_HIDAPI */ diff --git a/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_ios.h b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_ios.h new file mode 100644 index 0000000..f58f10d --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_ios.h @@ -0,0 +1,26 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + 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. +*/ + +/* The implementation for iOS and tvOS is in a separate .m file */ +#undef HIDAPI_H__ +#include "hidapi/hidapi.h" +#define HAVE_PLATFORM_BACKEND 1 +#define udev_ctx 1 diff --git a/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_libusb.h b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_libusb.h new file mode 100644 index 0000000..ed8b4a3 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_libusb.h @@ -0,0 +1,134 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + 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. +*/ + +/* Define standard library functions in terms of SDL */ + +/* #pragma push_macro/pop_macro works correctly only as of gcc >= 4.4.3 + clang-3.0 _seems_ to be OK. */ +#pragma push_macro("calloc") +#pragma push_macro("malloc") +#pragma push_macro("realloc") +#pragma push_macro("free") +#pragma push_macro("iconv_t") +#pragma push_macro("iconv") +#pragma push_macro("iconv_open") +#pragma push_macro("iconv_close") +#pragma push_macro("setlocale") +#pragma push_macro("snprintf") +#pragma push_macro("strcmp") +#pragma push_macro("strdup") +#pragma push_macro("strncpy") +#pragma push_macro("tolower") +#pragma push_macro("wcscmp") +#pragma push_macro("wcsdup") +#pragma push_macro("wcsncpy") + +#undef calloc +#undef malloc +#undef realloc +#undef free +#undef iconv_t +#undef iconv +#undef iconv_open +#undef iconv_close +#undef setlocale +#undef snprintf +#undef strcmp +#undef strdup +#undef strncpy +#undef tolower +#undef wcscmp +#undef wcsdup +#undef wcsncpy + +#define calloc SDL_calloc +#define malloc SDL_malloc +#define realloc SDL_realloc +#define free SDL_free +#define iconv_t SDL_iconv_t +#ifndef ICONV_CONST +#define ICONV_CONST +#define UNDEF_ICONV_CONST +#endif +#define iconv(a,b,c,d,e) SDL_iconv(a, (const char **)b, c, d, e) +#define iconv_open SDL_iconv_open +#define iconv_close SDL_iconv_close +#define setlocale(X, Y) NULL +#define snprintf SDL_snprintf +#define strcmp SDL_strcmp +#define strdup SDL_strdup +#define strncpy SDL_strlcpy +#define tolower SDL_tolower +#define wcscmp SDL_wcscmp +#define wcsdup SDL_wcsdup +#define wcsncpy SDL_wcslcpy + + +#ifndef SDL_PLATFORM_FREEBSD +/* this is awkwardly inlined, so we need to re-implement it here + * so we can override the libusb_control_transfer call */ +static int SDL_libusb_get_string_descriptor(libusb_device_handle *dev, + uint8_t descriptor_index, uint16_t lang_id, + unsigned char *data, int length) +{ + return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN | 0x0, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | descriptor_index, lang_id, + data, (uint16_t)length, 1000); /* Endpoint 0 IN */ +} +#define libusb_get_string_descriptor SDL_libusb_get_string_descriptor +#endif /* SDL_PLATFORM_FREEBSD */ + +#define HIDAPI_THREAD_MODEL_INCLUDE "hidapi_thread_sdl.h" +#ifndef LIBUSB_API_VERSION +#ifdef LIBUSBX_API_VERSION +#define LIBUSB_API_VERSION LIBUSBX_API_VERSION +#else +#define LIBUSB_API_VERSION 0x0 +#endif +#endif +/* we need libusb >= 1.0.16 because of libusb_get_port_numbers */ +/* we don't need libusb_wrap_sys_device: */ +#define HIDAPI_TARGET_LIBUSB_API_VERSION 0x01000102 + +#undef HIDAPI_H__ +#include "libusb/hid.c" + +/* restore libc function macros */ +#ifdef UNDEF_ICONV_CONST +#undef ICONV_CONST +#undef UNDEF_ICONV_CONST +#endif +#pragma pop_macro("calloc") +#pragma pop_macro("malloc") +#pragma pop_macro("realloc") +#pragma pop_macro("free") +#pragma pop_macro("iconv_t") +#pragma pop_macro("iconv") +#pragma pop_macro("iconv_open") +#pragma pop_macro("iconv_close") +#pragma pop_macro("setlocale") +#pragma pop_macro("snprintf") +#pragma pop_macro("strcmp") +#pragma pop_macro("strdup") +#pragma pop_macro("strncpy") +#pragma pop_macro("tolower") +#pragma pop_macro("wcscmp") +#pragma pop_macro("wcsdup") +#pragma pop_macro("wcsncpy") diff --git a/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_linux.h b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_linux.h new file mode 100644 index 0000000..29723d7 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_linux.h @@ -0,0 +1,47 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + 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. +*/ + +#ifdef SDL_USE_LIBUDEV +static const SDL_UDEV_Symbols *udev_ctx = NULL; + +#define udev_device_get_devnode udev_ctx->udev_device_get_devnode +#define udev_device_get_parent_with_subsystem_devtype udev_ctx->udev_device_get_parent_with_subsystem_devtype +#define udev_device_get_sysattr_value udev_ctx->udev_device_get_sysattr_value +#define udev_device_get_syspath udev_ctx->udev_device_get_syspath +#define udev_device_new_from_devnum udev_ctx->udev_device_new_from_devnum +#define udev_device_new_from_syspath udev_ctx->udev_device_new_from_syspath +#define udev_device_unref udev_ctx->udev_device_unref +#define udev_enumerate_add_match_subsystem udev_ctx->udev_enumerate_add_match_subsystem +#define udev_enumerate_get_list_entry udev_ctx->udev_enumerate_get_list_entry +#define udev_enumerate_new udev_ctx->udev_enumerate_new +#define udev_enumerate_scan_devices udev_ctx->udev_enumerate_scan_devices +#define udev_enumerate_unref udev_ctx->udev_enumerate_unref +#define udev_list_entry_get_name udev_ctx->udev_list_entry_get_name +#define udev_list_entry_get_next udev_ctx->udev_list_entry_get_next +#define udev_new udev_ctx->udev_new +#define udev_unref udev_ctx->udev_unref + +#undef HIDAPI_H__ +#define HIDAPI_ALLOW_BUILD_WORKAROUND_KERNEL_2_6_39 +#include "linux/hid.c" +#define HAVE_PLATFORM_BACKEND 1 + +#endif /* SDL_USE_LIBUDEV */ diff --git a/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_mac.h b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_mac.h new file mode 100644 index 0000000..820b67d --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_mac.h @@ -0,0 +1,25 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + 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. +*/ + +#undef HIDAPI_H__ +#include "mac/hid.c" +#define HAVE_PLATFORM_BACKEND 1 +#define udev_ctx 1 diff --git a/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_netbsd.h b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_netbsd.h new file mode 100644 index 0000000..1b39e22 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_netbsd.h @@ -0,0 +1,25 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + 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. +*/ + +#undef HIDAPI_H__ +#include "netbsd/hid.c" +#define HAVE_PLATFORM_BACKEND 1 +#define udev_ctx 1 diff --git a/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_steamxbox.h b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_steamxbox.h new file mode 100644 index 0000000..b6294a3 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_steamxbox.h @@ -0,0 +1,23 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + 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. +*/ + +#undef HIDAPI_H__ +#include "steamxbox/hid.c" diff --git a/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_windows.h b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_windows.h new file mode 100644 index 0000000..c29122b --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/SDL_hidapi_windows.h @@ -0,0 +1,82 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + 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. +*/ + +/* Define standard library functions in terms of SDL */ + +/* #pragma push_macro/pop_macro works correctly only as of gcc >= 4.4.3 + clang-3.0 _seems_ to be OK. */ +#pragma push_macro("calloc") +#pragma push_macro("free") +#pragma push_macro("malloc") +#pragma push_macro("memcmp") +#pragma push_macro("swprintf") +#pragma push_macro("towupper") +#pragma push_macro("wcscmp") +#pragma push_macro("_wcsdup") +#pragma push_macro("wcslen") +#pragma push_macro("wcsncpy") +#pragma push_macro("wcsstr") +#pragma push_macro("wcstol") + +#undef calloc +#undef free +#undef malloc +#undef memcmp +#undef swprintf +#undef towupper +#undef wcscmp +#undef _wcsdup +#undef wcslen +#undef wcsncpy +#undef wcsstr +#undef wcstol + +#define calloc SDL_calloc +#define free SDL_free +#define malloc SDL_malloc +#define memcmp SDL_memcmp +#define swprintf SDL_swprintf +#define towupper (wchar_t)SDL_toupper +#define wcscmp SDL_wcscmp +#define _wcsdup SDL_wcsdup +#define wcslen SDL_wcslen +#define wcsncpy SDL_wcslcpy +#define wcsstr SDL_wcsstr +#define wcstol SDL_wcstol + +#undef HIDAPI_H__ +#include "windows/hid.c" +#define HAVE_PLATFORM_BACKEND 1 +#define udev_ctx 1 + +/* restore libc function macros */ +#pragma pop_macro("calloc") +#pragma pop_macro("free") +#pragma pop_macro("malloc") +#pragma pop_macro("memcmp") +#pragma pop_macro("swprintf") +#pragma pop_macro("towupper") +#pragma pop_macro("wcscmp") +#pragma pop_macro("_wcsdup") +#pragma pop_macro("wcslen") +#pragma pop_macro("wcsncpy") +#pragma pop_macro("wcsstr") +#pragma pop_macro("wcstol") diff --git a/contrib/SDL-3.2.8/src/hidapi/VERSION b/contrib/SDL-3.2.8/src/hidapi/VERSION new file mode 100644 index 0000000..0548fb4 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/VERSION @@ -0,0 +1 @@ +0.14.0 \ No newline at end of file diff --git a/contrib/SDL-3.2.8/src/hidapi/android/hid.cpp b/contrib/SDL-3.2.8/src/hidapi/android/hid.cpp new file mode 100644 index 0000000..887390e --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/android/hid.cpp @@ -0,0 +1,1477 @@ +/* + 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 +#include + +#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 + +extern "C" { +#include "../SDL_hidapi_c.h" +} +#include "../../core/android/SDL_android.h" + +#define hid_close PLATFORM_hid_close +#define hid_device PLATFORM_hid_device +#define hid_device_ PLATFORM_hid_device_ +#define hid_enumerate PLATFORM_hid_enumerate +#define hid_error PLATFORM_hid_error +#define hid_exit PLATFORM_hid_exit +#define hid_free_enumeration PLATFORM_hid_free_enumeration +#define hid_get_device_info PLATFORM_hid_get_device_info +#define hid_get_feature_report PLATFORM_hid_get_feature_report +#define hid_get_indexed_string PLATFORM_hid_get_indexed_string +#define hid_get_input_report PLATFORM_hid_get_input_report +#define hid_get_manufacturer_string PLATFORM_hid_get_manufacturer_string +#define hid_get_product_string PLATFORM_hid_get_product_string +#define hid_get_report_descriptor PLATFORM_hid_get_report_descriptor +#define hid_get_serial_number_string PLATFORM_hid_get_serial_number_string +#define hid_init PLATFORM_hid_init +#define hid_open_path PLATFORM_hid_open_path +#define hid_open PLATFORM_hid_open +#define hid_read PLATFORM_hid_read +#define hid_read_timeout PLATFORM_hid_read_timeout +#define hid_send_feature_report PLATFORM_hid_send_feature_report +#define hid_set_nonblocking PLATFORM_hid_set_nonblocking +#define hid_version PLATFORM_hid_version +#define hid_version_str PLATFORM_hid_version_str +#define hid_write PLATFORM_hid_write + +#include +#include // For ETIMEDOUT and ECONNRESET +#include // 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; +}; + +template +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_midHIDDeviceManagerWriteReport; +static jmethodID g_midHIDDeviceManagerReadReport; +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; + } + + 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() + { + JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); + + if ( !g_HIDDeviceManagerCallbackHandler ) + { + LOGV( "Device open without callback handler" ); + return false; + } + + if ( m_bIsWaitingForOpen ) + { + SDL_SetError( "Waiting for permission" ); + return false; + } + + if ( !m_bOpenResult ) + { + m_bOpenResult = env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerOpen, m_nId ); + ExceptionCheck( env, "BOpen" ); + + if ( m_bIsWaitingForOpen ) + { + LOGV( "Device open waiting for permission" ); + SDL_SetError( "Waiting for permission" ); + m_bWasOpenPending = true; + return false; + } + + if ( !m_bOpenResult ) + { + LOGV( "Device open failed" ); + SDL_SetError( "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; + } + + bool BOpenPending() const + { + return m_bIsWaitingForOpen; + } + + void SetWasOpenPending( bool bState ) + { + m_bWasOpenPending = bState; + } + + bool BWasOpenPending() const + { + return m_bWasOpenPending; + } + + void SetOpenResult( bool bResult ) + { + if ( m_bIsWaitingForOpen ) + { + m_bOpenResult = bResult; + m_bIsWaitingForOpen = false; + + if ( m_bOpenResult ) + { + LOGV( "Device open succeeded" ); + } + else + { + LOGV( "Device open failed" ); + } + } + } + + bool BOpenResult() const + { + return m_bOpenResult; + } + + 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 WriteReport( const unsigned char *pData, size_t nDataLen, bool bFeature ) + { + JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); + + if ( !g_HIDDeviceManagerCallbackHandler ) + { + LOGV( "WriteReport without callback handler" ); + return -1; + } + + jbyteArray pBuf = NewByteArray( env, pData, nDataLen ); + int nRet = env->CallIntMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerWriteReport, m_nId, pBuf, bFeature ); + ExceptionCheck( env, "WriteReport" ); + env->DeleteLocalRef( pBuf ); + return nRet; + } + + void ProcessReportResponse( const uint8_t *pBuf, size_t nBufSize ) + { + hid_mutex_guard cvl( &m_cvLock ); + if ( m_bIsWaitingForReportResponse ) + { + m_reportResponse.assign( pBuf, nBufSize ); + + m_bIsWaitingForReportResponse = false; + m_nReportResponseError = 0; + pthread_cond_signal( &m_cv ); + } + } + + int ReadReport( unsigned char *pData, size_t nDataLen, bool bFeature ) + { + JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); + + if ( !g_HIDDeviceManagerCallbackHandler ) + { + LOGV( "ReadReport without callback handler" ); + return -1; + } + + { + hid_mutex_guard cvl( &m_cvLock ); + if ( m_bIsWaitingForReportResponse ) + { + LOGV( "Get feature report already ongoing... bail" ); + return -1; // Read already ongoing, we currently do not serialize, TODO + } + m_bIsWaitingForReportResponse = true; + } + + jbyteArray pBuf = NewByteArray( env, pData, nDataLen ); + int nRet = env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerReadReport, m_nId, pBuf, bFeature ) ? 0 : -1; + ExceptionCheck( env, "ReadReport" ); + env->DeleteLocalRef( pBuf ); + if ( nRet < 0 ) + { + LOGV( "ReadReport failed" ); + m_bIsWaitingForReportResponse = false; + return -1; + } + + { + hid_mutex_guard cvl( &m_cvLock ); + if ( m_bIsWaitingForReportResponse ) + { + 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_bIsWaitingForReportResponse && get_timespec_ms( ts ) < get_timespec_ms( endtime ) ); + + // We are back + if ( m_bIsWaitingForReportResponse ) + { + m_nReportResponseError = -ETIMEDOUT; + m_bIsWaitingForReportResponse = false; + } + LOGV( "=== Got feature report err=%d", m_nReportResponseError ); + if ( m_nReportResponseError != 0 ) + { + return m_nReportResponseError; + } + } + + size_t uBytesToCopy = m_reportResponse.size() > nDataLen ? nDataLen : m_reportResponse.size(); + SDL_memcpy( pData, m_reportResponse.data(), uBytesToCopy ); + m_reportResponse.clear(); + LOGV( "=== Got %zu bytes", uBytesToCopy ); + + return (int)uBytesToCopy; + } + } + + void Close( bool bDeleteDevice ) + { + JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); + + if ( g_HIDDeviceManagerCallbackHandler ) + { + if ( !m_bIsWaitingForOpen && m_bOpenResult ) + { + 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_reportResponse.clear(); + m_bIsWaitingForReportResponse = false; + m_nReportResponseError = -ECONNRESET; + pthread_cond_broadcast( &m_cv ); + + m_bOpenResult = false; + + 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_bWasOpenPending = false; + bool m_bOpenResult = false; + bool m_bIsWaitingForReportResponse = false; + int m_nReportResponseError = 0; + hid_buffer m_reportResponse; + +public: + hid_device_ref 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 g_Devices; + +static hid_device_ref FindDevice( int nDeviceId ) +{ + hid_device_ref pDevice; + + hid_mutex_guard l( &g_DevicesMutex ); + for ( pDevice = g_Devices; pDevice; pDevice = pDevice->next ) + { + if ( pDevice->GetId() == nDeviceId ) + { + break; + } + } + return pDevice; +} + + +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, bool bBluetooth ); + +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(HIDDeviceReportResponse)(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()"); + + 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_midHIDDeviceManagerWriteReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "writeReport", "(I[BZ)I" ); + if ( !g_midHIDDeviceManagerWriteReport ) + { + __android_log_print(ANDROID_LOG_ERROR, TAG, "HIDDeviceRegisterCallback: callback class missing writeReport" ); + } + g_midHIDDeviceManagerReadReport = env->GetMethodID( g_HIDDeviceManagerCallbackClass, "readReport", "(I[BZ)Z" ); + if ( !g_midHIDDeviceManagerReadReport ) + { + __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, bool bBluetooth ) +{ + 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; + if ( bBluetooth ) + { + pInfo->bus_type = HID_API_BUS_BLUETOOTH; + } + else + { + pInfo->bus_type = HID_API_BUS_USB; + } + + hid_device_ref pDevice( new CHIDDevice( nDeviceID, pInfo ) ); + + hid_mutex_guard l( &g_DevicesMutex ); + hid_device_ref 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 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 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 pDevice; + { + hid_mutex_guard l( &g_DevicesMutex ); + hid_device_ref 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 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(HIDDeviceReportResponse)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value) +{ + jbyte *pBuf = env->GetByteArrayElements(value, NULL); + jsize nBufSize = env->GetArrayLength(value); + + LOGV( "HIDDeviceReportResponse() id=%d len=%u\n", nDeviceID, nBufSize ); + hid_device_ref pDevice = FindDevice( nDeviceID ); + if ( pDevice ) + { + pDevice->ProcessReportResponse( reinterpret_cast< const uint8_t* >( pBuf ), nBufSize ); + } + + env->ReleaseByteArrayElements(value, pBuf, 0); +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +extern "C" +{ + +static void SDLCALL RequestBluetoothPermissionCallback( void *userdata, const char *permission, bool granted ) +{ + SDL_Log( "Bluetooth permission %s", granted ? "granted" : "denied" ); + + if ( granted && g_HIDDeviceManagerCallbackHandler ) + { + JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); + + env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerInitialize, false, true ); + } +} + +int hid_init(void) +{ + if ( !g_initialized && g_HIDDeviceManagerCallbackHandler ) + { + // HIDAPI doesn't work well with Android < 4.3 + if ( SDL_GetAndroidSDKVersion() >= 18 ) + { + JNIEnv *env = (JNIEnv *)SDL_GetAndroidJNIEnv(); + + env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerInitialize, true, false ); + + // 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, false ) ) + { + if ( SDL_GetAndroidSDKVersion() < 31 ) + { + env->CallBooleanMethod( g_HIDDeviceManagerCallbackHandler, g_midHIDDeviceManagerInitialize, false, true ); + } + else + { + SDL_Log( "Requesting Bluetooth permission" ); + SDL_RequestAndroidPermission( "android.permission.BLUETOOTH_CONNECT", RequestBluetoothPermissionCallback, NULL ); + } + } + 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; + + hid_mutex_guard l( &g_DevicesMutex ); + for ( hid_device_ref pDevice = g_Devices; pDevice; pDevice = pDevice->next ) + { + // Don't enumerate devices that are currently being opened, we'll re-enumerate them when we're done + // Make sure we skip them at least once, so they get removed and then re-added to the caller's device list + if ( pDevice->BWasOpenPending() ) + { + // Don't enumerate devices that failed to open, otherwise the application might try to keep prompting for access + if ( !pDevice->BOpenPending() && pDevice->BOpenResult() ) + { + pDevice->SetWasOpenPending( false ); + } + continue; + } + + const hid_device_info *info = pDevice->GetDeviceInfo(); + + /* See if there are any devices we should skip in enumeration */ + if (SDL_HIDAPI_ShouldIgnoreDevice(HID_API_BUS_UNKNOWN, info->vendor_id, info->product_id, 0, 0)) { + 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) +{ + 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 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 ) + { + SDL_SetError( "Couldn't find device with path %s", path ); + return NULL; + } + if ( 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=%zu", device->m_nId, length ); + hid_device_ref pDevice = FindDevice( device->m_nId ); + if ( pDevice ) + { + return pDevice->WriteReport( data, length, false ); + } + } + 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 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=%zu", 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=%zu", device->m_nId, length ); + hid_device_ref pDevice = FindDevice( device->m_nId ); + if ( pDevice ) + { + return pDevice->WriteReport( data, length, true ); + } + } + 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=%zu", device->m_nId, length ); + hid_device_ref pDevice = FindDevice( device->m_nId ); + if ( pDevice ) + { + return pDevice->ReadReport( data, length, true ); + } + } + return -1; // Controller was disconnected +} + + +// Synchronous operation. Will block until completed. +int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *device, unsigned char *data, size_t length) +{ + if ( device ) + { + LOGV( "hid_get_input_report id=%d length=%zu", device->m_nId, length ); + hid_device_ref pDevice = FindDevice( device->m_nId ); + if ( pDevice ) + { + return pDevice->ReadReport( data, length, false ); + } + } + 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 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 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 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 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; +} + +struct hid_device_info *hid_get_device_info(hid_device *device) +{ + if ( device ) + { + hid_device_ref pDevice = FindDevice( device->m_nId ); + if ( pDevice ) + { + return pDevice->GetDeviceInfo(); + } + } + return NULL; +} + +int hid_get_report_descriptor(hid_device *device, unsigned char *buf, size_t buf_size) +{ + // Not implemented + 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, bool bBluetooth ); + +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(HIDDeviceReportResponse)(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, bool bBluetooth ) +{ + 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(HIDDeviceReportResponse)(JNIEnv *env, jobject thiz, int nDeviceID, jbyteArray value) +{ + LOGV("Stub HIDDeviceReportResponse() 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;IIIIZ)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) }, + { "HIDDeviceReportResponse", "(I[B)V", (void*)HID_DEVICE_MANAGER_JAVA_INTERFACE(HIDDeviceReportResponse) } +}; diff --git a/contrib/SDL-3.2.8/src/hidapi/android/hid.h b/contrib/SDL-3.2.8/src/hidapi/android/hid.h new file mode 100644 index 0000000..5e6253b --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/android/hid.h @@ -0,0 +1,39 @@ +/* + 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 + +#ifdef __cplusplus +extern "C" { +#endif + +extern JNINativeMethod HIDDeviceManager_tab[8]; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/SDL-3.2.8/src/hidapi/bootstrap b/contrib/SDL-3.2.8/src/hidapi/bootstrap new file mode 100755 index 0000000..81e9b74 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/bootstrap @@ -0,0 +1,2 @@ +#!/bin/sh -x +autoreconf --install --verbose --force diff --git a/contrib/SDL-3.2.8/src/hidapi/configure.ac b/contrib/SDL-3.2.8/src/hidapi/configure.ac new file mode 100644 index 0000000..1b20510 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/configure.ac @@ -0,0 +1,256 @@ +AC_PREREQ(2.63) + +AC_INIT([hidapi],[m4_normalize(m4_builtin([include], VERSION))],[https://github.com/libusb/hidapi/issues]) + +echo "This build script for HIDAPI is deprecated." +echo "Consider using CMake instead." + +# Library soname version +# Follow the following rules (particularly the ones in the second link): +# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +# http://sourceware.org/autobook/autobook/autobook_91.html +lt_current="0" +lt_revision="0" +lt_age="0" +LTLDFLAGS="-version-info ${lt_current}:${lt_revision}:${lt_age}" + +AC_CONFIG_MACRO_DIR([m4]) +AM_INIT_AUTOMAKE([foreign -Wall -Werror]) + +m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) +LT_INIT + +AC_PROG_CC +AC_PROG_CXX +AC_PROG_OBJC +PKG_PROG_PKG_CONFIG + + +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +hidapi_lib_error() { + echo "" + echo " Library $1 was not found on this system." + echo " Please install it and re-run ./configure" + echo "" + exit 1 +} + +hidapi_prog_error() { + echo "" + echo " Program $1 was not found on this system." + echo " This program is part of $2." + echo " Please install it and re-run ./configure" + echo "" + exit 1 +} + +AC_MSG_CHECKING([operating system]) +AC_MSG_RESULT($host) +case $host in +*-linux*) + AC_MSG_RESULT([ (Linux back-end)]) + AC_DEFINE(OS_LINUX, 1, [Linux implementations]) + AC_SUBST(OS_LINUX) + backend="linux" + os="linux" + threads="pthreads" + + # HIDAPI/hidraw libs + PKG_CHECK_MODULES([libudev], [libudev], true, [hidapi_lib_error libudev]) + LIBS_HIDRAW_PR="${LIBS_HIDRAW_PR} $libudev_LIBS" + CFLAGS_HIDRAW="${CFLAGS_HIDRAW} $libudev_CFLAGS" + + # HIDAPI/libusb libs + AC_CHECK_LIB([rt], [clock_gettime], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -lrt"], [hidapi_lib_error librt]) + PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.9], true, [hidapi_lib_error libusb-1.0]) + LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} $libusb_LIBS" + CFLAGS_LIBUSB="${CFLAGS_LIBUSB} $libusb_CFLAGS" + ;; +*-darwin*) + AC_MSG_RESULT([ (Mac OS X back-end)]) + AC_DEFINE(OS_DARWIN, 1, [Mac implementation]) + AC_SUBST(OS_DARWIN) + backend="mac" + os="darwin" + threads="pthreads" + LIBS="${LIBS} -framework IOKit -framework CoreFoundation" + ;; +*-freebsd*) + AC_MSG_RESULT([ (FreeBSD back-end)]) + AC_DEFINE(OS_FREEBSD, 1, [FreeBSD implementation]) + AC_SUBST(OS_FREEBSD) + backend="libusb" + os="freebsd" + threads="pthreads" + + CFLAGS="$CFLAGS -I/usr/local/include" + LDFLAGS="$LDFLAGS -L/usr/local/lib" + LIBS="${LIBS}" + 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]) + ;; +*-kfreebsd*) + AC_MSG_RESULT([ (kFreeBSD back-end)]) + AC_DEFINE(OS_KFREEBSD, 1, [kFreeBSD implementation]) + AC_SUBST(OS_KFREEBSD) + backend="libusb" + os="kfreebsd" + 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" + ;; +*-*-haiku) + AC_MSG_RESULT([ (Haiku back-end)]) + AC_DEFINE(OS_HAIKU, 1, [Haiku implementation]) + AC_SUBST(OS_HAIKU) + backend="libusb" + os="haiku" + threads="pthreads" + + PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.9], true, [hidapi_lib_error libusb-1.0]) + LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} $libusb_LIBS" + CFLAGS_LIBUSB="${CFLAGS_LIBUSB} $libusb_CFLAGS" + AC_CHECK_LIB([iconv], [libiconv_open], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -liconv"], [hidapi_lib_error libiconv]) + ;; +*-mingw*) + AC_MSG_RESULT([ (Windows back-end, using MinGW)]) + backend="windows" + os="windows" + threads="windows" + win_implementation="mingw" + LDFLAGS="${LDFLAGS} -static-libgcc" + ;; +*-msys*) + AC_MSG_RESULT([ (Windows back-end, using MSYS2)]) + backend="windows" + os="windows" + threads="windows" + win_implementation="mingw" + LDFLAGS="${LDFLAGS} -static-libgcc" + ;; +*-cygwin*) + AC_MSG_RESULT([ (Windows back-end, using Cygwin)]) + backend="windows" + os="windows" + threads="windows" + win_implementation="cygwin" + ;; +*) + AC_MSG_ERROR([HIDAPI is not supported on your operating system yet]) +esac + +LIBS_HIDRAW="${LIBS} ${LIBS_HIDRAW_PR}" +LIBS_LIBUSB="${LIBS} ${LIBS_LIBUSB_PRIVATE}" +AC_SUBST([LIBS_HIDRAW]) +AC_SUBST([LIBS_LIBUSB]) +AC_SUBST([CFLAGS_LIBUSB]) +AC_SUBST([CFLAGS_HIDRAW]) + +if test "x$os" = xwindows; then + AC_DEFINE(OS_WINDOWS, 1, [Windows implementations]) + AC_SUBST(OS_WINDOWS) + LDFLAGS="${LDFLAGS} -no-undefined" + LIBS="${LIBS}" +fi + +if test "x$threads" = xpthreads; then + AX_PTHREAD([found_pthreads=yes], [found_pthreads=no]) + + if test "x$found_pthreads" = xyes; then + if test "x$os" = xlinux; then + # Only use pthreads for libusb implementation on Linux. + LIBS_LIBUSB="$PTHREAD_LIBS $LIBS_LIBUSB" + CFLAGS_LIBUSB="$CFLAGS_LIBUSB $PTHREAD_CFLAGS" + # There's no separate CC on Linux for threading, + # so it's ok that both implementations use $PTHREAD_CC + CC="$PTHREAD_CC" + else + LIBS="$PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + CC="$PTHREAD_CC" + fi + fi +fi + +# Test GUI +AC_ARG_ENABLE([testgui], + [AS_HELP_STRING([--enable-testgui], + [enable building of test GUI (default n)])], + [testgui_enabled=$enableval], + [testgui_enabled='no']) +AM_CONDITIONAL([BUILD_TESTGUI], [test "x$testgui_enabled" != "xno"]) + +# Configure the MacOS TestGUI app bundle +rm -Rf testgui/TestGUI.app +mkdir -p testgui/TestGUI.app +cp -R ${srcdir}/testgui/TestGUI.app.in/* testgui/TestGUI.app +chmod -R u+w testgui/TestGUI.app +mkdir testgui/TestGUI.app/Contents/MacOS/ + +if test "x$testgui_enabled" != "xno"; then + if test "x$os" = xdarwin; then + # On Mac OS, do not use pkg-config. + AC_CHECK_PROG([foxconfig], [fox-config], [fox-config], false) + if test "x$foxconfig" = "xfalse"; then + hidapi_prog_error fox-config "FOX Toolkit" + fi + LIBS_TESTGUI="${LIBS_TESTGUI} `$foxconfig --libs`" + LIBS_TESTGUI="${LIBS_TESTGUI} -framework Cocoa -L/usr/X11R6/lib" + CFLAGS_TESTGUI="${CFLAGS_TESTGUI} `$foxconfig --cflags`" + OBJCFLAGS="${OBJCFLAGS} -x objective-c++" + elif test "x$os" = xwindows; then + # On Windows, just set the paths for Fox toolkit + if test "x$win_implementation" = xmingw; then + CFLAGS_TESTGUI="-I\$(srcdir)/../../hidapi-externals/fox/include -g -c" + LIBS_TESTGUI=" -mwindows \$(srcdir)/../../hidapi-externals/fox/lib/libFOX-1.6.a -lgdi32 -Wl,--enable-auto-import -static-libgcc -static-libstdc++ -lkernel32" + else + # Cygwin + CFLAGS_TESTGUI="-DWIN32 -I\$(srcdir)/../../hidapi-externals/fox/include -g -c" + LIBS_TESTGUI="\$(srcdir)/../../hidapi-externals/fox/lib/libFOX-cygwin-1.6.a -lgdi32 -Wl,--enable-auto-import -static-libgcc -static-libstdc++ -lkernel32" + fi + else + # On Linux and FreeBSD platforms, use pkg-config to find fox. + PKG_CHECK_MODULES([fox], [fox17], [], [PKG_CHECK_MODULES([fox], [fox])]) + LIBS_TESTGUI="${LIBS_TESTGUI} $fox_LIBS" + if test "x$os" = xfreebsd; then + LIBS_TESTGUI="${LIBS_TESTGUI} -L/usr/local/lib" + fi + CFLAGS_TESTGUI="${CFLAGS_TESTGUI} $fox_CFLAGS" + fi +fi +AC_SUBST([LIBS_TESTGUI]) +AC_SUBST([CFLAGS_TESTGUI]) +AC_SUBST([backend]) + +# OS info for Automake +AM_CONDITIONAL(OS_LINUX, test "x$os" = xlinux) +AM_CONDITIONAL(OS_DARWIN, test "x$os" = xdarwin) +AM_CONDITIONAL(OS_FREEBSD, test "x$os" = xfreebsd) +AM_CONDITIONAL(OS_KFREEBSD, test "x$os" = xkfreebsd) +AM_CONDITIONAL(OS_HAIKU, test "x$os" = xhaiku) +AM_CONDITIONAL(OS_WINDOWS, test "x$os" = xwindows) + +AC_CONFIG_HEADERS([config.h]) + +if test "x$os" = "xlinux"; then + AC_CONFIG_FILES([pc/hidapi-hidraw.pc]) + AC_CONFIG_FILES([pc/hidapi-libusb.pc]) +else + AC_CONFIG_FILES([pc/hidapi.pc]) +fi + +AC_SUBST(LTLDFLAGS) + +AC_CONFIG_FILES([Makefile \ + hidtest/Makefile \ + libusb/Makefile \ + linux/Makefile \ + mac/Makefile \ + testgui/Makefile \ + windows/Makefile]) +AC_OUTPUT diff --git a/contrib/SDL-3.2.8/src/hidapi/dist/hidapi.podspec b/contrib/SDL-3.2.8/src/hidapi/dist/hidapi.podspec new file mode 100644 index 0000000..8588514 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/dist/hidapi.podspec @@ -0,0 +1,31 @@ +Pod::Spec.new do |spec| + + spec.name = "hidapi" + spec.version = File.read('../VERSION') + spec.summary = "A Simple library for communicating with USB and Bluetooth HID devices on Linux, Mac and Windows." + + spec.description = <<-DESC + HIDAPI is a multi-platform library which allows an application to interface with USB and Bluetooth HID-Class devices on Windows, Linux, FreeBSD, and macOS. HIDAPI can be either built as a shared library (.so, .dll or .dylib) or can be embedded directly into a target application by adding a single source file (per platform) and a single header. + DESC + + spec.homepage = "https://github.com/libusb/hidapi" + + spec.license = { :type=> "GNU GPLv3 or BSD or HIDAPI original", :file => "LICENSE.txt" } + + spec.authors = { "Alan Ott" => "alan@signal11.us", + "Ludovic Rousseau" => "rousseau@debian.org", + "libusb/hidapi Team" => "https://github.com/libusb/hidapi/blob/master/AUTHORS.txt", + } + + spec.platform = :osx + spec.osx.deployment_target = "10.7" + + spec.source = { :git => "https://github.com/libusb/hidapi.git", :tag => "hidapi-#{spec.version}" } + + spec.source_files = "mac/hid.c", "hidapi/hidapi.h", "mac/hidapi_darwin.h" + + spec.public_header_files = "hidapi/hidapi.h", "mac/hidapi_darwin.h" + + spec.frameworks = "IOKit", "CoreFoundation" + +end diff --git a/contrib/SDL-3.2.8/src/hidapi/documentation/cmake-gui-drop-down.png b/contrib/SDL-3.2.8/src/hidapi/documentation/cmake-gui-drop-down.png new file mode 100644 index 0000000..548abe8 Binary files /dev/null and b/contrib/SDL-3.2.8/src/hidapi/documentation/cmake-gui-drop-down.png differ diff --git a/contrib/SDL-3.2.8/src/hidapi/documentation/cmake-gui-highlights.png b/contrib/SDL-3.2.8/src/hidapi/documentation/cmake-gui-highlights.png new file mode 100644 index 0000000..228838f Binary files /dev/null and b/contrib/SDL-3.2.8/src/hidapi/documentation/cmake-gui-highlights.png differ diff --git a/contrib/SDL-3.2.8/src/hidapi/doxygen/Doxyfile b/contrib/SDL-3.2.8/src/hidapi/doxygen/Doxyfile new file mode 100644 index 0000000..b0bc233 --- /dev/null +++ b/contrib/SDL-3.2.8/src/hidapi/doxygen/Doxyfile @@ -0,0 +1,2724 @@ +# Doxyfile 1.9.6 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = hidapi + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = ../ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:^^" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = NO + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about +# undocumented enumeration values. If set to NO, doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ../hidapi \ + ./main_page.md + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding +# "INPUT_ENCODING" for further information on supported encodings. + +INPUT_FILE_ENCODING = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# ANamespace::AClass, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = HID_API_AS_STR_IMPL \ + HID_API_AS_STR \ + HID_API_TO_VERSION_STR + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = ../hidtest + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = *.c + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = main_page.md + +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. +# The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_ADD_INC_PATHS = YES + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generate light mode output, DARK always +# generate dark mode output, AUTO_LIGHT automatically set the mode according to +# the user preference, use light mode if no preference is set (the default), +# AUTO_DARK automatically set the mode according to the user preference, use +# dark mode if no preference is set and TOGGLE allow to user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = AUTO_LIGHT + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use gray-scales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /