├── .gitignore.txt ├── Info.plist ├── LICENSE ├── QJoyControl.pro ├── README.md ├── eventhandler.h ├── hidapi ├── .appveyor.yml ├── .builds │ ├── alpine.yml │ ├── archlinux.yml │ ├── fedora-mingw.yml │ └── freebsd.yml ├── .gitattributes ├── .gitignore ├── .travis.yml ├── AUTHORS.txt ├── HACKING.txt ├── LICENSE-bsd.txt ├── LICENSE-gpl3.txt ├── LICENSE-orig.txt ├── LICENSE.txt ├── Makefile.am ├── README.md ├── android │ └── jni │ │ └── Android.mk ├── bootstrap ├── configure.ac ├── dist │ └── hidapi.podspec ├── doxygen │ └── Doxyfile ├── hidapi │ └── hidapi.h ├── hidtest │ ├── .gitignore │ ├── Makefile.am │ └── test.c ├── libusb │ ├── .gitignore │ ├── Makefile-manual │ ├── Makefile.am │ ├── Makefile.freebsd │ ├── Makefile.linux │ └── hid.c ├── linux │ ├── .gitignore │ ├── Makefile-manual │ ├── Makefile.am │ └── hid.c ├── m4 │ ├── .gitignore │ ├── ax_pthread.m4 │ └── pkg.m4 ├── mac │ ├── .gitignore │ ├── Makefile-manual │ ├── Makefile.am │ ├── hid.c │ └── hidtest ├── pc │ ├── .gitignore │ ├── hidapi-hidraw.pc.in │ ├── hidapi-libusb.pc.in │ └── hidapi.pc.in ├── testgui │ ├── .gitignore │ ├── Makefile-manual │ ├── Makefile.am │ ├── Makefile.freebsd │ ├── Makefile.linux │ ├── Makefile.mac │ ├── Makefile.mingw │ ├── TestGUI.app.in │ │ └── Contents │ │ │ ├── Info.plist │ │ │ ├── PkgInfo │ │ │ └── Resources │ │ │ ├── English.lproj │ │ │ └── InfoPlist.strings │ │ │ └── Signal11.icns │ ├── copy_to_bundle.sh │ ├── mac_support.h │ ├── mac_support_cocoa.m │ ├── test.cpp │ ├── testgui.sln │ └── testgui.vcproj ├── udev │ └── 99-hid.rules └── windows │ ├── .gitignore │ ├── Makefile-manual │ ├── Makefile.am │ ├── Makefile.mingw │ ├── ddk_build │ ├── .gitignore │ ├── hidapi.def │ └── sources │ ├── hid.c │ ├── hidapi.sln │ ├── hidapi.vcproj │ ├── hidapi.vcxproj │ ├── hidtest.vcproj │ └── hidtest.vcxproj ├── img ├── Logo.icns ├── Logo.png ├── Logo.svg ├── batt_0.png ├── batt_0_chr.png ├── batt_100.png ├── batt_100_chr.png ├── batt_25.png ├── batt_25_chr.png ├── batt_50.png ├── batt_50_chr.png ├── batt_75.png ├── batt_75_chr.png └── retail_colors.xml ├── inputmappanel.cpp ├── inputmappanel.h ├── inputmappanel.ui ├── inputmapwidget.cpp ├── inputmapwidget.h ├── inputmapwidget.ui ├── ir_sensor.h ├── joyconworker.cpp ├── joyconworker.h ├── linux ├── .gitignore └── eventhandler_linux.cpp ├── luts.h ├── mac ├── .gitignore ├── eventhandler_macos.cpp ├── powertools.h └── powertools.mm ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h ├── mainwindow.ui ├── resources.qrc ├── statuswidget.cpp ├── statuswidget.h └── statuswidget.ui /.gitignore.txt: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | *.slo 3 | *.lo 4 | *.o 5 | *.a 6 | *.la 7 | *.lai 8 | *.so 9 | *.so.* 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | object_script.*.Release 15 | object_script.*.Debug 16 | *_plugin_import.cpp 17 | /.qmake.cache 18 | /.qmake.stash 19 | *.pro.user 20 | *.pro.user.* 21 | *.qbs.user 22 | *.qbs.user.* 23 | *.moc 24 | moc_*.cpp 25 | moc_*.h 26 | qrc_*.cpp 27 | ui_*.h 28 | *.qmlc 29 | *.jsc 30 | Makefile* 31 | *build-* 32 | *.qm 33 | *.prl 34 | 35 | # Qt unit tests 36 | target_wrapper.* 37 | 38 | # QtCreator 39 | *.autosave 40 | 41 | # QtCreator Qml 42 | *.qmlproject.user 43 | *.qmlproject.user.* 44 | 45 | # QtCreator CMake 46 | CMakeLists.txt.user* 47 | 48 | # QtCreator 4.8< compilation database 49 | compile_commands.json 50 | 51 | # QtCreator local machine specific files for imported projects 52 | *creator.user* -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleExecutable 6 | QJoyControl 7 | CFBundleGetInfoString 8 | Created by Qt/QMake 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.yourcompany.QJoyControl 13 | CFBundlePackageType 14 | APPL 15 | CFBundleSignature 16 | ???? 17 | LSMinimumSystemVersion 18 | 10.12 19 | LSUIElement 20 | 1 21 | NOTE 22 | This file was generated by Qt/QMake. 23 | NSPrincipalClass 24 | NSApplication 25 | NSSupportsAutomaticGraphicsSwitching 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Erik Werner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /QJoyControl.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by Erik Werner 2018-09-22T21:09:40 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui widgets 8 | 9 | TARGET = QJoyControl 10 | TEMPLATE = app 11 | 12 | VERSION = 0.2 13 | QMAKE_TARGET_PRODUCT = "QJoyControl" 14 | QMAKE_TARGET_COMPANY = "UntitledSoftware" 15 | 16 | DEFINES += APP_VERSION=\"\\\"$${VERSION}\\\"\" \ 17 | APP_PRODUCT=\"\\\"$${QMAKE_TARGET_PRODUCT}\\\"\" \ 18 | APP_COMPANY=\"\\\"$${QMAKE_TARGET_COMPANY}\\\"\" 19 | 20 | 21 | # With C++11 support 22 | greaterThan(QT_MAJOR_VERSION, 4){ 23 | CONFIG += c++11 24 | } else { 25 | QMAKE_CXXFLAGS += -std=c++0x 26 | } 27 | 28 | INCLUDEPATH += hidapi/hidapi 29 | 30 | SOURCES += \ 31 | inputmappanel.cpp \ 32 | inputmapwidget.cpp \ 33 | main.cpp \ 34 | mainwindow.cpp \ 35 | joyconworker.cpp \ 36 | statuswidget.cpp 37 | 38 | 39 | 40 | HEADERS += \ 41 | inputmappanel.h \ 42 | inputmapwidget.h \ 43 | mainwindow.h \ 44 | joyconworker.h \ 45 | luts.h \ 46 | ir_sensor.h \ 47 | statuswidget.h \ 48 | eventhandler.h \ 49 | hidapi/hidapi/hidapi.h 50 | 51 | FORMS += \ 52 | inputmappanel.ui \ 53 | inputmapwidget.ui \ 54 | mainwindow.ui \ 55 | statuswidget.ui 56 | 57 | macx { 58 | CONFIG += app_bundle 59 | QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7 60 | ICON = img/Logo.icns 61 | 62 | # use custom plist to hide dock icon 63 | #QMAKE_INFO_PLIST = Info.plist 64 | 65 | # for homebrew hidapi installation 66 | #HIDAPI_PATH = /usr/local/Cellar/hidapi/0.9.0 67 | #INCLUDEPATH += $$HIDAPI_PATH/include/hidapi 68 | 69 | # use local hidapi installation 70 | SOURCES += hidapi/mac/hid.c 71 | HIDAPI_PATH = $$PWD/hidapi/mac 72 | INCLUDEPATH += $$HIDAPI_PATH 73 | 74 | #prevent app nap from sleeping threads 75 | INCLUDEPATH += $$PWD/mac 76 | HEADERS += mac/powertools.h 77 | OBJECTIVE_SOURCES += mac/powertools.mm 78 | LIBS += -framework Foundation 79 | 80 | # include hidapi dynamic library 81 | #LIBS += $$HIDAPI_PATH/lib/libhidapi.dylib 82 | 83 | # include power management libs 84 | LIBS += -framework CoreFoundation -framework IOkit 85 | 86 | # include system event services Mac 87 | LIBS += -framework ApplicationServices 88 | SOURCES += mac/eventhandler_macos.cpp 89 | } 90 | 91 | unix:!macx { 92 | SOURCES += linux/hid-libusb.c 93 | LIBS += -lusb-1.0 94 | # include system event services Linux 95 | #unix: !macx: LIB += 96 | SOURCES += eventhandler_linux.cpp 97 | } 98 | 99 | win32 { 100 | # include system event services Windows 101 | #win32: LIB += 102 | SOURCES += eventhandler_win.cpp 103 | SOURCES += windows/hid.cpp 104 | LIBS += -lSetupAPI 105 | } 106 | 107 | RESOURCES += \ 108 | resources.qrc 109 | 110 | # Default rules for deployment. 111 | qnx: target.path = /tmp/$${TARGET}/bin 112 | else: unix:!android: target.path = /opt/$${TARGET}/bin 113 | !isEmpty(target.path): INSTALLS += target 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QJoyControl 2 | QJoyControl lets you use Nintendo Switch JoyCons as input devices on your computer. It was originally made to use a JoyCon as a PowerPoint remote, but it accumulated a few extra features along the way. Currently, QJoyControl supports: 3 | * JoyCons and Pro Controller 4 | * Mouse control with analog sticks and gyroscope 5 | * Adjustable mouse sensitivity 6 | * Configurable button-to-key mapping 7 | * Image capture with the IR Camera 8 | * Rumble and player LED commands 9 | 10 | It also works pretty well as a PowerPoint remote. 11 | 12 | ## Setup 13 | 1. Pair the JoyCon with your computer and connect to it with bluetooth 14 | * To pair, press the pairing button on the JoyCon and go to Bluetooth Preferences on your Mac 15 | 2. Open QJoyControl and select the JoyCon from the device list 16 | * If nothing shows up, make sure the JoyCon is paired and connected and click Refresh to check again 17 | 3. Click Connect to begin streaming input data 18 | 19 | If MacOS does not ask to give QJoyControl permission to control your computer, you may need to go into System Preferences and do it manually before keyboard and mouse inputs will register with MacOS. To do this, go to System Preferences, Security & Privacy > Privacy > Accessibility. From there, click the lock icon in the bottom-left corner, enter you password to unlock, click the plus button, and select QJoyControl to add QJoyControl to the list of approved applications. 20 | 21 | ## Compatibility 22 | QJoyControl should work on MacOS 10.7 and later, although it has only been tested on MacOS 10.13 and 10.14. QJoyControl was written with Qt and [hidapi](https://github.com/signal11/hidapi) for cross-platform support. It should eventually work on MacOS, Windows, and Linux, but at the moment only MacOS support is implemented. 23 | 24 | ## Thanks 25 | * All of the HID communication came from the hard work at [JoyCon Reverse Engineering](https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering) 26 | * The IR camera features came from the excellent [Joy-Con Toolkit](https://github.com/CTCaer/jc_toolkit) 27 | 28 | ## Disclaimer 29 | This project is not endorsed by, affiliated with, maintained, authorized, or sponsored by Nintendo. All product and company names are the registered trademarks of their original owners. The use of any trade name or trademark is for identification and reference purposes only and does not imply any association with the trademark holder of their product brand. 30 | -------------------------------------------------------------------------------- /eventhandler.h: -------------------------------------------------------------------------------- 1 | #ifndef EVENTHANDLER_H 2 | #define EVENTHANDLER_H 3 | 4 | #include 5 | #include 6 | 7 | /*! 8 | * \brief The JOYCON_BUTTONS enum is used to mask 9 | * button status from the bytes of a standard input report 10 | * the joycons 11 | */ 12 | enum JOYCON_BUTTONS : int { 13 | // byte 3: 14 | R_BUT_Y = 1, 15 | R_BUT_X = 2, 16 | R_BUT_B = 4, 17 | R_BUT_A = 8, 18 | R_BUT_SR = 16, 19 | R_BUT_SL = 32, 20 | R_BUT_R = 64, 21 | R_BUT_ZR = 128, 22 | // byte 4:, & with 256 for key mapping 23 | L_BUT_MINUS= 1, 24 | R_BUT_PLUS = 2, 25 | R_BUT_STICK = 4, 26 | L_BUT_STICK = 8, 27 | R_BUT_HOME = 16, 28 | L_BUT_CAP = 32, 29 | // 64 is unused 30 | CHARGE_GRIP = 128, 31 | // byte 5:, & with 512 for key mapping 32 | L_BUT_DOWN = 1, 33 | L_BUT_UP = 2, 34 | L_BUT_RIGHT = 4, 35 | L_BUT_LEFT = 8, 36 | L_BUT_SR = 16, 37 | L_BUT_SL = 32, 38 | L_BUT_L = 64, 39 | L_BUT_ZL = 128 40 | }; 41 | 42 | class EventHandler 43 | { 44 | public: 45 | EventHandler(); 46 | void handleMouseMove(double dx, double dy); 47 | void handleButtonPress(int button_mask); 48 | void handleButtonRelease(int button_mask); 49 | void addMapping(int from, int to); 50 | void mapToMouseButton(int mask, int button); 51 | 52 | private: 53 | //< a map to lookup OS button press from JoyCon buttom press 54 | //< JoyCon buttons from byte 4 are & with 256 55 | //< JoyCon buttons from byte 5 are & with 512 56 | QMap keyCodeMap; 57 | QMap qt_to_cg; 58 | bool _left_button_down = false; 59 | bool _right_button_down = false; 60 | }; 61 | 62 | #endif // EVENTHANDLER_H 63 | -------------------------------------------------------------------------------- /hidapi/.appveyor.yml: -------------------------------------------------------------------------------- 1 | os: Visual Studio 2015 2 | 3 | environment: 4 | matrix: 5 | - BUILD_ENV: msbuild 6 | arch: x64 7 | - BUILD_ENV: msbuild 8 | arch: Win32 9 | - BUILD_ENV: cygwin 10 | 11 | install: 12 | - cmd: if %BUILD_ENV%==cygwin ( 13 | C:\cygwin64\setup-x86_64.exe --quiet-mode --no-shortcuts --upgrade-also --packages autoconf,automake ) 14 | 15 | build_script: 16 | - cmd: if %BUILD_ENV%==msbuild ( 17 | msbuild .\windows\hidapi.sln /p:Configuration=Release /p:Platform=%arch% /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" ) 18 | - cmd: if %BUILD_ENV%==cygwin ( 19 | C:\cygwin64\bin\bash -exlc "cd $APPVEYOR_BUILD_FOLDER; ./bootstrap; ./configure; make" ) 20 | 21 | artifacts: 22 | # Win32 artifacts 23 | - path: .\windows\Release\hidapi.dll 24 | - path: .\windows\Release\hidapi.lib 25 | - path: .\windows\Release\hidapi.pdb 26 | - path: .\windows\Release\hidtest.exe 27 | - path: .\windows\Release\hidtest.pdb 28 | # x64 artifacts 29 | - path: .\windows\x64\Release\hidapi.dll 30 | - path: .\windows\x64\Release\hidapi.lib 31 | - path: .\windows\x64\Release\hidapi.pdb 32 | - path: .\windows\x64\Release\hidtest.exe 33 | - path: .\windows\x64\Release\hidtest.pdb 34 | -------------------------------------------------------------------------------- /hidapi/.builds/alpine.yml: -------------------------------------------------------------------------------- 1 | image: alpine/edge 2 | packages: 3 | - autoconf 4 | - automake 5 | - libtool 6 | - eudev-dev 7 | - libusb-dev 8 | - linux-headers 9 | sources: 10 | - https://github.com/libusb/hidapi 11 | tasks: 12 | - setup: | 13 | cd hidapi 14 | ./bootstrap 15 | ./configure 16 | - build: | 17 | cd hidapi 18 | make 19 | make DESTDIR=$PWD/root install 20 | -------------------------------------------------------------------------------- /hidapi/.builds/archlinux.yml: -------------------------------------------------------------------------------- 1 | image: archlinux 2 | sources: 3 | - https://github.com/libusb/hidapi 4 | tasks: 5 | - setup: | 6 | cd hidapi 7 | ./bootstrap 8 | ./configure 9 | - build: | 10 | cd hidapi 11 | make 12 | make DESTDIR=$PWD/root install 13 | -------------------------------------------------------------------------------- /hidapi/.builds/fedora-mingw.yml: -------------------------------------------------------------------------------- 1 | image: fedora/latest 2 | packages: 3 | - autoconf 4 | - automake 5 | - libtool 6 | - mingw64-gcc 7 | - mingw64-gcc-c++ 8 | sources: 9 | - https://github.com/libusb/hidapi 10 | tasks: 11 | - setup: | 12 | cd hidapi 13 | ./bootstrap 14 | mingw64-configure 15 | - build: | 16 | cd hidapi 17 | make 18 | make DESTDIR=$PWD/root install 19 | -------------------------------------------------------------------------------- /hidapi/.builds/freebsd.yml: -------------------------------------------------------------------------------- 1 | image: freebsd/latest 2 | packages: 3 | - autoconf 4 | - automake 5 | - libiconv 6 | - libtool 7 | - pkgconf 8 | sources: 9 | - https://github.com/libusb/hidapi 10 | tasks: 11 | - setup: | 12 | cd hidapi 13 | ./bootstrap 14 | ./configure 15 | - build: | 16 | cd hidapi 17 | make 18 | make DESTDIR=$PWD/root install 19 | -------------------------------------------------------------------------------- /hidapi/.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | *.sln text eol=crlf 4 | *.vcproj text eol=crlf 5 | 6 | bootstrap text eol=lf 7 | configure.ac text eol=lf 8 | -------------------------------------------------------------------------------- /hidapi/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Autotools-added generated files 3 | Makefile.in 4 | aclocal.m4 5 | ar-lib 6 | autom4te.cache/ 7 | config.* 8 | configure 9 | compile 10 | depcomp 11 | install-sh 12 | libusb/Makefile.in 13 | linux/Makefile.in 14 | ltmain.sh 15 | mac/Makefile.in 16 | missing 17 | testgui/Makefile.in 18 | windows/Makefile.in 19 | 20 | Makefile 21 | stamp-h1 22 | libtool 23 | -------------------------------------------------------------------------------- /hidapi/.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | 3 | os: osx 4 | osx_image: xcode10.2 5 | 6 | script: 7 | - ./bootstrap 8 | - ./configure 9 | - make 10 | - make DESTDIR=$PWD/root install 11 | -------------------------------------------------------------------------------- /hidapi/AUTHORS.txt: -------------------------------------------------------------------------------- 1 | 2 | HIDAPI Authors: 3 | 4 | Alan Ott : 5 | Original Author and Maintainer 6 | Linux, Windows, and Mac implementations 7 | 8 | Ludovic Rousseau : 9 | Formatting for Doxygen documentation 10 | Bug fixes 11 | Correctness fixes 12 | 13 | libusb/hidapi Team: 14 | Development/maintainance since June 4th 2019 15 | 16 | For a comprehensive list of contributions, see the commit list at github: 17 | https://github.com/libusb/hidapi/commits/master 18 | 19 | -------------------------------------------------------------------------------- /hidapi/HACKING.txt: -------------------------------------------------------------------------------- 1 | This file is mostly for the maintainer. 2 | 3 | 1. Build hidapi.dll 4 | 2. Build hidtest.exe in DEBUG and RELEASE 5 | 3. Commit all 6 | 7 | 4. Run the Following 8 | export VERSION=0.1.0 9 | export TAG_NAME=hidapi-$VERSION 10 | git tag $TAG_NAME 11 | git archive --format zip --prefix $TAG_NAME/ $TAG_NAME >../$TAG_NAME.zip 12 | 5. Test the zip file. 13 | 6. Run the following: 14 | git push origin $TAG_NAME 15 | 16 | -------------------------------------------------------------------------------- /hidapi/LICENSE-bsd.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Alan Ott, Signal 11 Software 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of Signal 11 Software nor the names of its 13 | contributors may be used to endorse or promote products derived from 14 | this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /hidapi/LICENSE-orig.txt: -------------------------------------------------------------------------------- 1 | HIDAPI - Multi-Platform library for 2 | communication with HID devices. 3 | 4 | Copyright 2009, Alan Ott, Signal 11 Software. 5 | All Rights Reserved. 6 | 7 | This software may be used by anyone for any reason so 8 | long as the copyright notice in the source files 9 | remains intact. 10 | -------------------------------------------------------------------------------- /hidapi/LICENSE.txt: -------------------------------------------------------------------------------- 1 | HIDAPI can be used under one of three licenses. 2 | 3 | 1. The GNU General Public License, version 3.0, in LICENSE-gpl3.txt 4 | 2. A BSD-Style License, in LICENSE-bsd.txt. 5 | 3. The more liberal original HIDAPI license. LICENSE-orig.txt 6 | 7 | The license chosen is at the discretion of the user of HIDAPI. For example: 8 | 1. An author of GPL software would likely use HIDAPI under the terms of the 9 | GPL. 10 | 11 | 2. An author of commercial closed-source software would likely use HIDAPI 12 | under the terms of the BSD-style license or the original HIDAPI license. 13 | 14 | -------------------------------------------------------------------------------- /hidapi/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | ACLOCAL_AMFLAGS = -I m4 3 | 4 | if OS_FREEBSD 5 | pkgconfigdir=$(prefix)/libdata/pkgconfig 6 | else 7 | pkgconfigdir=$(libdir)/pkgconfig 8 | endif 9 | 10 | if OS_LINUX 11 | pkgconfig_DATA=pc/hidapi-hidraw.pc pc/hidapi-libusb.pc 12 | else 13 | pkgconfig_DATA=pc/hidapi.pc 14 | endif 15 | 16 | SUBDIRS= 17 | 18 | if OS_LINUX 19 | SUBDIRS += linux libusb 20 | endif 21 | 22 | if OS_DARWIN 23 | SUBDIRS += mac 24 | endif 25 | 26 | if OS_FREEBSD 27 | SUBDIRS += libusb 28 | endif 29 | 30 | if OS_KFREEBSD 31 | SUBDIRS += libusb 32 | endif 33 | 34 | if OS_WINDOWS 35 | SUBDIRS += windows 36 | endif 37 | 38 | SUBDIRS += hidtest 39 | 40 | if BUILD_TESTGUI 41 | SUBDIRS += testgui 42 | endif 43 | 44 | EXTRA_DIST = udev doxygen 45 | 46 | dist_doc_DATA = \ 47 | README.md \ 48 | AUTHORS.txt \ 49 | LICENSE-bsd.txt \ 50 | LICENSE-gpl3.txt \ 51 | LICENSE-orig.txt \ 52 | LICENSE.txt 53 | 54 | SCMCLEAN_TARGETS= \ 55 | aclocal.m4 \ 56 | config.guess \ 57 | config.sub \ 58 | configure \ 59 | config.h.in \ 60 | depcomp \ 61 | install-sh \ 62 | ltmain.sh \ 63 | missing \ 64 | mac/Makefile.in \ 65 | testgui/Makefile.in \ 66 | libusb/Makefile.in \ 67 | Makefile.in \ 68 | linux/Makefile.in \ 69 | windows/Makefile.in \ 70 | m4/libtool.m4 \ 71 | m4/lt~obsolete.m4 \ 72 | m4/ltoptions.m4 \ 73 | m4/ltsugar.m4 \ 74 | m4/ltversion.m4 75 | 76 | SCMCLEAN_DIR_TARGETS = \ 77 | autom4te.cache 78 | 79 | scm-clean: distclean 80 | rm -f $(SCMCLEAN_TARGETS) 81 | rm -Rf $(SCMCLEAN_DIR_TARGETS) 82 | -------------------------------------------------------------------------------- /hidapi/README.md: -------------------------------------------------------------------------------- 1 | ## HIDAPI library for Windows, Linux, FreeBSD and macOS 2 | 3 | | CI instance | Status | 4 | |----------------------|--------| 5 | | `macOS master` | [![Build Status](https://travis-ci.org/libusb/hidapi.svg?branch=master)](https://travis-ci.org/libusb/hidapi) | 6 | | `Windows master` | [![Build status](https://ci.appveyor.com/api/projects/status/r482aevuigmi86rk/branch/master?svg=true)](https://ci.appveyor.com/project/Youw/hidapi/branch/master) | 7 | | `Linux/BSD, last build (branch/PR)` | [![builds.sr.ht status](https://builds.sr.ht/~qbicz/hidapi.svg)](https://builds.sr.ht/~qbicz/hidapi?) | 8 | 9 | HIDAPI is a multi-platform library which allows an application to interface 10 | with USB and Bluetooth HID-Class devices on Windows, Linux, FreeBSD, and macOS. 11 | HIDAPI can be either built as a shared library (`.so`, `.dll` or `.dylib`) or 12 | can be embedded directly into a target application by adding a single source 13 | file (per platform) and a single header. 14 | 15 | HIDAPI library was originally developed by Alan Ott ([signal11](https://github.com/signal11)). 16 | 17 | 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. 18 | 19 | ## Table of Contents 20 | 21 | * [About](#about) 22 | * [What Does the API Look Like?](#what-does-the-api-look-like) 23 | * [License](#license) 24 | * [Download](#download) 25 | * [Build Instructions](#build-instructions) 26 | * [Prerequisites](#prerequisites) 27 | * [Linux](#linux) 28 | * [FreeBSD](#freebsd) 29 | * [Mac](#mac) 30 | * [Windows](#windows) 31 | * [Building HIDAPI into a shared library on Unix Platforms](#building-hidapi-into-a-shared-library-on-unix-platforms) 32 | * [Building the manual way on Unix platforms](#building-the-manual-way-on-unix-platforms) 33 | * [Building on Windows](#building-on-windows) 34 | * [Cross Compiling](#cross-compiling) 35 | * [Prerequisites](#prerequisites-1) 36 | * [Building HIDAPI](#building-hidapi) 37 | 38 | ## About 39 | 40 | HIDAPI has five back-ends: 41 | * Windows (using `hid.dll`) 42 | * Linux/hidraw (using the Kernel's hidraw driver) 43 | * Linux/libusb (using libusb-1.0) 44 | * FreeBSD (using libusb-1.0) 45 | * Mac (using IOHidManager) 46 | 47 | On Linux, either the hidraw or the libusb back-end can be used. There are 48 | tradeoffs, and the functionality supported is slightly different. 49 | 50 | __Linux/hidraw__ (`linux/hid.c`): 51 | 52 | This back-end uses the hidraw interface in the Linux kernel, and supports 53 | both USB and Bluetooth HID devices. It requires kernel version at least 2.6.39 54 | to build. In addition, it will only communicate with devices which have hidraw 55 | nodes associated with them. 56 | Keyboards, mice, and some other devices which are blacklisted from having 57 | hidraw nodes will not work. Fortunately, for nearly all the uses of hidraw, 58 | this is not a problem. 59 | 60 | __Linux/FreeBSD/libusb__ (`libusb/hid.c`): 61 | 62 | This back-end uses libusb-1.0 to communicate directly to a USB device. This 63 | back-end will of course not work with Bluetooth devices. 64 | 65 | HIDAPI also comes with a Test GUI. The Test GUI is cross-platform and uses 66 | Fox Toolkit . It will build on every platform 67 | which HIDAPI supports. Since it relies on a 3rd party library, building it 68 | is optional but recommended because it is so useful when debugging hardware. 69 | 70 | ## What Does the API Look Like? 71 | The API provides the most commonly used HID functions including sending 72 | and receiving of input, output, and feature reports. The sample program, 73 | which communicates with a heavily hacked up version of the Microchip USB 74 | Generic HID sample looks like this (with error checking removed for 75 | simplicity): 76 | 77 | **Warning: Only run the code you understand, and only when it conforms to the 78 | device spec. Writing data at random to your HID devices can break them.** 79 | 80 | ```c 81 | #ifdef WIN32 82 | #include 83 | #endif 84 | #include 85 | #include 86 | #include "hidapi.h" 87 | 88 | #define MAX_STR 255 89 | 90 | int main(int argc, char* argv[]) 91 | { 92 | int res; 93 | unsigned char buf[65]; 94 | wchar_t wstr[MAX_STR]; 95 | hid_device *handle; 96 | int i; 97 | 98 | // Initialize the hidapi library 99 | res = hid_init(); 100 | 101 | // Open the device using the VID, PID, 102 | // and optionally the Serial number. 103 | handle = hid_open(0x4d8, 0x3f, NULL); 104 | 105 | // Read the Manufacturer String 106 | res = hid_get_manufacturer_string(handle, wstr, MAX_STR); 107 | wprintf(L"Manufacturer String: %s\n", wstr); 108 | 109 | // Read the Product String 110 | res = hid_get_product_string(handle, wstr, MAX_STR); 111 | wprintf(L"Product String: %s\n", wstr); 112 | 113 | // Read the Serial Number String 114 | res = hid_get_serial_number_string(handle, wstr, MAX_STR); 115 | wprintf(L"Serial Number String: (%d) %s\n", wstr[0], wstr); 116 | 117 | // Read Indexed String 1 118 | res = hid_get_indexed_string(handle, 1, wstr, MAX_STR); 119 | wprintf(L"Indexed String 1: %s\n", wstr); 120 | 121 | // Toggle LED (cmd 0x80). The first byte is the report number (0x0). 122 | buf[0] = 0x0; 123 | buf[1] = 0x80; 124 | res = hid_write(handle, buf, 65); 125 | 126 | // Request state (cmd 0x81). The first byte is the report number (0x0). 127 | buf[0] = 0x0; 128 | buf[1] = 0x81; 129 | res = hid_write(handle, buf, 65); 130 | 131 | // Read requested state 132 | res = hid_read(handle, buf, 65); 133 | 134 | // Print out the returned buffer. 135 | for (i = 0; i < 4; i++) 136 | printf("buf[%d]: %d\n", i, buf[i]); 137 | 138 | // Close the device 139 | hid_close(handle); 140 | 141 | // Finalize the hidapi library 142 | res = hid_exit(); 143 | 144 | return 0; 145 | } 146 | ``` 147 | 148 | You can also use [hidtest/test.c](hidtest/test.c) 149 | as a starting point for your applications. 150 | 151 | 152 | ## License 153 | HIDAPI may be used by one of three licenses as outlined in [LICENSE.txt](LICENSE.txt). 154 | 155 | ## Download 156 | HIDAPI can be downloaded from GitHub 157 | ```sh 158 | git clone git://github.com/libusb/hidapi.git 159 | ``` 160 | 161 | ## Build Instructions 162 | 163 | This section is long. Don't be put off by this. It's not long because it's 164 | complicated to build HIDAPI; it's quite the opposite. This section is long 165 | because of the flexibility of HIDAPI and the large number of ways in which 166 | it can be built and used. You will likely pick a single build method. 167 | 168 | HIDAPI can be built in several different ways. If you elect to build a 169 | shared library, you will need to build it from the HIDAPI source 170 | distribution. If you choose instead to embed HIDAPI directly into your 171 | application, you can skip the building and look at the provided platform 172 | Makefiles for guidance. These platform Makefiles are located in `linux/`, 173 | `libusb/`, `mac/` and `windows/` and are called `Makefile-manual`. In addition, 174 | Visual Studio projects are provided. Even if you're going to embed HIDAPI 175 | into your project, it is still beneficial to build the example programs. 176 | 177 | 178 | ### Prerequisites: 179 | 180 | #### Linux: 181 | On Linux, you will need to install development packages for libudev, 182 | libusb and optionally Fox-toolkit (for the test GUI). On 183 | Debian/Ubuntu systems these can be installed by running: 184 | ```sh 185 | sudo apt-get install libudev-dev libusb-1.0-0-dev libfox-1.6-dev 186 | ``` 187 | 188 | If you downloaded the source directly from the git repository (using 189 | git clone), you'll need Autotools: 190 | ```sh 191 | sudo apt-get install autotools-dev autoconf automake libtool 192 | ``` 193 | 194 | #### FreeBSD: 195 | On FreeBSD you will need to install GNU make, libiconv, and 196 | optionally Fox-Toolkit (for the test GUI). This is done by running 197 | the following: 198 | ```sh 199 | pkg_add -r gmake libiconv fox16 200 | ``` 201 | 202 | If you downloaded the source directly from the git repository (using 203 | git clone), you'll need Autotools: 204 | ```sh 205 | pkg_add -r autotools 206 | ``` 207 | 208 | #### Mac: 209 | On Mac, you will need to install Fox-Toolkit if you wish to build 210 | the Test GUI. There are two ways to do this, and each has a slight 211 | complication. Which method you use depends on your use case. 212 | 213 | If you wish to build the Test GUI just for your own testing on your 214 | own computer, then the easiest method is to install Fox-Toolkit 215 | using ports: 216 | ```sh 217 | sudo port install fox 218 | ``` 219 | 220 | If you wish to build the TestGUI app bundle to redistribute to 221 | others, you will need to install Fox-toolkit from source. This is 222 | because the version of fox that gets installed using ports uses the 223 | ports X11 libraries which are not compatible with the Apple X11 224 | libraries. If you install Fox with ports and then try to distribute 225 | your built app bundle, it will simply fail to run on other systems. 226 | To install Fox-Toolkit manually, download the source package from 227 | , extract it, and run the following from 228 | within the extracted source: 229 | ```sh 230 | ./configure && make && make install 231 | ``` 232 | 233 | #### Windows: 234 | On Windows, if you want to build the test GUI, you will need to get 235 | the `hidapi-externals.zip` package from the download site. This 236 | contains pre-built binaries for Fox-toolkit. Extract 237 | `hidapi-externals.zip` just outside of hidapi, so that 238 | hidapi-externals and hidapi are on the same level, as shown: 239 | ``` 240 | Parent_Folder 241 | | 242 | +hidapi 243 | +hidapi-externals 244 | ``` 245 | Again, this step is not required if you do not wish to build the 246 | test GUI. 247 | 248 | 249 | ### Building HIDAPI into a shared library on Unix Platforms: 250 | 251 | On Unix-like systems such as Linux, FreeBSD, macOS, and even Windows, using 252 | MinGW or Cygwin, the easiest way to build a standard system-installed shared 253 | library is to use the GNU Autotools build system. If you checked out the 254 | source from the git repository, run the following: 255 | 256 | ```sh 257 | ./bootstrap 258 | ./configure 259 | make 260 | make install # as root, or using sudo 261 | ``` 262 | 263 | If you downloaded a source package (i.e.: if you did not run git clone), you 264 | can skip the `./bootstrap` step. 265 | 266 | `./configure` can take several arguments which control the build. The two most 267 | likely to be used are: 268 | ```sh 269 | --enable-testgui 270 | Enable build of the Test GUI. This requires Fox toolkit to 271 | be installed. Instructions for installing Fox-Toolkit on 272 | each platform are in the Prerequisites section above. 273 | 274 | --prefix=/usr 275 | Specify where you want the output headers and libraries to 276 | be installed. The example above will put the headers in 277 | /usr/include and the binaries in /usr/lib. The default is to 278 | install into /usr/local which is fine on most systems. 279 | ``` 280 | ### Building the manual way on Unix platforms: 281 | 282 | Manual Makefiles are provided mostly to give the user and idea what it takes 283 | to build a program which embeds HIDAPI directly inside of it. These should 284 | really be used as examples only. If you want to build a system-wide shared 285 | library, use the Autotools method described above. 286 | 287 | To build HIDAPI using the manual Makefiles, change to the directory 288 | of your platform and run make. For example, on Linux run: 289 | ```sh 290 | cd linux/ 291 | make -f Makefile-manual 292 | ``` 293 | 294 | To build the Test GUI using the manual makefiles: 295 | ```sh 296 | cd testgui/ 297 | make -f Makefile-manual 298 | ``` 299 | 300 | ### Building on Windows: 301 | 302 | To build the HIDAPI DLL on Windows using Visual Studio, build the `.sln` file 303 | in the `windows/` directory. 304 | 305 | To build the Test GUI on windows using Visual Studio, build the `.sln` file in 306 | the `testgui/` directory. 307 | 308 | To build HIDAPI using MinGW or Cygwin using Autotools, use the instructions 309 | in the section [Building HIDAPI into a shared library on Unix Platforms](#building-hidapi-into-a-shared-library-on-unix-platforms) 310 | above. Note that building the Test GUI with MinGW or Cygwin will 311 | require the Windows procedure in the [Prerequisites](#prerequisites-1) section 312 | above (i.e.: `hidapi-externals.zip`). 313 | 314 | To build HIDAPI using MinGW using the Manual Makefiles, see the section 315 | [Building the manual way on Unix platforms](#building-the-manual-way-on-unix-platforms) 316 | above. 317 | 318 | HIDAPI can also be built using the Windows DDK (now also called the Windows 319 | Driver Kit or WDK). This method was originally required for the HIDAPI build 320 | but not anymore. However, some users still prefer this method. It is not as 321 | well supported anymore but should still work. Patches are welcome if it does 322 | not. To build using the DDK: 323 | 324 | 1. Install the Windows Driver Kit (WDK) from Microsoft. 325 | 2. From the Start menu, in the Windows Driver Kits folder, select Build 326 | Environments, then your operating system, then the x86 Free Build 327 | Environment (or one that is appropriate for your system). 328 | 3. From the console, change directory to the `windows/ddk_build/` directory, 329 | which is part of the HIDAPI distribution. 330 | 4. Type build. 331 | 5. You can find the output files (DLL and LIB) in a subdirectory created 332 | by the build system which is appropriate for your environment. On 333 | Windows XP, this directory is `objfre_wxp_x86/i386`. 334 | 335 | ## Cross Compiling 336 | 337 | This section talks about cross compiling HIDAPI for Linux using Autotools. 338 | This is useful for using HIDAPI on embedded Linux targets. These 339 | instructions assume the most raw kind of embedded Linux build, where all 340 | prerequisites will need to be built first. This process will of course vary 341 | based on your embedded Linux build system if you are using one, such as 342 | OpenEmbedded or Buildroot. 343 | 344 | For the purpose of this section, it will be assumed that the following 345 | environment variables are exported. 346 | ```sh 347 | $ export STAGING=$HOME/out 348 | $ export HOST=arm-linux 349 | ``` 350 | 351 | `STAGING` and `HOST` can be modified to suit your setup. 352 | 353 | ### Prerequisites 354 | 355 | Note that the build of libudev is the very basic configuration. 356 | 357 | Build libusb. From the libusb source directory, run: 358 | ```sh 359 | ./configure --host=$HOST --prefix=$STAGING 360 | make 361 | make install 362 | ``` 363 | 364 | Build libudev. From the libudev source directory, run: 365 | ```sh 366 | ./configure --disable-gudev --disable-introspection --disable-hwdb \ 367 | --host=$HOST --prefix=$STAGING 368 | make 369 | make install 370 | ``` 371 | 372 | ### Building HIDAPI 373 | 374 | Build HIDAPI: 375 | ``` 376 | PKG_CONFIG_DIR= \ 377 | PKG_CONFIG_LIBDIR=$STAGING/lib/pkgconfig:$STAGING/share/pkgconfig \ 378 | PKG_CONFIG_SYSROOT_DIR=$STAGING \ 379 | ./configure --host=$HOST --prefix=$STAGING 380 | ``` 381 | -------------------------------------------------------------------------------- /hidapi/android/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH:= $(call my-dir) 2 | 3 | HIDAPI_ROOT_REL:= ../.. 4 | HIDAPI_ROOT_ABS:= $(LOCAL_PATH)/../.. 5 | 6 | include $(CLEAR_VARS) 7 | 8 | LOCAL_SRC_FILES := \ 9 | $(HIDAPI_ROOT_REL)/libusb/hid.c 10 | 11 | LOCAL_C_INCLUDES += \ 12 | $(HIDAPI_ROOT_ABS)/hidapi \ 13 | $(HIDAPI_ROOT_ABS)/android 14 | 15 | LOCAL_SHARED_LIBRARIES := libusb1.0 16 | 17 | LOCAL_MODULE := libhidapi 18 | 19 | include $(BUILD_SHARED_LIBRARY) 20 | -------------------------------------------------------------------------------- /hidapi/bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh -x 2 | autoreconf --install --verbose --force 3 | -------------------------------------------------------------------------------- /hidapi/configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ(2.63) 2 | 3 | # Version number. This is currently the only place. 4 | m4_define([HIDAPI_MAJOR], 0) 5 | m4_define([HIDAPI_MINOR], 9) 6 | m4_define([HIDAPI_RELEASE], 0) 7 | m4_define([HIDAPI_RC], ) 8 | m4_define([VERSION_STRING], HIDAPI_MAJOR[.]HIDAPI_MINOR[.]HIDAPI_RELEASE[]HIDAPI_RC) 9 | 10 | AC_INIT([hidapi],[VERSION_STRING],[alan@signal11.us]) 11 | 12 | # Library soname version 13 | # Follow the following rules (particularly the ones in the second link): 14 | # http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html 15 | # http://sourceware.org/autobook/autobook/autobook_91.html 16 | lt_current="0" 17 | lt_revision="0" 18 | lt_age="0" 19 | LTLDFLAGS="-version-info ${lt_current}:${lt_revision}:${lt_age}" 20 | 21 | AC_CONFIG_MACRO_DIR([m4]) 22 | AM_INIT_AUTOMAKE([foreign -Wall -Werror]) 23 | AC_CONFIG_MACRO_DIR([m4]) 24 | 25 | m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) 26 | LT_INIT 27 | 28 | AC_PROG_CC 29 | AC_PROG_CXX 30 | AC_PROG_OBJC 31 | PKG_PROG_PKG_CONFIG 32 | 33 | 34 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 35 | 36 | hidapi_lib_error() { 37 | echo "" 38 | echo " Library $1 was not found on this system." 39 | echo " Please install it and re-run ./configure" 40 | echo "" 41 | exit 1 42 | } 43 | 44 | hidapi_prog_error() { 45 | echo "" 46 | echo " Program $1 was not found on this system." 47 | echo " This program is part of $2." 48 | echo " Please install it and re-run ./configure" 49 | echo "" 50 | exit 1 51 | } 52 | 53 | AC_MSG_CHECKING([operating system]) 54 | AC_MSG_RESULT($host) 55 | case $host in 56 | *-linux*) 57 | AC_MSG_RESULT([ (Linux back-end)]) 58 | AC_DEFINE(OS_LINUX, 1, [Linux implementations]) 59 | AC_SUBST(OS_LINUX) 60 | backend="linux" 61 | os="linux" 62 | threads="pthreads" 63 | 64 | # HIDAPI/hidraw libs 65 | PKG_CHECK_MODULES([libudev], [libudev], true, [hidapi_lib_error libudev]) 66 | LIBS_HIDRAW_PR="${LIBS_HIDRAW_PR} $libudev_LIBS" 67 | CFLAGS_HIDRAW="${CFLAGS_HIDRAW} $libudev_CFLAGS" 68 | 69 | # HIDAPI/libusb libs 70 | AC_CHECK_LIB([rt], [clock_gettime], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -lrt"], [hidapi_lib_error librt]) 71 | PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.9], true, [hidapi_lib_error libusb-1.0]) 72 | LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} $libusb_LIBS" 73 | CFLAGS_LIBUSB="${CFLAGS_LIBUSB} $libusb_CFLAGS" 74 | ;; 75 | *-darwin*) 76 | AC_MSG_RESULT([ (Mac OS X back-end)]) 77 | AC_DEFINE(OS_DARWIN, 1, [Mac implementation]) 78 | AC_SUBST(OS_DARWIN) 79 | backend="mac" 80 | os="darwin" 81 | threads="pthreads" 82 | LIBS="${LIBS} -framework IOKit -framework CoreFoundation" 83 | ;; 84 | *-freebsd*) 85 | AC_MSG_RESULT([ (FreeBSD back-end)]) 86 | AC_DEFINE(OS_FREEBSD, 1, [FreeBSD implementation]) 87 | AC_SUBST(OS_FREEBSD) 88 | backend="libusb" 89 | os="freebsd" 90 | threads="pthreads" 91 | 92 | CFLAGS="$CFLAGS -I/usr/local/include" 93 | LDFLAGS="$LDFLAGS -L/usr/local/lib" 94 | LIBS="${LIBS}" 95 | PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.9], true, [hidapi_lib_error libusb-1.0]) 96 | LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} $libusb_LIBS" 97 | CFLAGS_LIBUSB="${CFLAGS_LIBUSB} $libusb_CFLAGS" 98 | AC_CHECK_LIB([iconv], [iconv_open], [LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} -liconv"], [hidapi_lib_error libiconv]) 99 | ;; 100 | *-kfreebsd*) 101 | AC_MSG_RESULT([ (kFreeBSD back-end)]) 102 | AC_DEFINE(OS_KFREEBSD, 1, [kFreeBSD implementation]) 103 | AC_SUBST(OS_KFREEBSD) 104 | backend="libusb" 105 | os="kfreebsd" 106 | threads="pthreads" 107 | 108 | PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.9], true, [hidapi_lib_error libusb-1.0]) 109 | LIBS_LIBUSB_PRIVATE="${LIBS_LIBUSB_PRIVATE} $libusb_LIBS" 110 | CFLAGS_LIBUSB="${CFLAGS_LIBUSB} $libusb_CFLAGS" 111 | ;; 112 | *-mingw*) 113 | AC_MSG_RESULT([ (Windows back-end, using MinGW)]) 114 | backend="windows" 115 | os="windows" 116 | threads="windows" 117 | win_implementation="mingw" 118 | ;; 119 | *-cygwin*) 120 | AC_MSG_RESULT([ (Windows back-end, using Cygwin)]) 121 | backend="windows" 122 | os="windows" 123 | threads="windows" 124 | win_implementation="cygwin" 125 | ;; 126 | *) 127 | AC_MSG_ERROR([HIDAPI is not supported on your operating system yet]) 128 | esac 129 | 130 | LIBS_HIDRAW="${LIBS} ${LIBS_HIDRAW_PR}" 131 | LIBS_LIBUSB="${LIBS} ${LIBS_LIBUSB_PRIVATE}" 132 | AC_SUBST([LIBS_HIDRAW]) 133 | AC_SUBST([LIBS_LIBUSB]) 134 | AC_SUBST([CFLAGS_LIBUSB]) 135 | AC_SUBST([CFLAGS_HIDRAW]) 136 | 137 | if test "x$os" = xwindows; then 138 | AC_DEFINE(OS_WINDOWS, 1, [Windows implementations]) 139 | AC_SUBST(OS_WINDOWS) 140 | LDFLAGS="${LDFLAGS} -no-undefined" 141 | LIBS="${LIBS} -lsetupapi" 142 | fi 143 | 144 | if test "x$threads" = xpthreads; then 145 | AX_PTHREAD([found_pthreads=yes], [found_pthreads=no]) 146 | 147 | if test "x$found_pthreads" = xyes; then 148 | if test "x$os" = xlinux; then 149 | # Only use pthreads for libusb implementation on Linux. 150 | LIBS_LIBUSB="$PTHREAD_LIBS $LIBS_LIBUSB" 151 | CFLAGS_LIBUSB="$CFLAGS_LIBUSB $PTHREAD_CFLAGS" 152 | # There's no separate CC on Linux for threading, 153 | # so it's ok that both implementations use $PTHREAD_CC 154 | CC="$PTHREAD_CC" 155 | else 156 | LIBS="$PTHREAD_LIBS $LIBS" 157 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 158 | CC="$PTHREAD_CC" 159 | fi 160 | fi 161 | fi 162 | 163 | # Test GUI 164 | AC_ARG_ENABLE([testgui], 165 | [AS_HELP_STRING([--enable-testgui], 166 | [enable building of test GUI (default n)])], 167 | [testgui_enabled=$enableval], 168 | [testgui_enabled='no']) 169 | AM_CONDITIONAL([BUILD_TESTGUI], [test "x$testgui_enabled" != "xno"]) 170 | 171 | # Configure the MacOS TestGUI app bundle 172 | rm -Rf testgui/TestGUI.app 173 | mkdir -p testgui/TestGUI.app 174 | cp -R ${srcdir}/testgui/TestGUI.app.in/* testgui/TestGUI.app 175 | chmod -R u+w testgui/TestGUI.app 176 | mkdir testgui/TestGUI.app/Contents/MacOS/ 177 | 178 | if test "x$testgui_enabled" != "xno"; then 179 | if test "x$os" = xdarwin; then 180 | # On Mac OS, don't use pkg-config. 181 | AC_CHECK_PROG([foxconfig], [fox-config], [fox-config], false) 182 | if test "x$foxconfig" = "xfalse"; then 183 | hidapi_prog_error fox-config "FOX Toolkit" 184 | fi 185 | LIBS_TESTGUI="${LIBS_TESTGUI} `$foxconfig --libs`" 186 | LIBS_TESTGUI="${LIBS_TESTGUI} -framework Cocoa -L/usr/X11R6/lib" 187 | CFLAGS_TESTGUI="${CFLAGS_TESTGUI} `$foxconfig --cflags`" 188 | OBJCFLAGS="${OBJCFLAGS} -x objective-c++" 189 | elif test "x$os" = xwindows; then 190 | # On Windows, just set the paths for Fox toolkit 191 | if test "x$win_implementation" = xmingw; then 192 | CFLAGS_TESTGUI="-I\$(srcdir)/../../hidapi-externals/fox/include -g -c" 193 | LIBS_TESTGUI=" -mwindows \$(srcdir)/../../hidapi-externals/fox/lib/libFOX-1.6.a -lgdi32 -Wl,--enable-auto-import -static-libgcc -static-libstdc++ -lkernel32" 194 | else 195 | # Cygwin 196 | CFLAGS_TESTGUI="-DWIN32 -I\$(srcdir)/../../hidapi-externals/fox/include -g -c" 197 | LIBS_TESTGUI="\$(srcdir)/../../hidapi-externals/fox/lib/libFOX-cygwin-1.6.a -lgdi32 -Wl,--enable-auto-import -static-libgcc -static-libstdc++ -lkernel32" 198 | fi 199 | else 200 | # On Linux and FreeBSD platforms, use pkg-config to find fox. 201 | PKG_CHECK_MODULES([fox], [fox17], [], [PKG_CHECK_MODULES([fox], [fox])]) 202 | LIBS_TESTGUI="${LIBS_TESTGUI} $fox_LIBS" 203 | if test "x$os" = xfreebsd; then 204 | LIBS_TESTGUI="${LIBS_TESTGUI} -L/usr/local/lib" 205 | fi 206 | CFLAGS_TESTGUI="${CFLAGS_TESTGUI} $fox_CFLAGS" 207 | fi 208 | fi 209 | AC_SUBST([LIBS_TESTGUI]) 210 | AC_SUBST([CFLAGS_TESTGUI]) 211 | AC_SUBST([backend]) 212 | 213 | # OS info for Automake 214 | AM_CONDITIONAL(OS_LINUX, test "x$os" = xlinux) 215 | AM_CONDITIONAL(OS_DARWIN, test "x$os" = xdarwin) 216 | AM_CONDITIONAL(OS_FREEBSD, test "x$os" = xfreebsd) 217 | AM_CONDITIONAL(OS_KFREEBSD, test "x$os" = xkfreebsd) 218 | AM_CONDITIONAL(OS_WINDOWS, test "x$os" = xwindows) 219 | 220 | AC_CONFIG_HEADERS([config.h]) 221 | 222 | if test "x$os" = "xlinux"; then 223 | AC_CONFIG_FILES([pc/hidapi-hidraw.pc]) 224 | AC_CONFIG_FILES([pc/hidapi-libusb.pc]) 225 | else 226 | AC_CONFIG_FILES([pc/hidapi.pc]) 227 | fi 228 | 229 | AC_SUBST(LTLDFLAGS) 230 | 231 | AC_CONFIG_FILES([Makefile \ 232 | hidtest/Makefile \ 233 | libusb/Makefile \ 234 | linux/Makefile \ 235 | mac/Makefile \ 236 | testgui/Makefile \ 237 | windows/Makefile]) 238 | AC_OUTPUT 239 | -------------------------------------------------------------------------------- /hidapi/dist/hidapi.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | 3 | spec.name = "hidapi" 4 | spec.version = "0.9.0" 5 | spec.summary = "A Simple library for communicating with USB and Bluetooth HID devices on Linux, Mac and Windows." 6 | 7 | spec.description = <<-DESC 8 | 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. 9 | DESC 10 | 11 | spec.homepage = "https://github.com/libusb/hidapi" 12 | 13 | spec.license = { :type=> "GNU GPLv3 or BSD or HIDAPI original", :file => "LICENSE.txt" } 14 | 15 | spec.authors = { "Alan Ott" => "alan@signal11.us", 16 | "Ludovic Rousseau" => "rousseau@debian.org", 17 | "libusb/hidapi Team" => "https://github.com/libusb/hidapi/blob/master/AUTHORS.txt", 18 | } 19 | 20 | spec.platform = :osx 21 | spec.osx.deployment_target = "10.7" 22 | 23 | spec.source = { :git => "https://github.com/libusb/hidapi.git", :tag => "hidapi-#{spec.version}" } 24 | 25 | spec.source_files = "mac/hid.c", "hidapi/hidapi.h" 26 | 27 | spec.public_header_files = "hidapi/hidapi.h" 28 | 29 | spec.frameworks = "IOKit", "CoreFoundation" 30 | 31 | end 32 | -------------------------------------------------------------------------------- /hidapi/hidtest/.gitignore: -------------------------------------------------------------------------------- 1 | Debug 2 | Release 3 | *.exp 4 | *.ilk 5 | *.lib 6 | *.suo 7 | *.vcproj.* 8 | *.ncb 9 | *.suo 10 | *.dll 11 | *.pdb 12 | *.o 13 | .deps/ 14 | .libs/ 15 | hidtest-hidraw 16 | hidtest-libusb 17 | hidtest 18 | -------------------------------------------------------------------------------- /hidapi/hidtest/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_srcdir)/hidapi/ 2 | 3 | ## Linux 4 | if OS_LINUX 5 | noinst_PROGRAMS = hidtest-libusb hidtest-hidraw 6 | 7 | hidtest_hidraw_SOURCES = test.c 8 | hidtest_hidraw_LDADD = $(top_builddir)/linux/libhidapi-hidraw.la 9 | 10 | hidtest_libusb_SOURCES = test.c 11 | hidtest_libusb_LDADD = $(top_builddir)/libusb/libhidapi-libusb.la 12 | else 13 | 14 | # Other OS's 15 | noinst_PROGRAMS = hidtest 16 | 17 | hidtest_SOURCES = test.c 18 | hidtest_LDADD = $(top_builddir)/$(backend)/libhidapi.la 19 | 20 | endif 21 | -------------------------------------------------------------------------------- /hidapi/hidtest/test.c: -------------------------------------------------------------------------------- 1 | /******************************************************* 2 | Windows HID simplification 3 | 4 | Alan Ott 5 | Signal 11 Software 6 | 7 | 8/22/2009 8 | 9 | Copyright 2009 10 | 11 | This contents of this file may be used by anyone 12 | for any reason without any conditions and may be 13 | used as a starting point for your own applications 14 | which use HIDAPI. 15 | ********************************************************/ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "hidapi.h" 22 | 23 | // Headers needed for sleeping. 24 | #ifdef _WIN32 25 | #include 26 | #else 27 | #include 28 | #endif 29 | 30 | int main(int argc, char* argv[]) 31 | { 32 | int res; 33 | unsigned char buf[256]; 34 | #define MAX_STR 255 35 | wchar_t wstr[MAX_STR]; 36 | hid_device *handle; 37 | int i; 38 | 39 | #ifdef WIN32 40 | UNREFERENCED_PARAMETER(argc); 41 | UNREFERENCED_PARAMETER(argv); 42 | #endif 43 | 44 | struct hid_device_info *devs, *cur_dev; 45 | 46 | if (hid_init()) 47 | return -1; 48 | 49 | devs = hid_enumerate(0x0, 0x0); 50 | cur_dev = devs; 51 | while (cur_dev) { 52 | printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number); 53 | printf("\n"); 54 | printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string); 55 | printf(" Product: %ls\n", cur_dev->product_string); 56 | printf(" Release: %hx\n", cur_dev->release_number); 57 | printf(" Interface: %d\n", cur_dev->interface_number); 58 | printf("\n"); 59 | cur_dev = cur_dev->next; 60 | } 61 | hid_free_enumeration(devs); 62 | 63 | // Set up the command buffer. 64 | memset(buf,0x00,sizeof(buf)); 65 | buf[0] = 0x01; 66 | buf[1] = 0x81; 67 | 68 | 69 | // Open the device using the VID, PID, 70 | // and optionally the Serial number. 71 | ////handle = hid_open(0x4d8, 0x3f, L"12345"); 72 | handle = hid_open(0x4d8, 0x3f, NULL); 73 | if (!handle) { 74 | printf("unable to open device\n"); 75 | return 1; 76 | } 77 | 78 | // Read the Manufacturer String 79 | wstr[0] = 0x0000; 80 | res = hid_get_manufacturer_string(handle, wstr, MAX_STR); 81 | if (res < 0) 82 | printf("Unable to read manufacturer string\n"); 83 | printf("Manufacturer String: %ls\n", wstr); 84 | 85 | // Read the Product String 86 | wstr[0] = 0x0000; 87 | res = hid_get_product_string(handle, wstr, MAX_STR); 88 | if (res < 0) 89 | printf("Unable to read product string\n"); 90 | printf("Product String: %ls\n", wstr); 91 | 92 | // Read the Serial Number String 93 | wstr[0] = 0x0000; 94 | res = hid_get_serial_number_string(handle, wstr, MAX_STR); 95 | if (res < 0) 96 | printf("Unable to read serial number string\n"); 97 | printf("Serial Number String: (%d) %ls", wstr[0], wstr); 98 | printf("\n"); 99 | 100 | // Read Indexed String 1 101 | wstr[0] = 0x0000; 102 | res = hid_get_indexed_string(handle, 1, wstr, MAX_STR); 103 | if (res < 0) 104 | printf("Unable to read indexed string 1\n"); 105 | printf("Indexed String 1: %ls\n", wstr); 106 | 107 | // Set the hid_read() function to be non-blocking. 108 | hid_set_nonblocking(handle, 1); 109 | 110 | // Try to read from the device. There should be no 111 | // data here, but execution should not block. 112 | res = hid_read(handle, buf, 17); 113 | 114 | // Send a Feature Report to the device 115 | buf[0] = 0x2; 116 | buf[1] = 0xa0; 117 | buf[2] = 0x0a; 118 | buf[3] = 0x00; 119 | buf[4] = 0x00; 120 | res = hid_send_feature_report(handle, buf, 17); 121 | if (res < 0) { 122 | printf("Unable to send a feature report.\n"); 123 | } 124 | 125 | memset(buf,0,sizeof(buf)); 126 | 127 | // Read a Feature Report from the device 128 | buf[0] = 0x2; 129 | res = hid_get_feature_report(handle, buf, sizeof(buf)); 130 | if (res < 0) { 131 | printf("Unable to get a feature report.\n"); 132 | printf("%ls", hid_error(handle)); 133 | } 134 | else { 135 | // Print out the returned buffer. 136 | printf("Feature Report\n "); 137 | for (i = 0; i < res; i++) 138 | printf("%02hhx ", buf[i]); 139 | printf("\n"); 140 | } 141 | 142 | memset(buf,0,sizeof(buf)); 143 | 144 | // Toggle LED (cmd 0x80). The first byte is the report number (0x1). 145 | buf[0] = 0x1; 146 | buf[1] = 0x80; 147 | res = hid_write(handle, buf, 17); 148 | if (res < 0) { 149 | printf("Unable to write()\n"); 150 | printf("Error: %ls\n", hid_error(handle)); 151 | } 152 | 153 | 154 | // Request state (cmd 0x81). The first byte is the report number (0x1). 155 | buf[0] = 0x1; 156 | buf[1] = 0x81; 157 | hid_write(handle, buf, 17); 158 | if (res < 0) 159 | printf("Unable to write() (2)\n"); 160 | 161 | // Read requested state. hid_read() has been set to be 162 | // non-blocking by the call to hid_set_nonblocking() above. 163 | // This loop demonstrates the non-blocking nature of hid_read(). 164 | res = 0; 165 | while (res == 0) { 166 | res = hid_read(handle, buf, sizeof(buf)); 167 | if (res == 0) 168 | printf("waiting...\n"); 169 | if (res < 0) 170 | printf("Unable to read()\n"); 171 | #ifdef WIN32 172 | Sleep(500); 173 | #else 174 | usleep(500*1000); 175 | #endif 176 | } 177 | 178 | printf("Data read:\n "); 179 | // Print out the returned buffer. 180 | for (i = 0; i < res; i++) 181 | printf("%02hhx ", buf[i]); 182 | printf("\n"); 183 | 184 | hid_close(handle); 185 | 186 | /* Free static HIDAPI objects. */ 187 | hid_exit(); 188 | 189 | #ifdef WIN32 190 | system("pause"); 191 | #endif 192 | 193 | return 0; 194 | } 195 | -------------------------------------------------------------------------------- /hidapi/libusb/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.la 4 | *.lo 5 | *.a 6 | .libs 7 | .deps 8 | hidtest-libusb 9 | -------------------------------------------------------------------------------- /hidapi/libusb/Makefile-manual: -------------------------------------------------------------------------------- 1 | 2 | 3 | OS=$(shell uname) 4 | 5 | ifeq ($(OS), Linux) 6 | FILE=Makefile.linux 7 | endif 8 | 9 | ifeq ($(OS), FreeBSD) 10 | FILE=Makefile.freebsd 11 | endif 12 | 13 | ifeq ($(FILE), ) 14 | all: 15 | $(error Your platform ${OS} is not supported by hidapi/libusb at this time.) 16 | endif 17 | 18 | include $(FILE) 19 | -------------------------------------------------------------------------------- /hidapi/libusb/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_srcdir)/hidapi $(CFLAGS_LIBUSB) 2 | 3 | if OS_LINUX 4 | lib_LTLIBRARIES = libhidapi-libusb.la 5 | libhidapi_libusb_la_SOURCES = hid.c 6 | libhidapi_libusb_la_LDFLAGS = $(LTLDFLAGS) $(PTHREAD_CFLAGS) 7 | libhidapi_libusb_la_LIBADD = $(LIBS_LIBUSB) 8 | endif 9 | 10 | if OS_FREEBSD 11 | lib_LTLIBRARIES = libhidapi.la 12 | libhidapi_la_SOURCES = hid.c 13 | libhidapi_la_LDFLAGS = $(LTLDFLAGS) 14 | libhidapi_la_LIBADD = $(LIBS_LIBUSB) 15 | endif 16 | 17 | if OS_KFREEBSD 18 | lib_LTLIBRARIES = libhidapi.la 19 | libhidapi_la_SOURCES = hid.c 20 | libhidapi_la_LDFLAGS = $(LTLDFLAGS) 21 | libhidapi_la_LIBADD = $(LIBS_LIBUSB) 22 | endif 23 | 24 | hdrdir = $(includedir)/hidapi 25 | hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h 26 | 27 | EXTRA_DIST = Makefile-manual 28 | -------------------------------------------------------------------------------- /hidapi/libusb/Makefile.freebsd: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Simple Makefile for HIDAPI test program 3 | # 4 | # Alan Ott 5 | # Signal 11 Software 6 | # 2010-06-01 7 | ########################################### 8 | 9 | all: hidtest libs 10 | 11 | libs: libhidapi.so 12 | 13 | CC ?= cc 14 | CFLAGS ?= -Wall -g -fPIC 15 | 16 | CXX ?= c++ 17 | CXXFLAGS ?= -Wall -g 18 | 19 | COBJS = hid.o 20 | CPPOBJS = ../hidtest/hidtest.o 21 | OBJS = $(COBJS) $(CPPOBJS) 22 | INCLUDES = -I../hidapi -I/usr/local/include 23 | LDFLAGS = -L/usr/local/lib 24 | LIBS = -lusb -liconv -pthread 25 | 26 | 27 | # Console Test Program 28 | hidtest: $(OBJS) 29 | $(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS) 30 | 31 | # Shared Libs 32 | libhidapi.so: $(COBJS) 33 | $(CC) $(LDFLAGS) -shared -Wl,-soname,$@.0 $^ -o $@ $(LIBS) 34 | 35 | # Objects 36 | $(COBJS): %.o: %.c 37 | $(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@ 38 | 39 | $(CPPOBJS): %.o: %.cpp 40 | $(CXX) $(CXXFLAGS) -c $(INCLUDES) $< -o $@ 41 | 42 | 43 | clean: 44 | rm -f $(OBJS) hidtest libhidapi.so ../hidtest/hidtest.o 45 | 46 | .PHONY: clean libs 47 | -------------------------------------------------------------------------------- /hidapi/libusb/Makefile.linux: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Simple Makefile for HIDAPI test program 3 | # 4 | # Alan Ott 5 | # Signal 11 Software 6 | # 2010-06-01 7 | ########################################### 8 | 9 | all: hidtest-libusb libs 10 | 11 | libs: libhidapi-libusb.so 12 | 13 | CC ?= gcc 14 | CFLAGS ?= -Wall -g -fpic 15 | 16 | CXX ?= g++ 17 | CXXFLAGS ?= -Wall -g -fpic 18 | 19 | LDFLAGS ?= -Wall -g 20 | 21 | COBJS_LIBUSB = hid.o 22 | COBJS = $(COBJS_LIBUSB) 23 | CPPOBJS = ../hidtest/hidtest.o 24 | OBJS = $(COBJS) $(CPPOBJS) 25 | LIBS_USB = `pkg-config libusb-1.0 --libs` -lrt -lpthread 26 | LIBS = $(LIBS_USB) 27 | INCLUDES ?= -I../hidapi `pkg-config libusb-1.0 --cflags` 28 | 29 | 30 | # Console Test Program 31 | hidtest-libusb: $(COBJS_LIBUSB) $(CPPOBJS) 32 | $(CXX) $(LDFLAGS) $^ $(LIBS_USB) -o $@ 33 | 34 | # Shared Libs 35 | libhidapi-libusb.so: $(COBJS_LIBUSB) 36 | $(CC) $(LDFLAGS) $(LIBS_USB) -shared -fpic -Wl,-soname,$@.0 $^ -o $@ 37 | 38 | # Objects 39 | $(COBJS): %.o: %.c 40 | $(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@ 41 | 42 | $(CPPOBJS): %.o: %.cpp 43 | $(CXX) $(CXXFLAGS) -c $(INCLUDES) $< -o $@ 44 | 45 | 46 | clean: 47 | rm -f $(OBJS) hidtest-libusb libhidapi-libusb.so ../hidtest/hidtest.o 48 | 49 | .PHONY: clean libs 50 | -------------------------------------------------------------------------------- /hidapi/linux/.gitignore: -------------------------------------------------------------------------------- 1 | Debug 2 | Release 3 | *.exp 4 | *.ilk 5 | *.lib 6 | *.suo 7 | *.vcproj.* 8 | *.ncb 9 | *.suo 10 | *.dll 11 | *.pdb 12 | *.o 13 | *.so 14 | hidtest-hidraw 15 | .deps 16 | .libs 17 | *.lo 18 | *.la 19 | -------------------------------------------------------------------------------- /hidapi/linux/Makefile-manual: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Simple Makefile for HIDAPI test program 3 | # 4 | # Alan Ott 5 | # Signal 11 Software 6 | # 2010-06-01 7 | ########################################### 8 | 9 | all: hidtest-hidraw libs 10 | 11 | libs: libhidapi-hidraw.so 12 | 13 | CC ?= gcc 14 | CFLAGS ?= -Wall -g -fpic 15 | 16 | CXX ?= g++ 17 | CXXFLAGS ?= -Wall -g -fpic 18 | 19 | LDFLAGS ?= -Wall -g 20 | 21 | 22 | COBJS = hid.o ../hidtest/test.o 23 | CPPOBJS = 24 | OBJS = $(COBJS) $(CPPOBJS) 25 | LIBS_UDEV = `pkg-config libudev --libs` -lrt 26 | LIBS = $(LIBS_UDEV) 27 | INCLUDES ?= -I../hidapi `pkg-config libusb-1.0 --cflags` 28 | 29 | 30 | # Console Test Program 31 | hidtest-hidraw: $(COBJS) $(CPPOBJS) 32 | $(CC) $(LDFLAGS) $^ $(LIBS_UDEV) -o $@ 33 | 34 | # Shared Libs 35 | libhidapi-hidraw.so: $(COBJS) 36 | $(CC) $(LDFLAGS) $(LIBS_UDEV) -shared -fpic -Wl,-soname,$@.0 $^ -o $@ 37 | 38 | # Objects 39 | $(COBJS): %.o: %.c 40 | $(CC) $(CFLAGS) -c $(INCLUDES) $< -o $@ 41 | 42 | $(CPPOBJS): %.o: %.cpp 43 | $(CXX) $(CXXFLAGS) -c $(INCLUDES) $< -o $@ 44 | 45 | 46 | clean: 47 | rm -f $(OBJS) hidtest-hidraw libhidapi-hidraw.so $(COBJS) $(CPPOBJS) 48 | 49 | .PHONY: clean libs 50 | -------------------------------------------------------------------------------- /hidapi/linux/Makefile.am: -------------------------------------------------------------------------------- 1 | lib_LTLIBRARIES = libhidapi-hidraw.la 2 | libhidapi_hidraw_la_SOURCES = hid.c 3 | libhidapi_hidraw_la_LDFLAGS = $(LTLDFLAGS) 4 | AM_CPPFLAGS = -I$(top_srcdir)/hidapi/ $(CFLAGS_HIDRAW) 5 | libhidapi_hidraw_la_LIBADD = $(LIBS_HIDRAW) 6 | 7 | hdrdir = $(includedir)/hidapi 8 | hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h 9 | 10 | EXTRA_DIST = Makefile-manual 11 | -------------------------------------------------------------------------------- /hidapi/m4/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore All, except pkg.m4, and of course this file. 2 | * 3 | !.gitignore 4 | !pkg.m4 5 | !ax_pthread.m4 6 | -------------------------------------------------------------------------------- /hidapi/m4/ax_pthread.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_pthread.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # This macro figures out how to build C programs using POSIX threads. It 12 | # sets the PTHREAD_LIBS output variable to the threads library and linker 13 | # flags, and the PTHREAD_CFLAGS output variable to any special C compiler 14 | # flags that are needed. (The user can also force certain compiler 15 | # flags/libs to be tested by setting these environment variables.) 16 | # 17 | # Also sets PTHREAD_CC to any special C compiler that is needed for 18 | # multi-threaded programs (defaults to the value of CC otherwise). (This 19 | # is necessary on AIX to use the special cc_r compiler alias.) 20 | # 21 | # NOTE: You are assumed to not only compile your program with these flags, 22 | # but also link it with them as well. e.g. you should link with 23 | # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS 24 | # 25 | # If you are only building threads programs, you may wish to use these 26 | # variables in your default LIBS, CFLAGS, and CC: 27 | # 28 | # LIBS="$PTHREAD_LIBS $LIBS" 29 | # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 30 | # CC="$PTHREAD_CC" 31 | # 32 | # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant 33 | # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name 34 | # (e.g. PTHREAD_CREATE_UNDETACHED on AIX). 35 | # 36 | # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the 37 | # PTHREAD_PRIO_INHERIT symbol is defined when compiling with 38 | # PTHREAD_CFLAGS. 39 | # 40 | # ACTION-IF-FOUND is a list of shell commands to run if a threads library 41 | # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it 42 | # is not found. If ACTION-IF-FOUND is not specified, the default action 43 | # will define HAVE_PTHREAD. 44 | # 45 | # Please let the authors know if this macro fails on any platform, or if 46 | # you have any other suggestions or comments. This macro was based on work 47 | # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help 48 | # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by 49 | # Alejandro Forero Cuervo to the autoconf macro repository. We are also 50 | # grateful for the helpful feedback of numerous users. 51 | # 52 | # Updated for Autoconf 2.68 by Daniel Richard G. 53 | # 54 | # LICENSE 55 | # 56 | # Copyright (c) 2008 Steven G. Johnson 57 | # Copyright (c) 2011 Daniel Richard G. 58 | # 59 | # This program is free software: you can redistribute it and/or modify it 60 | # under the terms of the GNU General Public License as published by the 61 | # Free Software Foundation, either version 3 of the License, or (at your 62 | # option) any later version. 63 | # 64 | # This program is distributed in the hope that it will be useful, but 65 | # WITHOUT ANY WARRANTY; without even the implied warranty of 66 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 67 | # Public License for more details. 68 | # 69 | # You should have received a copy of the GNU General Public License along 70 | # with this program. If not, see . 71 | # 72 | # As a special exception, the respective Autoconf Macro's copyright owner 73 | # gives unlimited permission to copy, distribute and modify the configure 74 | # scripts that are the output of Autoconf when processing the Macro. You 75 | # need not follow the terms of the GNU General Public License when using 76 | # or distributing such scripts, even though portions of the text of the 77 | # Macro appear in them. The GNU General Public License (GPL) does govern 78 | # all other use of the material that constitutes the Autoconf Macro. 79 | # 80 | # This special exception to the GPL applies to versions of the Autoconf 81 | # Macro released by the Autoconf Archive. When you make and distribute a 82 | # modified version of the Autoconf Macro, you may extend this special 83 | # exception to the GPL to apply to your modified version as well. 84 | 85 | #serial 18 86 | 87 | AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) 88 | AC_DEFUN([AX_PTHREAD], [ 89 | AC_REQUIRE([AC_CANONICAL_HOST]) 90 | AC_LANG_PUSH([C]) 91 | ax_pthread_ok=no 92 | 93 | # We used to check for pthread.h first, but this fails if pthread.h 94 | # requires special compiler flags (e.g. on True64 or Sequent). 95 | # It gets checked for in the link test anyway. 96 | 97 | # First of all, check if the user has set any of the PTHREAD_LIBS, 98 | # etcetera environment variables, and if threads linking works using 99 | # them: 100 | if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then 101 | save_CFLAGS="$CFLAGS" 102 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 103 | save_LIBS="$LIBS" 104 | LIBS="$PTHREAD_LIBS $LIBS" 105 | AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) 106 | AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes) 107 | AC_MSG_RESULT($ax_pthread_ok) 108 | if test x"$ax_pthread_ok" = xno; then 109 | PTHREAD_LIBS="" 110 | PTHREAD_CFLAGS="" 111 | fi 112 | LIBS="$save_LIBS" 113 | CFLAGS="$save_CFLAGS" 114 | fi 115 | 116 | # We must check for the threads library under a number of different 117 | # names; the ordering is very important because some systems 118 | # (e.g. DEC) have both -lpthread and -lpthreads, where one of the 119 | # libraries is broken (non-POSIX). 120 | 121 | # Create a list of thread flags to try. Items starting with a "-" are 122 | # C compiler flags, and other items are library names, except for "none" 123 | # which indicates that we try without any flags at all, and "pthread-config" 124 | # which is a program returning the flags for the Pth emulation library. 125 | 126 | ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" 127 | 128 | # The ordering *is* (sometimes) important. Some notes on the 129 | # individual items follow: 130 | 131 | # pthreads: AIX (must check this before -lpthread) 132 | # none: in case threads are in libc; should be tried before -Kthread and 133 | # other compiler flags to prevent continual compiler warnings 134 | # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) 135 | # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) 136 | # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) 137 | # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) 138 | # -pthreads: Solaris/gcc 139 | # -mthreads: Mingw32/gcc, Lynx/gcc 140 | # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it 141 | # doesn't hurt to check since this sometimes defines pthreads too; 142 | # also defines -D_REENTRANT) 143 | # ... -mt is also the pthreads flag for HP/aCC 144 | # pthread: Linux, etcetera 145 | # --thread-safe: KAI C++ 146 | # pthread-config: use pthread-config program (for GNU Pth library) 147 | 148 | case ${host_os} in 149 | solaris*) 150 | 151 | # On Solaris (at least, for some versions), libc contains stubbed 152 | # (non-functional) versions of the pthreads routines, so link-based 153 | # tests will erroneously succeed. (We need to link with -pthreads/-mt/ 154 | # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather 155 | # a function called by this macro, so we could check for that, but 156 | # who knows whether they'll stub that too in a future libc.) So, 157 | # we'll just look for -pthreads and -lpthread first: 158 | 159 | ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" 160 | ;; 161 | 162 | darwin*) 163 | ax_pthread_flags="-pthread $ax_pthread_flags" 164 | ;; 165 | esac 166 | 167 | if test x"$ax_pthread_ok" = xno; then 168 | for flag in $ax_pthread_flags; do 169 | 170 | case $flag in 171 | none) 172 | AC_MSG_CHECKING([whether pthreads work without any flags]) 173 | ;; 174 | 175 | -*) 176 | AC_MSG_CHECKING([whether pthreads work with $flag]) 177 | PTHREAD_CFLAGS="$flag" 178 | ;; 179 | 180 | pthread-config) 181 | AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no) 182 | if test x"$ax_pthread_config" = xno; then continue; fi 183 | PTHREAD_CFLAGS="`pthread-config --cflags`" 184 | PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" 185 | ;; 186 | 187 | *) 188 | AC_MSG_CHECKING([for the pthreads library -l$flag]) 189 | PTHREAD_LIBS="-l$flag" 190 | ;; 191 | esac 192 | 193 | save_LIBS="$LIBS" 194 | save_CFLAGS="$CFLAGS" 195 | LIBS="$PTHREAD_LIBS $LIBS" 196 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 197 | 198 | # Check for various functions. We must include pthread.h, 199 | # since some functions may be macros. (On the Sequent, we 200 | # need a special flag -Kthread to make this header compile.) 201 | # We check for pthread_join because it is in -lpthread on IRIX 202 | # while pthread_create is in libc. We check for pthread_attr_init 203 | # due to DEC craziness with -lpthreads. We check for 204 | # pthread_cleanup_push because it is one of the few pthread 205 | # functions on Solaris that doesn't have a non-functional libc stub. 206 | # We try pthread_create on general principles. 207 | AC_LINK_IFELSE([AC_LANG_PROGRAM([#include 208 | static void routine(void *a) { a = 0; } 209 | static void *start_routine(void *a) { return a; }], 210 | [pthread_t th; pthread_attr_t attr; 211 | pthread_create(&th, 0, start_routine, 0); 212 | pthread_join(th, 0); 213 | pthread_attr_init(&attr); 214 | pthread_cleanup_push(routine, 0); 215 | pthread_cleanup_pop(0) /* ; */])], 216 | [ax_pthread_ok=yes], 217 | []) 218 | 219 | LIBS="$save_LIBS" 220 | CFLAGS="$save_CFLAGS" 221 | 222 | AC_MSG_RESULT($ax_pthread_ok) 223 | if test "x$ax_pthread_ok" = xyes; then 224 | break; 225 | fi 226 | 227 | PTHREAD_LIBS="" 228 | PTHREAD_CFLAGS="" 229 | done 230 | fi 231 | 232 | # Various other checks: 233 | if test "x$ax_pthread_ok" = xyes; then 234 | save_LIBS="$LIBS" 235 | LIBS="$PTHREAD_LIBS $LIBS" 236 | save_CFLAGS="$CFLAGS" 237 | CFLAGS="$CFLAGS $PTHREAD_CFLAGS" 238 | 239 | # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. 240 | AC_MSG_CHECKING([for joinable pthread attribute]) 241 | attr_name=unknown 242 | for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do 243 | AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], 244 | [int attr = $attr; return attr /* ; */])], 245 | [attr_name=$attr; break], 246 | []) 247 | done 248 | AC_MSG_RESULT($attr_name) 249 | if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then 250 | AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name, 251 | [Define to necessary symbol if this constant 252 | uses a non-standard name on your system.]) 253 | fi 254 | 255 | AC_MSG_CHECKING([if more special flags are required for pthreads]) 256 | flag=no 257 | case ${host_os} in 258 | aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; 259 | osf* | hpux*) flag="-D_REENTRANT";; 260 | solaris*) 261 | if test "$GCC" = "yes"; then 262 | flag="-D_REENTRANT" 263 | else 264 | flag="-mt -D_REENTRANT" 265 | fi 266 | ;; 267 | esac 268 | AC_MSG_RESULT(${flag}) 269 | if test "x$flag" != xno; then 270 | PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" 271 | fi 272 | 273 | AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], 274 | ax_cv_PTHREAD_PRIO_INHERIT, [ 275 | AC_LINK_IFELSE([ 276 | AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])], 277 | [ax_cv_PTHREAD_PRIO_INHERIT=yes], 278 | [ax_cv_PTHREAD_PRIO_INHERIT=no]) 279 | ]) 280 | AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], 281 | AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], 1, [Have PTHREAD_PRIO_INHERIT.])) 282 | 283 | LIBS="$save_LIBS" 284 | CFLAGS="$save_CFLAGS" 285 | 286 | # More AIX lossage: must compile with xlc_r or cc_r 287 | if test x"$GCC" != xyes; then 288 | AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC}) 289 | else 290 | PTHREAD_CC=$CC 291 | fi 292 | else 293 | PTHREAD_CC="$CC" 294 | fi 295 | 296 | AC_SUBST(PTHREAD_LIBS) 297 | AC_SUBST(PTHREAD_CFLAGS) 298 | AC_SUBST(PTHREAD_CC) 299 | 300 | # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: 301 | if test x"$ax_pthread_ok" = xyes; then 302 | ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) 303 | : 304 | else 305 | ax_pthread_ok=no 306 | $2 307 | fi 308 | AC_LANG_POP 309 | ])dnl AX_PTHREAD 310 | -------------------------------------------------------------------------------- /hidapi/m4/pkg.m4: -------------------------------------------------------------------------------- 1 | # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- 2 | # 3 | # Copyright © 2004 Scott James Remnant . 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program; if not, write to the Free Software 17 | # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | # 19 | # As a special exception to the GNU General Public License, if you 20 | # distribute this file as part of a program that contains a 21 | # configuration script generated by Autoconf, you may include it under 22 | # the same distribution terms that you use for the rest of that program. 23 | 24 | # PKG_PROG_PKG_CONFIG([MIN-VERSION]) 25 | # ---------------------------------- 26 | AC_DEFUN([PKG_PROG_PKG_CONFIG], 27 | [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) 28 | m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) 29 | AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl 30 | if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then 31 | AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) 32 | fi 33 | if test -n "$PKG_CONFIG"; then 34 | _pkg_min_version=m4_default([$1], [0.9.0]) 35 | AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) 36 | if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then 37 | AC_MSG_RESULT([yes]) 38 | else 39 | AC_MSG_RESULT([no]) 40 | PKG_CONFIG="" 41 | fi 42 | 43 | fi[]dnl 44 | ])# PKG_PROG_PKG_CONFIG 45 | 46 | # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) 47 | # 48 | # Check to see whether a particular set of modules exists. Similar 49 | # to PKG_CHECK_MODULES(), but does not set variables or print errors. 50 | # 51 | # 52 | # Similar to PKG_CHECK_MODULES, make sure that the first instance of 53 | # this or PKG_CHECK_MODULES is called, or make sure to call 54 | # PKG_CHECK_EXISTS manually 55 | # -------------------------------------------------------------- 56 | AC_DEFUN([PKG_CHECK_EXISTS], 57 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl 58 | if test -n "$PKG_CONFIG" && \ 59 | AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then 60 | m4_ifval([$2], [$2], [:]) 61 | m4_ifvaln([$3], [else 62 | $3])dnl 63 | fi]) 64 | 65 | 66 | # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) 67 | # --------------------------------------------- 68 | m4_define([_PKG_CONFIG], 69 | [if test -n "$PKG_CONFIG"; then 70 | if test -n "$$1"; then 71 | pkg_cv_[]$1="$$1" 72 | else 73 | PKG_CHECK_EXISTS([$3], 74 | [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], 75 | [pkg_failed=yes]) 76 | fi 77 | else 78 | pkg_failed=untried 79 | fi[]dnl 80 | ])# _PKG_CONFIG 81 | 82 | # _PKG_SHORT_ERRORS_SUPPORTED 83 | # ----------------------------- 84 | AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], 85 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) 86 | if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then 87 | _pkg_short_errors_supported=yes 88 | else 89 | _pkg_short_errors_supported=no 90 | fi[]dnl 91 | ])# _PKG_SHORT_ERRORS_SUPPORTED 92 | 93 | 94 | # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], 95 | # [ACTION-IF-NOT-FOUND]) 96 | # 97 | # 98 | # Note that if there is a possibility the first call to 99 | # PKG_CHECK_MODULES might not happen, you should be sure to include an 100 | # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac 101 | # 102 | # 103 | # -------------------------------------------------------------- 104 | AC_DEFUN([PKG_CHECK_MODULES], 105 | [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl 106 | AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl 107 | AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl 108 | 109 | pkg_failed=no 110 | AC_MSG_CHECKING([for $1]) 111 | 112 | _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) 113 | _PKG_CONFIG([$1][_LIBS], [libs], [$2]) 114 | 115 | m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS 116 | and $1[]_LIBS to avoid the need to call pkg-config. 117 | See the pkg-config man page for more details.]) 118 | 119 | if test $pkg_failed = yes; then 120 | _PKG_SHORT_ERRORS_SUPPORTED 121 | if test $_pkg_short_errors_supported = yes; then 122 | $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"` 123 | else 124 | $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` 125 | fi 126 | # Put the nasty error message in config.log where it belongs 127 | echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD 128 | 129 | ifelse([$4], , [AC_MSG_ERROR(dnl 130 | [Package requirements ($2) were not met: 131 | 132 | $$1_PKG_ERRORS 133 | 134 | Consider adjusting the PKG_CONFIG_PATH environment variable if you 135 | installed software in a non-standard prefix. 136 | 137 | _PKG_TEXT 138 | ])], 139 | [AC_MSG_RESULT([no]) 140 | $4]) 141 | elif test $pkg_failed = untried; then 142 | ifelse([$4], , [AC_MSG_FAILURE(dnl 143 | [The pkg-config script could not be found or is too old. Make sure it 144 | is in your PATH or set the PKG_CONFIG environment variable to the full 145 | path to pkg-config. 146 | 147 | _PKG_TEXT 148 | 149 | To get pkg-config, see .])], 150 | [$4]) 151 | else 152 | $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS 153 | $1[]_LIBS=$pkg_cv_[]$1[]_LIBS 154 | AC_MSG_RESULT([yes]) 155 | ifelse([$3], , :, [$3]) 156 | fi[]dnl 157 | ])# PKG_CHECK_MODULES 158 | -------------------------------------------------------------------------------- /hidapi/mac/.gitignore: -------------------------------------------------------------------------------- 1 | Debug 2 | Release 3 | *.exp 4 | *.ilk 5 | *.lib 6 | *.suo 7 | *.vcproj.* 8 | *.ncb 9 | *.suo 10 | *.dll 11 | *.pdb 12 | *.o 13 | hidapi-hidtest 14 | .deps 15 | .libs 16 | *.la 17 | *.lo 18 | -------------------------------------------------------------------------------- /hidapi/mac/Makefile-manual: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Simple Makefile for HIDAPI test program 3 | # 4 | # Alan Ott 5 | # Signal 11 Software 6 | # 2010-07-03 7 | ########################################### 8 | 9 | all: hidtest 10 | 11 | CC=gcc 12 | CXX=g++ 13 | COBJS=hid.o ../hidtest/test.o 14 | OBJS=$(COBJS) 15 | CFLAGS+=-I../hidapi -Wall -g -c 16 | LIBS=-framework IOKit -framework CoreFoundation 17 | 18 | 19 | hidtest: $(OBJS) 20 | $(CC) -Wall -g $^ $(LIBS) -o hidtest 21 | 22 | $(COBJS): %.o: %.c 23 | $(CC) $(CFLAGS) $< -o $@ 24 | 25 | $(CPPOBJS): %.o: %.cpp 26 | $(CXX) $(CFLAGS) $< -o $@ 27 | 28 | clean: 29 | rm -f *.o hidtest $(CPPOBJS) 30 | 31 | .PHONY: clean 32 | -------------------------------------------------------------------------------- /hidapi/mac/Makefile.am: -------------------------------------------------------------------------------- 1 | lib_LTLIBRARIES = libhidapi.la 2 | libhidapi_la_SOURCES = hid.c 3 | libhidapi_la_LDFLAGS = $(LTLDFLAGS) 4 | AM_CPPFLAGS = -I$(top_srcdir)/hidapi/ 5 | 6 | hdrdir = $(includedir)/hidapi 7 | hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h 8 | 9 | EXTRA_DIST = Makefile-manual 10 | -------------------------------------------------------------------------------- /hidapi/mac/hidtest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/hidapi/mac/hidtest -------------------------------------------------------------------------------- /hidapi/pc/.gitignore: -------------------------------------------------------------------------------- 1 | *.pc 2 | -------------------------------------------------------------------------------- /hidapi/pc/hidapi-hidraw.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: hidapi-hidraw 7 | Description: C Library for USB/Bluetooth HID device access from Linux, Mac OS X, FreeBSD, and Windows. This is the hidraw implementation. 8 | Version: @VERSION@ 9 | Libs: -L${libdir} -lhidapi-hidraw 10 | Cflags: -I${includedir}/hidapi 11 | -------------------------------------------------------------------------------- /hidapi/pc/hidapi-libusb.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: hidapi-libusb 7 | Description: C Library for USB HID device access from Linux, Mac OS X, FreeBSD, and Windows. This is the libusb implementation. 8 | Version: @VERSION@ 9 | Libs: -L${libdir} -lhidapi-libusb 10 | Cflags: -I${includedir}/hidapi 11 | -------------------------------------------------------------------------------- /hidapi/pc/hidapi.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: hidapi 7 | Description: C Library for USB/Bluetooth HID device access from Linux, Mac OS X, FreeBSD, and Windows. 8 | Version: @VERSION@ 9 | Libs: -L${libdir} -lhidapi 10 | Cflags: -I${includedir}/hidapi 11 | -------------------------------------------------------------------------------- /hidapi/testgui/.gitignore: -------------------------------------------------------------------------------- 1 | Debug 2 | Release 3 | *.exp 4 | *.ilk 5 | *.lib 6 | *.suo 7 | *.vcproj.* 8 | *.ncb 9 | *.suo 10 | *.dll 11 | *.pdb 12 | *.o 13 | hidapi-testgui 14 | hidapi-hidraw-testgui 15 | hidapi-libusb-testgui 16 | .deps 17 | .libs 18 | *.la 19 | *.lo 20 | TestGUI.app 21 | -------------------------------------------------------------------------------- /hidapi/testgui/Makefile-manual: -------------------------------------------------------------------------------- 1 | 2 | 3 | OS=$(shell uname) 4 | 5 | ifeq ($(OS), Darwin) 6 | FILE=Makefile.mac 7 | endif 8 | 9 | ifneq (,$(findstring MINGW,$(OS))) 10 | FILE=Makefile.mingw 11 | endif 12 | 13 | ifeq ($(OS), Linux) 14 | FILE=Makefile.linux 15 | endif 16 | 17 | ifeq ($(OS), FreeBSD) 18 | FILE=Makefile.freebsd 19 | endif 20 | 21 | ifeq ($(FILE), ) 22 | all: 23 | $(error Your platform ${OS} is not supported at this time.) 24 | endif 25 | 26 | include $(FILE) 27 | -------------------------------------------------------------------------------- /hidapi/testgui/Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | AM_CPPFLAGS = -I$(top_srcdir)/hidapi/ $(CFLAGS_TESTGUI) 3 | 4 | if OS_LINUX 5 | ## Linux 6 | bin_PROGRAMS = hidapi-hidraw-testgui hidapi-libusb-testgui 7 | 8 | hidapi_hidraw_testgui_SOURCES = test.cpp 9 | hidapi_hidraw_testgui_LDADD = $(top_builddir)/linux/libhidapi-hidraw.la $(LIBS_TESTGUI) 10 | 11 | hidapi_libusb_testgui_SOURCES = test.cpp 12 | hidapi_libusb_testgui_LDADD = $(top_builddir)/libusb/libhidapi-libusb.la $(LIBS_TESTGUI) 13 | else 14 | ## Other OS's 15 | bin_PROGRAMS = hidapi-testgui 16 | 17 | hidapi_testgui_SOURCES = test.cpp 18 | hidapi_testgui_LDADD = $(top_builddir)/$(backend)/libhidapi.la $(LIBS_TESTGUI) 19 | endif 20 | 21 | if OS_DARWIN 22 | hidapi_testgui_SOURCES = test.cpp mac_support_cocoa.m mac_support.h 23 | # Rules for copying the binary and its dependencies into the app bundle. 24 | TestGUI.app/Contents/MacOS/hidapi-testgui$(EXEEXT): hidapi-testgui$(EXEEXT) 25 | $(srcdir)/copy_to_bundle.sh 26 | 27 | all: all-am TestGUI.app/Contents/MacOS/hidapi-testgui$(EXEEXT) 28 | 29 | endif 30 | 31 | EXTRA_DIST = \ 32 | copy_to_bundle.sh \ 33 | Makefile-manual \ 34 | Makefile.freebsd \ 35 | Makefile.linux \ 36 | Makefile.mac \ 37 | Makefile.mingw \ 38 | TestGUI.app.in \ 39 | testgui.sln \ 40 | testgui.vcproj 41 | 42 | distclean-local: 43 | rm -rf TestGUI.app 44 | -------------------------------------------------------------------------------- /hidapi/testgui/Makefile.freebsd: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Simple Makefile for HIDAPI test program 3 | # 4 | # Alan Ott 5 | # Signal 11 Software 6 | # 2010-06-01 7 | ########################################### 8 | 9 | all: testgui 10 | 11 | CC=cc 12 | CXX=c++ 13 | COBJS=../libusb/hid.o 14 | CPPOBJS=test.o 15 | OBJS=$(COBJS) $(CPPOBJS) 16 | CFLAGS=-I../hidapi -I/usr/local/include `fox-config --cflags` -Wall -g -c 17 | LDFLAGS= -L/usr/local/lib 18 | LIBS= -lusb -liconv `fox-config --libs` -pthread 19 | 20 | 21 | testgui: $(OBJS) 22 | $(CXX) -Wall -g $^ $(LDFLAGS) -o $@ $(LIBS) 23 | 24 | $(COBJS): %.o: %.c 25 | $(CC) $(CFLAGS) $< -o $@ 26 | 27 | $(CPPOBJS): %.o: %.cpp 28 | $(CXX) $(CFLAGS) $< -o $@ 29 | 30 | clean: 31 | rm *.o testgui 32 | 33 | .PHONY: clean 34 | -------------------------------------------------------------------------------- /hidapi/testgui/Makefile.linux: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Simple Makefile for HIDAPI test program 3 | # 4 | # Alan Ott 5 | # Signal 11 Software 6 | # 2010-06-01 7 | ########################################### 8 | 9 | all: testgui 10 | 11 | CC=gcc 12 | CXX=g++ 13 | COBJS=../libusb/hid.o 14 | CPPOBJS=test.o 15 | OBJS=$(COBJS) $(CPPOBJS) 16 | CFLAGS=-I../hidapi -Wall -g -c `fox-config --cflags` `pkg-config libusb-1.0 --cflags` 17 | LIBS=-ludev -lrt -lpthread `fox-config --libs` `pkg-config libusb-1.0 --libs` 18 | 19 | 20 | testgui: $(OBJS) 21 | g++ -Wall -g $^ $(LIBS) -o testgui 22 | 23 | $(COBJS): %.o: %.c 24 | $(CC) $(CFLAGS) $< -o $@ 25 | 26 | $(CPPOBJS): %.o: %.cpp 27 | $(CXX) $(CFLAGS) $< -o $@ 28 | 29 | clean: 30 | rm *.o testgui 31 | 32 | .PHONY: clean 33 | -------------------------------------------------------------------------------- /hidapi/testgui/Makefile.mac: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Simple Makefile for HIDAPI test program 3 | # 4 | # Alan Ott 5 | # Signal 11 Software 6 | # 2010-07-03 7 | ########################################### 8 | 9 | all: hidapi-testgui 10 | 11 | CC=gcc 12 | CXX=g++ 13 | COBJS=../mac/hid.o 14 | CPPOBJS=test.o 15 | OBJCOBJS=mac_support_cocoa.o 16 | OBJS=$(COBJS) $(CPPOBJS) $(OBJCOBJS) 17 | CFLAGS=-I../hidapi -Wall -g -c `fox-config --cflags` 18 | LDFLAGS=-L/usr/X11R6/lib 19 | LIBS=`fox-config --libs` -framework IOKit -framework CoreFoundation -framework Cocoa 20 | 21 | 22 | hidapi-testgui: $(OBJS) TestGUI.app 23 | g++ -Wall -g $(OBJS) $(LIBS) $(LDFLAGS) -o hidapi-testgui 24 | ./copy_to_bundle.sh 25 | #cp TestGUI.app/Contents/MacOS/hidapi-testgui TestGUI.app/Contents/MacOS/tg 26 | #cp start.sh TestGUI.app/Contents/MacOS/hidapi-testgui 27 | 28 | $(COBJS): %.o: %.c 29 | $(CC) $(CFLAGS) $< -o $@ 30 | 31 | $(CPPOBJS): %.o: %.cpp 32 | $(CXX) $(CFLAGS) $< -o $@ 33 | 34 | $(OBJCOBJS): %.o: %.m 35 | $(CXX) $(CFLAGS) -x objective-c++ $< -o $@ 36 | 37 | TestGUI.app: TestGUI.app.in 38 | rm -Rf TestGUI.app 39 | mkdir -p TestGUI.app 40 | cp -R TestGUI.app.in/ TestGUI.app 41 | 42 | clean: 43 | rm -f $(OBJS) hidapi-testgui 44 | rm -Rf TestGUI.app 45 | 46 | .PHONY: clean 47 | -------------------------------------------------------------------------------- /hidapi/testgui/Makefile.mingw: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Simple Makefile for HIDAPI test program 3 | # 4 | # Alan Ott 5 | # Signal 11 Software 6 | # 2010-06-01 7 | ########################################### 8 | 9 | all: hidapi-testgui 10 | 11 | CC=gcc 12 | CXX=g++ 13 | COBJS=../windows/hid.o 14 | CPPOBJS=test.o 15 | OBJS=$(COBJS) $(CPPOBJS) 16 | CFLAGS=-I../hidapi -I../../hidapi-externals/fox/include -g -c 17 | LIBS= -mwindows -lsetupapi -L../../hidapi-externals/fox/lib -Wl,-Bstatic -lFOX-1.6 -Wl,-Bdynamic -lgdi32 -Wl,--enable-auto-import -static-libgcc -static-libstdc++ -lkernel32 18 | 19 | 20 | hidapi-testgui: $(OBJS) 21 | g++ -g $^ $(LIBS) -o hidapi-testgui 22 | 23 | $(COBJS): %.o: %.c 24 | $(CC) $(CFLAGS) $< -o $@ 25 | 26 | $(CPPOBJS): %.o: %.cpp 27 | $(CXX) $(CFLAGS) $< -o $@ 28 | 29 | clean: 30 | rm -f *.o hidapi-testgui.exe 31 | 32 | .PHONY: clean 33 | -------------------------------------------------------------------------------- /hidapi/testgui/TestGUI.app.in/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | 9 | CFBundleExecutable 10 | hidapi-testgui 11 | CFBundleIconFile 12 | Signal11.icns 13 | CFBundleIdentifier 14 | us.signal11.hidtestgui 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | testgui 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | CSResourcesFileMapped 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /hidapi/testgui/TestGUI.app.in/Contents/PkgInfo: -------------------------------------------------------------------------------- 1 | APPL???? -------------------------------------------------------------------------------- /hidapi/testgui/TestGUI.app.in/Contents/Resources/English.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/hidapi/testgui/TestGUI.app.in/Contents/Resources/English.lproj/InfoPlist.strings -------------------------------------------------------------------------------- /hidapi/testgui/TestGUI.app.in/Contents/Resources/Signal11.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/hidapi/testgui/TestGUI.app.in/Contents/Resources/Signal11.icns -------------------------------------------------------------------------------- /hidapi/testgui/copy_to_bundle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #### Configuration: 4 | # The name of the executable. It is assumed 5 | # that it is in the current working directory. 6 | EXE_NAME=hidapi-testgui 7 | # Path to the executable directory inside the bundle. 8 | # This must be an absolute path, so use $PWD. 9 | EXEPATH=$PWD/TestGUI.app/Contents/MacOS 10 | # Libraries to explicitly bundle, even though they 11 | # may not be in /opt/local. One per line. These 12 | # are used with grep, so only a portion of the name 13 | # is required. eg: libFOX, libz, etc. 14 | LIBS_TO_BUNDLE=libFOX 15 | 16 | 17 | function copydeps { 18 | local file=$1 19 | # echo "Copying deps for $file...." 20 | local BASE_OF_EXE=`basename $file` 21 | 22 | # A will contain the dependencies of this library 23 | local A=`otool -LX $file |cut -f 1 -d " "` 24 | local i 25 | for i in $A; do 26 | local BASE=`basename $i` 27 | 28 | # See if it's a lib we specifically want to bundle 29 | local bundle_this_lib=0 30 | local j 31 | for j in $LIBS_TO_BUNDLE; do 32 | echo $i |grep -q $j 33 | if [ $? -eq 0 ]; then 34 | bundle_this_lib=1 35 | echo "bundling $i because it's in the list." 36 | break; 37 | fi 38 | done 39 | 40 | # See if it's in /opt/local. Bundle all in /opt/local 41 | local isOptLocal=0 42 | echo $i |grep -q /opt/local 43 | if [ $? -eq 0 ]; then 44 | isOptLocal=1 45 | echo "bundling $i because it's in /opt/local." 46 | fi 47 | 48 | # Bundle the library 49 | if [ $isOptLocal -ne 0 ] || [ $bundle_this_lib -ne 0 ]; then 50 | 51 | # Copy the file into the bundle if it exists. 52 | if [ -f $EXEPATH/$BASE ]; then 53 | z=0 54 | else 55 | cp $i $EXEPATH 56 | chmod 755 $EXEPATH/$BASE 57 | fi 58 | 59 | 60 | # echo "$BASE_OF_EXE depends on $BASE" 61 | 62 | # Fix the paths using install_name_tool and then 63 | # call this function recursively for each dependency 64 | # of this library. 65 | if [ $BASE_OF_EXE != $BASE ]; then 66 | 67 | # Fix the paths 68 | install_name_tool -id @executable_path/$BASE $EXEPATH/$BASE 69 | install_name_tool -change $i @executable_path/$BASE $EXEPATH/$BASE_OF_EXE 70 | 71 | # Call this function (recursive) on 72 | # on each dependency of this library. 73 | copydeps $EXEPATH/$BASE 74 | fi 75 | fi 76 | done 77 | } 78 | 79 | rm -f $EXEPATH/* 80 | 81 | # Copy the binary into the bundle. Use ../libtool to do this if it's 82 | # available because if $EXE_NAME was built with autotools, it will be 83 | # necessary. If ../libtool not available, just use cp to do the copy, but 84 | # only if $EXE_NAME is a binary. 85 | if [ -x ../libtool ]; then 86 | ../libtool --mode=install cp $EXE_NAME $EXEPATH 87 | else 88 | file -bI $EXE_NAME |grep binary 89 | if [ $? -ne 0 ]; then 90 | echo "There is no ../libtool and $EXE_NAME is not a binary." 91 | echo "I'm not sure what to do." 92 | exit 1 93 | else 94 | cp $EXE_NAME $EXEPATH 95 | fi 96 | fi 97 | copydeps $EXEPATH/$EXE_NAME 98 | -------------------------------------------------------------------------------- /hidapi/testgui/mac_support.h: -------------------------------------------------------------------------------- 1 | /******************************* 2 | Mac support for HID Test GUI 3 | 4 | Alan Ott 5 | Signal 11 Software 6 | 7 | *******************************/ 8 | 9 | #ifndef MAC_SUPPORT_H__ 10 | #define MAC_SUPPORT_H__ 11 | 12 | extern "C" { 13 | void init_apple_message_system(); 14 | void check_apple_events(); 15 | } 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /hidapi/testgui/mac_support_cocoa.m: -------------------------------------------------------------------------------- 1 | /******************************* 2 | Mac support for HID Test GUI 3 | 4 | Alan Ott 5 | Signal 11 Software 6 | *******************************/ 7 | 8 | #include 9 | #import 10 | 11 | #ifndef MAC_OS_X_VERSION_10_12 12 | #define MAC_OS_X_VERSION_10_12 101200 13 | #endif 14 | 15 | // macOS 10.12 deprecated NSAnyEventMask in favor of NSEventMaskAny 16 | #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12 17 | #define NSEventMaskAny NSAnyEventMask 18 | #endif 19 | 20 | extern FXMainWindow *g_main_window; 21 | 22 | 23 | @interface MyAppDelegate : NSObject 24 | { 25 | } 26 | @end 27 | 28 | @implementation MyAppDelegate 29 | - (void) applicationWillBecomeActive:(NSNotification*)notif 30 | { 31 | printf("WillBecomeActive\n"); 32 | g_main_window->show(); 33 | 34 | } 35 | 36 | - (void) applicationWillTerminate:(NSNotification*)notif 37 | { 38 | /* Doesn't get called. Not sure why */ 39 | printf("WillTerminate\n"); 40 | FXApp::instance()->exit(); 41 | } 42 | 43 | - (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*)sender 44 | { 45 | /* Doesn't get called. Not sure why */ 46 | printf("ShouldTerminate\n"); 47 | return YES; 48 | } 49 | 50 | - (void) applicationWillHide:(NSNotification*)notif 51 | { 52 | printf("WillHide\n"); 53 | g_main_window->hide(); 54 | } 55 | 56 | - (void) handleQuitEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)replyEvent 57 | { 58 | printf("QuitEvent\n"); 59 | FXApp::instance()->exit(); 60 | } 61 | 62 | @end 63 | 64 | extern "C" { 65 | 66 | void 67 | init_apple_message_system() 68 | { 69 | static MyAppDelegate *d = [MyAppDelegate new]; 70 | 71 | [[NSApplication sharedApplication] setDelegate:d]; 72 | 73 | /* Register for Apple Events. */ 74 | /* This is from 75 | http://stackoverflow.com/questions/1768497/application-exit-event */ 76 | NSAppleEventManager *aem = [NSAppleEventManager sharedAppleEventManager]; 77 | [aem setEventHandler:d 78 | andSelector:@selector(handleQuitEvent:withReplyEvent:) 79 | forEventClass:kCoreEventClass andEventID:kAEQuitApplication]; 80 | } 81 | 82 | void 83 | check_apple_events() 84 | { 85 | NSApplication *app = [NSApplication sharedApplication]; 86 | 87 | NSAutoreleasePool *pool = [NSAutoreleasePool new]; 88 | while (1) { 89 | NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny 90 | untilDate:nil 91 | inMode:NSDefaultRunLoopMode 92 | dequeue:YES]; 93 | if (event == NULL) 94 | break; 95 | else { 96 | //printf("Event happened: Type: %d\n", event->_type); 97 | [app sendEvent: event]; 98 | } 99 | } 100 | [pool release]; 101 | } 102 | 103 | } /* extern "C" */ 104 | -------------------------------------------------------------------------------- /hidapi/testgui/test.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************* 2 | Demo Program for HIDAPI 3 | 4 | Alan Ott 5 | Signal 11 Software 6 | 7 | 2010-07-20 8 | 9 | Copyright 2010, All Rights Reserved 10 | 11 | This contents of this file may be used by anyone 12 | for any reason without any conditions and may be 13 | used as a starting point for your own applications 14 | which use HIDAPI. 15 | ********************************************************/ 16 | 17 | 18 | #include 19 | 20 | #include "hidapi.h" 21 | #include "mac_support.h" 22 | #include 23 | #include 24 | #include 25 | 26 | #ifdef _WIN32 27 | // Thanks Microsoft, but I know how to use strncpy(). 28 | #pragma warning(disable:4996) 29 | #endif 30 | 31 | class MainWindow : public FXMainWindow { 32 | FXDECLARE(MainWindow) 33 | 34 | public: 35 | enum { 36 | ID_FIRST = FXMainWindow::ID_LAST, 37 | ID_CONNECT, 38 | ID_DISCONNECT, 39 | ID_RESCAN, 40 | ID_SEND_OUTPUT_REPORT, 41 | ID_SEND_FEATURE_REPORT, 42 | ID_GET_FEATURE_REPORT, 43 | ID_CLEAR, 44 | ID_TIMER, 45 | ID_MAC_TIMER, 46 | ID_LAST, 47 | }; 48 | 49 | private: 50 | FXList *device_list; 51 | FXButton *connect_button; 52 | FXButton *disconnect_button; 53 | FXButton *rescan_button; 54 | FXButton *output_button; 55 | FXLabel *connected_label; 56 | FXTextField *output_text; 57 | FXTextField *output_len; 58 | FXButton *feature_button; 59 | FXButton *get_feature_button; 60 | FXTextField *feature_text; 61 | FXTextField *feature_len; 62 | FXTextField *get_feature_text; 63 | FXText *input_text; 64 | FXFont *title_font; 65 | 66 | struct hid_device_info *devices; 67 | hid_device *connected_device; 68 | size_t getDataFromTextField(FXTextField *tf, char *buf, size_t len); 69 | int getLengthFromTextField(FXTextField *tf); 70 | 71 | 72 | protected: 73 | MainWindow() {}; 74 | public: 75 | MainWindow(FXApp *a); 76 | ~MainWindow(); 77 | virtual void create(); 78 | 79 | long onConnect(FXObject *sender, FXSelector sel, void *ptr); 80 | long onDisconnect(FXObject *sender, FXSelector sel, void *ptr); 81 | long onRescan(FXObject *sender, FXSelector sel, void *ptr); 82 | long onSendOutputReport(FXObject *sender, FXSelector sel, void *ptr); 83 | long onSendFeatureReport(FXObject *sender, FXSelector sel, void *ptr); 84 | long onGetFeatureReport(FXObject *sender, FXSelector sel, void *ptr); 85 | long onClear(FXObject *sender, FXSelector sel, void *ptr); 86 | long onTimeout(FXObject *sender, FXSelector sel, void *ptr); 87 | long onMacTimeout(FXObject *sender, FXSelector sel, void *ptr); 88 | }; 89 | 90 | // FOX 1.7 changes the timeouts to all be nanoseconds. 91 | // Fox 1.6 had all timeouts as milliseconds. 92 | #if (FOX_MINOR >= 7) 93 | const int timeout_scalar = 1000*1000; 94 | #else 95 | const int timeout_scalar = 1; 96 | #endif 97 | 98 | FXMainWindow *g_main_window; 99 | 100 | 101 | FXDEFMAP(MainWindow) MainWindowMap [] = { 102 | FXMAPFUNC(SEL_COMMAND, MainWindow::ID_CONNECT, MainWindow::onConnect ), 103 | FXMAPFUNC(SEL_COMMAND, MainWindow::ID_DISCONNECT, MainWindow::onDisconnect ), 104 | FXMAPFUNC(SEL_COMMAND, MainWindow::ID_RESCAN, MainWindow::onRescan ), 105 | FXMAPFUNC(SEL_COMMAND, MainWindow::ID_SEND_OUTPUT_REPORT, MainWindow::onSendOutputReport ), 106 | FXMAPFUNC(SEL_COMMAND, MainWindow::ID_SEND_FEATURE_REPORT, MainWindow::onSendFeatureReport ), 107 | FXMAPFUNC(SEL_COMMAND, MainWindow::ID_GET_FEATURE_REPORT, MainWindow::onGetFeatureReport ), 108 | FXMAPFUNC(SEL_COMMAND, MainWindow::ID_CLEAR, MainWindow::onClear ), 109 | FXMAPFUNC(SEL_TIMEOUT, MainWindow::ID_TIMER, MainWindow::onTimeout ), 110 | FXMAPFUNC(SEL_TIMEOUT, MainWindow::ID_MAC_TIMER, MainWindow::onMacTimeout ), 111 | }; 112 | 113 | FXIMPLEMENT(MainWindow, FXMainWindow, MainWindowMap, ARRAYNUMBER(MainWindowMap)); 114 | 115 | MainWindow::MainWindow(FXApp *app) 116 | : FXMainWindow(app, "HIDAPI Test Application", NULL, NULL, DECOR_ALL, 200,100, 425,700) 117 | { 118 | devices = NULL; 119 | connected_device = NULL; 120 | 121 | FXVerticalFrame *vf = new FXVerticalFrame(this, LAYOUT_FILL_Y|LAYOUT_FILL_X); 122 | 123 | FXLabel *label = new FXLabel(vf, "HIDAPI Test Tool"); 124 | title_font = new FXFont(getApp(), "Arial", 14, FXFont::Bold); 125 | label->setFont(title_font); 126 | 127 | new FXLabel(vf, 128 | "Select a device and press Connect.", NULL, JUSTIFY_LEFT); 129 | new FXLabel(vf, 130 | "Output data bytes can be entered in the Output section, \n" 131 | "separated by space, comma or brackets. Data starting with 0x\n" 132 | "is treated as hex. Data beginning with a 0 is treated as \n" 133 | "octal. All other data is treated as decimal.", NULL, JUSTIFY_LEFT); 134 | new FXLabel(vf, 135 | "Data received from the device appears in the Input section.", 136 | NULL, JUSTIFY_LEFT); 137 | new FXLabel(vf, 138 | "Optionally, a report length may be specified. Extra bytes are\n" 139 | "padded with zeros. If no length is specified, the length is \n" 140 | "inferred from the data.", 141 | NULL, JUSTIFY_LEFT); 142 | new FXLabel(vf, ""); 143 | 144 | // Device List and Connect/Disconnect buttons 145 | FXHorizontalFrame *hf = new FXHorizontalFrame(vf, LAYOUT_FILL_X); 146 | //device_list = new FXList(new FXHorizontalFrame(hf,FRAME_SUNKEN|FRAME_THICK, 0,0,0,0, 0,0,0,0), NULL, 0, LISTBOX_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0,0,300,200); 147 | device_list = new FXList(new FXHorizontalFrame(hf,FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0), NULL, 0, LISTBOX_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,300,200); 148 | FXVerticalFrame *buttonVF = new FXVerticalFrame(hf); 149 | connect_button = new FXButton(buttonVF, "Connect", NULL, this, ID_CONNECT, BUTTON_NORMAL|LAYOUT_FILL_X); 150 | disconnect_button = new FXButton(buttonVF, "Disconnect", NULL, this, ID_DISCONNECT, BUTTON_NORMAL|LAYOUT_FILL_X); 151 | disconnect_button->disable(); 152 | rescan_button = new FXButton(buttonVF, "Re-Scan devices", NULL, this, ID_RESCAN, BUTTON_NORMAL|LAYOUT_FILL_X); 153 | new FXHorizontalFrame(buttonVF, 0, 0,0,0,0, 0,0,50,0); 154 | 155 | connected_label = new FXLabel(vf, "Disconnected"); 156 | 157 | new FXHorizontalFrame(vf); 158 | 159 | // Output Group Box 160 | FXGroupBox *gb = new FXGroupBox(vf, "Output", FRAME_GROOVE|LAYOUT_FILL_X); 161 | FXMatrix *matrix = new FXMatrix(gb, 3, MATRIX_BY_COLUMNS|LAYOUT_FILL_X); 162 | new FXLabel(matrix, "Data"); 163 | new FXLabel(matrix, "Length"); 164 | new FXLabel(matrix, ""); 165 | 166 | //hf = new FXHorizontalFrame(gb, LAYOUT_FILL_X); 167 | output_text = new FXTextField(matrix, 30, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN); 168 | output_text->setText("1 0x81 0"); 169 | output_len = new FXTextField(matrix, 5, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN); 170 | output_button = new FXButton(matrix, "Send Output Report", NULL, this, ID_SEND_OUTPUT_REPORT, BUTTON_NORMAL|LAYOUT_FILL_X); 171 | output_button->disable(); 172 | //new FXHorizontalFrame(matrix, LAYOUT_FILL_X); 173 | 174 | //hf = new FXHorizontalFrame(gb, LAYOUT_FILL_X); 175 | feature_text = new FXTextField(matrix, 30, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN); 176 | feature_len = new FXTextField(matrix, 5, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN); 177 | feature_button = new FXButton(matrix, "Send Feature Report", NULL, this, ID_SEND_FEATURE_REPORT, BUTTON_NORMAL|LAYOUT_FILL_X); 178 | feature_button->disable(); 179 | 180 | get_feature_text = new FXTextField(matrix, 30, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN); 181 | new FXWindow(matrix); 182 | get_feature_button = new FXButton(matrix, "Get Feature Report", NULL, this, ID_GET_FEATURE_REPORT, BUTTON_NORMAL|LAYOUT_FILL_X); 183 | get_feature_button->disable(); 184 | 185 | 186 | // Input Group Box 187 | gb = new FXGroupBox(vf, "Input", FRAME_GROOVE|LAYOUT_FILL_X|LAYOUT_FILL_Y); 188 | FXVerticalFrame *innerVF = new FXVerticalFrame(gb, LAYOUT_FILL_X|LAYOUT_FILL_Y); 189 | input_text = new FXText(new FXHorizontalFrame(innerVF,LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, 0,0,0,0, 0,0,0,0), NULL, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y); 190 | input_text->setEditable(false); 191 | new FXButton(innerVF, "Clear", NULL, this, ID_CLEAR, BUTTON_NORMAL|LAYOUT_RIGHT); 192 | 193 | 194 | } 195 | 196 | MainWindow::~MainWindow() 197 | { 198 | if (connected_device) 199 | hid_close(connected_device); 200 | hid_exit(); 201 | delete title_font; 202 | } 203 | 204 | void 205 | MainWindow::create() 206 | { 207 | FXMainWindow::create(); 208 | show(); 209 | 210 | onRescan(NULL, 0, NULL); 211 | 212 | 213 | #ifdef __APPLE__ 214 | init_apple_message_system(); 215 | #endif 216 | 217 | getApp()->addTimeout(this, ID_MAC_TIMER, 218 | 50 * timeout_scalar /*50ms*/); 219 | } 220 | 221 | long 222 | MainWindow::onConnect(FXObject *sender, FXSelector sel, void *ptr) 223 | { 224 | if (connected_device != NULL) 225 | return 1; 226 | 227 | FXint cur_item = device_list->getCurrentItem(); 228 | if (cur_item < 0) 229 | return -1; 230 | FXListItem *item = device_list->getItem(cur_item); 231 | if (!item) 232 | return -1; 233 | struct hid_device_info *device_info = (struct hid_device_info*) item->getData(); 234 | if (!device_info) 235 | return -1; 236 | 237 | connected_device = hid_open_path(device_info->path); 238 | 239 | if (!connected_device) { 240 | FXMessageBox::error(this, MBOX_OK, "Device Error", "Unable To Connect to Device"); 241 | return -1; 242 | } 243 | 244 | hid_set_nonblocking(connected_device, 1); 245 | 246 | getApp()->addTimeout(this, ID_TIMER, 247 | 5 * timeout_scalar /*5ms*/); 248 | 249 | FXString s; 250 | s.format("Connected to: %04hx:%04hx -", device_info->vendor_id, device_info->product_id); 251 | s += FXString(" ") + device_info->manufacturer_string; 252 | s += FXString(" ") + device_info->product_string; 253 | connected_label->setText(s); 254 | output_button->enable(); 255 | feature_button->enable(); 256 | get_feature_button->enable(); 257 | connect_button->disable(); 258 | disconnect_button->enable(); 259 | input_text->setText(""); 260 | 261 | 262 | return 1; 263 | } 264 | 265 | long 266 | MainWindow::onDisconnect(FXObject *sender, FXSelector sel, void *ptr) 267 | { 268 | hid_close(connected_device); 269 | connected_device = NULL; 270 | connected_label->setText("Disconnected"); 271 | output_button->disable(); 272 | feature_button->disable(); 273 | get_feature_button->disable(); 274 | connect_button->enable(); 275 | disconnect_button->disable(); 276 | 277 | getApp()->removeTimeout(this, ID_TIMER); 278 | 279 | return 1; 280 | } 281 | 282 | long 283 | MainWindow::onRescan(FXObject *sender, FXSelector sel, void *ptr) 284 | { 285 | struct hid_device_info *cur_dev; 286 | 287 | device_list->clearItems(); 288 | 289 | // List the Devices 290 | hid_free_enumeration(devices); 291 | devices = hid_enumerate(0x0, 0x0); 292 | cur_dev = devices; 293 | while (cur_dev) { 294 | // Add it to the List Box. 295 | FXString s; 296 | FXString usage_str; 297 | s.format("%04hx:%04hx -", cur_dev->vendor_id, cur_dev->product_id); 298 | s += FXString(" ") + cur_dev->manufacturer_string; 299 | s += FXString(" ") + cur_dev->product_string; 300 | usage_str.format(" (usage: %04hx:%04hx) ", cur_dev->usage_page, cur_dev->usage); 301 | s += usage_str; 302 | FXListItem *li = new FXListItem(s, NULL, cur_dev); 303 | device_list->appendItem(li); 304 | 305 | cur_dev = cur_dev->next; 306 | } 307 | 308 | if (device_list->getNumItems() == 0) 309 | device_list->appendItem("*** No Devices Connected ***"); 310 | else { 311 | device_list->selectItem(0); 312 | } 313 | 314 | return 1; 315 | } 316 | 317 | size_t 318 | MainWindow::getDataFromTextField(FXTextField *tf, char *buf, size_t len) 319 | { 320 | const char *delim = " ,{}\t\r\n"; 321 | FXString data = tf->getText(); 322 | const FXchar *d = data.text(); 323 | size_t i = 0; 324 | 325 | // Copy the string from the GUI. 326 | size_t sz = strlen(d); 327 | char *str = (char*) malloc(sz+1); 328 | strcpy(str, d); 329 | 330 | // For each token in the string, parse and store in buf[]. 331 | char *token = strtok(str, delim); 332 | while (token) { 333 | char *endptr; 334 | long int val = strtol(token, &endptr, 0); 335 | buf[i++] = val; 336 | token = strtok(NULL, delim); 337 | } 338 | 339 | free(str); 340 | return i; 341 | } 342 | 343 | /* getLengthFromTextField() 344 | Returns length: 345 | 0: empty text field 346 | >0: valid length 347 | -1: invalid length */ 348 | int 349 | MainWindow::getLengthFromTextField(FXTextField *tf) 350 | { 351 | long int len; 352 | FXString str = tf->getText(); 353 | size_t sz = str.length(); 354 | 355 | if (sz > 0) { 356 | char *endptr; 357 | len = strtol(str.text(), &endptr, 0); 358 | if (endptr != str.text() && *endptr == '\0') { 359 | if (len <= 0) { 360 | FXMessageBox::error(this, MBOX_OK, "Invalid length", "Enter a length greater than zero."); 361 | return -1; 362 | } 363 | return len; 364 | } 365 | else 366 | return -1; 367 | } 368 | 369 | return 0; 370 | } 371 | 372 | long 373 | MainWindow::onSendOutputReport(FXObject *sender, FXSelector sel, void *ptr) 374 | { 375 | char buf[256]; 376 | size_t data_len, len; 377 | int textfield_len; 378 | 379 | memset(buf, 0x0, sizeof(buf)); 380 | textfield_len = getLengthFromTextField(output_len); 381 | data_len = getDataFromTextField(output_text, buf, sizeof(buf)); 382 | 383 | if (textfield_len < 0) { 384 | FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is invalid. Please enter a number in hex, octal, or decimal."); 385 | return 1; 386 | } 387 | 388 | if (textfield_len > sizeof(buf)) { 389 | FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is too long."); 390 | return 1; 391 | } 392 | 393 | len = (textfield_len)? textfield_len: data_len; 394 | 395 | int res = hid_write(connected_device, (const unsigned char*)buf, len); 396 | if (res < 0) { 397 | FXMessageBox::error(this, MBOX_OK, "Error Writing", "Could not write to device. Error reported was: %ls", hid_error(connected_device)); 398 | } 399 | 400 | return 1; 401 | } 402 | 403 | long 404 | MainWindow::onSendFeatureReport(FXObject *sender, FXSelector sel, void *ptr) 405 | { 406 | char buf[256]; 407 | size_t data_len, len; 408 | int textfield_len; 409 | 410 | memset(buf, 0x0, sizeof(buf)); 411 | textfield_len = getLengthFromTextField(feature_len); 412 | data_len = getDataFromTextField(feature_text, buf, sizeof(buf)); 413 | 414 | if (textfield_len < 0) { 415 | FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is invalid. Please enter a number in hex, octal, or decimal."); 416 | return 1; 417 | } 418 | 419 | if (textfield_len > sizeof(buf)) { 420 | FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is too long."); 421 | return 1; 422 | } 423 | 424 | len = (textfield_len)? textfield_len: data_len; 425 | 426 | int res = hid_send_feature_report(connected_device, (const unsigned char*)buf, len); 427 | if (res < 0) { 428 | FXMessageBox::error(this, MBOX_OK, "Error Writing", "Could not send feature report to device. Error reported was: %ls", hid_error(connected_device)); 429 | } 430 | 431 | return 1; 432 | } 433 | 434 | long 435 | MainWindow::onGetFeatureReport(FXObject *sender, FXSelector sel, void *ptr) 436 | { 437 | char buf[256]; 438 | size_t len; 439 | 440 | memset(buf, 0x0, sizeof(buf)); 441 | len = getDataFromTextField(get_feature_text, buf, sizeof(buf)); 442 | 443 | if (len != 1) { 444 | FXMessageBox::error(this, MBOX_OK, "Too many numbers", "Enter only a single report number in the text field"); 445 | } 446 | 447 | int res = hid_get_feature_report(connected_device, (unsigned char*)buf, sizeof(buf)); 448 | if (res < 0) { 449 | FXMessageBox::error(this, MBOX_OK, "Error Getting Report", "Could not get feature report from device. Error reported was: %ls", hid_error(connected_device)); 450 | } 451 | 452 | if (res > 0) { 453 | FXString s; 454 | s.format("Returned Feature Report. %d bytes:\n", res); 455 | for (int i = 0; i < res; i++) { 456 | FXString t; 457 | t.format("%02hhx ", buf[i]); 458 | s += t; 459 | if ((i+1) % 4 == 0) 460 | s += " "; 461 | if ((i+1) % 16 == 0) 462 | s += "\n"; 463 | } 464 | s += "\n"; 465 | input_text->appendText(s); 466 | input_text->setBottomLine(INT_MAX); 467 | } 468 | 469 | return 1; 470 | } 471 | 472 | long 473 | MainWindow::onClear(FXObject *sender, FXSelector sel, void *ptr) 474 | { 475 | input_text->setText(""); 476 | return 1; 477 | } 478 | 479 | long 480 | MainWindow::onTimeout(FXObject *sender, FXSelector sel, void *ptr) 481 | { 482 | unsigned char buf[256]; 483 | int res = hid_read(connected_device, buf, sizeof(buf)); 484 | 485 | if (res > 0) { 486 | FXString s; 487 | s.format("Received %d bytes:\n", res); 488 | for (int i = 0; i < res; i++) { 489 | FXString t; 490 | t.format("%02hhx ", buf[i]); 491 | s += t; 492 | if ((i+1) % 4 == 0) 493 | s += " "; 494 | if ((i+1) % 16 == 0) 495 | s += "\n"; 496 | } 497 | s += "\n"; 498 | input_text->appendText(s); 499 | input_text->setBottomLine(INT_MAX); 500 | } 501 | if (res < 0) { 502 | input_text->appendText("hid_read() returned error\n"); 503 | input_text->setBottomLine(INT_MAX); 504 | } 505 | 506 | getApp()->addTimeout(this, ID_TIMER, 507 | 5 * timeout_scalar /*5ms*/); 508 | return 1; 509 | } 510 | 511 | long 512 | MainWindow::onMacTimeout(FXObject *sender, FXSelector sel, void *ptr) 513 | { 514 | #ifdef __APPLE__ 515 | check_apple_events(); 516 | 517 | getApp()->addTimeout(this, ID_MAC_TIMER, 518 | 50 * timeout_scalar /*50ms*/); 519 | #endif 520 | 521 | return 1; 522 | } 523 | 524 | int main(int argc, char **argv) 525 | { 526 | FXApp app("HIDAPI Test Application", "Signal 11 Software"); 527 | app.init(argc, argv); 528 | g_main_window = new MainWindow(&app); 529 | app.create(); 530 | app.run(); 531 | return 0; 532 | } 533 | -------------------------------------------------------------------------------- /hidapi/testgui/testgui.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual C++ Express 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testgui", "testgui.vcproj", "{08769AC3-785A-4DDC-BFC7-1775414B7AB7}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {08769AC3-785A-4DDC-BFC7-1775414B7AB7}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {08769AC3-785A-4DDC-BFC7-1775414B7AB7}.Debug|Win32.Build.0 = Debug|Win32 14 | {08769AC3-785A-4DDC-BFC7-1775414B7AB7}.Release|Win32.ActiveCfg = Release|Win32 15 | {08769AC3-785A-4DDC-BFC7-1775414B7AB7}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /hidapi/testgui/testgui.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 53 | 56 | 59 | 62 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 95 | 96 | 104 | 107 | 110 | 113 | 116 | 119 | 131 | 134 | 137 | 140 | 153 | 156 | 159 | 162 | 165 | 168 | 171 | 175 | 176 | 177 | 178 | 179 | 180 | 185 | 188 | 189 | 192 | 193 | 194 | 199 | 202 | 203 | 204 | 209 | 210 | 213 | 214 | 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /hidapi/udev/99-hid.rules: -------------------------------------------------------------------------------- 1 | # This is a sample udev file for HIDAPI devices which changes the permissions 2 | # to 0666 (world readable/writable) for a specified device on Linux systems. 3 | 4 | 5 | # If you are using the libusb implementation of hidapi (libusb/hid.c), then 6 | # use something like the following line, substituting the VID and PID with 7 | # those of your device. Note that for kernels before 2.6.24, you will need 8 | # to substitute "usb" with "usb_device". It shouldn't hurt to use two lines 9 | # (one each way) for compatibility with older systems. 10 | 11 | # HIDAPI/libusb 12 | SUBSYSTEM=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="003f", MODE="0666" 13 | 14 | 15 | # If you are using the hidraw implementation (linux/hid.c), then do something 16 | # like the following, substituting the VID and PID with your device. Busnum 1 17 | # is USB. 18 | 19 | # HIDAPI/hidraw 20 | KERNEL=="hidraw*", ATTRS{busnum}=="1", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="003f", MODE="0666" 21 | 22 | # Once done, optionally rename this file for your device, and drop it into 23 | # /etc/udev/rules.d and unplug and re-plug your device. This is all that is 24 | # necessary to see the new permissions. Udev does not have to be restarted. 25 | 26 | # Note that the hexadecimal values for VID and PID are case sensitive and 27 | # must be lower case. 28 | 29 | # If you think permissions of 0666 are too loose, then see: 30 | # http://reactivated.net/writing_udev_rules.html for more information on finer 31 | # grained permission setting. For example, it might be sufficient to just 32 | # set the group or user owner for specific devices (for example the plugdev 33 | # group on some systems). 34 | -------------------------------------------------------------------------------- /hidapi/windows/.gitignore: -------------------------------------------------------------------------------- 1 | Debug 2 | Release 3 | .vs/ 4 | *.exp 5 | *.ilk 6 | *.lib 7 | *.suo 8 | *.vcproj.* 9 | *.vcxproj.* 10 | *.ncb 11 | *.suo 12 | *.dll 13 | *.pdb 14 | .deps 15 | .libs 16 | *.lo 17 | *.la 18 | -------------------------------------------------------------------------------- /hidapi/windows/Makefile-manual: -------------------------------------------------------------------------------- 1 | 2 | 3 | OS=$(shell uname) 4 | 5 | ifneq (,$(findstring MINGW,$(OS))) 6 | FILE=Makefile.mingw 7 | endif 8 | 9 | ifeq ($(FILE), ) 10 | all: 11 | $(error Your platform ${OS} is not supported at this time.) 12 | endif 13 | 14 | include $(FILE) 15 | -------------------------------------------------------------------------------- /hidapi/windows/Makefile.am: -------------------------------------------------------------------------------- 1 | lib_LTLIBRARIES = libhidapi.la 2 | libhidapi_la_SOURCES = hid.c 3 | libhidapi_la_LDFLAGS = $(LTLDFLAGS) 4 | AM_CPPFLAGS = -I$(top_srcdir)/hidapi/ 5 | libhidapi_la_LIBADD = $(LIBS) 6 | 7 | hdrdir = $(includedir)/hidapi 8 | hdr_HEADERS = $(top_srcdir)/hidapi/hidapi.h 9 | 10 | EXTRA_DIST = \ 11 | ddk_build \ 12 | hidapi.vcproj \ 13 | hidtest.vcproj \ 14 | Makefile-manual \ 15 | Makefile.mingw \ 16 | hidapi.sln 17 | -------------------------------------------------------------------------------- /hidapi/windows/Makefile.mingw: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Simple Makefile for HIDAPI test program 3 | # 4 | # Alan Ott 5 | # Signal 11 Software 6 | # 2010-06-01 7 | ########################################### 8 | 9 | all: hidtest libhidapi.dll 10 | 11 | CC=gcc 12 | CXX=g++ 13 | COBJS=hid.o 14 | CPPOBJS=../hidtest/hidtest.o 15 | OBJS=$(COBJS) $(CPPOBJS) 16 | CFLAGS=-I../hidapi -g -c 17 | LIBS= -lsetupapi 18 | DLL_LDFLAGS = -mwindows -lsetupapi 19 | 20 | hidtest: $(OBJS) 21 | g++ -g $^ $(LIBS) -o hidtest 22 | 23 | libhidapi.dll: $(OBJS) 24 | $(CC) -g $^ $(DLL_LDFLAGS) -o libhidapi.dll 25 | 26 | $(COBJS): %.o: %.c 27 | $(CC) $(CFLAGS) $< -o $@ 28 | 29 | $(CPPOBJS): %.o: %.cpp 30 | $(CXX) $(CFLAGS) $< -o $@ 31 | 32 | clean: 33 | rm *.o ../hidtest/*.o hidtest.exe 34 | 35 | .PHONY: clean 36 | -------------------------------------------------------------------------------- /hidapi/windows/ddk_build/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | obj*_*_* -------------------------------------------------------------------------------- /hidapi/windows/ddk_build/hidapi.def: -------------------------------------------------------------------------------- 1 | LIBRARY hidapi 2 | EXPORTS 3 | hid_open @1 4 | hid_write @2 5 | hid_read @3 6 | hid_close @4 7 | hid_get_product_string @5 8 | hid_get_manufacturer_string @6 9 | hid_get_serial_number_string @7 10 | hid_get_indexed_string @8 11 | hid_error @9 12 | hid_set_nonblocking @10 13 | hid_enumerate @11 14 | hid_open_path @12 15 | hid_send_feature_report @13 16 | hid_get_feature_report @14 17 | hid_get_input_report @15 18 | -------------------------------------------------------------------------------- /hidapi/windows/ddk_build/sources: -------------------------------------------------------------------------------- 1 | TARGETNAME=hidapi 2 | TARGETTYPE=DYNLINK 3 | UMTYPE=console 4 | UMENTRY=main 5 | 6 | MSC_WARNING_LEVEL=/W3 /WX 7 | 8 | TARGETLIBS=$(SDK_LIB_PATH)\hid.lib \ 9 | $(SDK_LIB_PATH)\setupapi.lib \ 10 | $(SDK_LIB_PATH)\kernel32.lib \ 11 | $(SDK_LIB_PATH)\comdlg32.lib 12 | 13 | USE_MSVCRT=1 14 | 15 | INCLUDES= ..\..\hidapi 16 | SOURCES= ..\hid.c \ 17 | 18 | 19 | TARGET_DESTINATION=retail 20 | 21 | MUI=0 22 | MUI_COMMENT="HID Interface DLL" 23 | 24 | -------------------------------------------------------------------------------- /hidapi/windows/hidapi.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.136 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hidapi", "hidapi.vcxproj", "{A107C21C-418A-4697-BB10-20C3AA60E2E4}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hidtest", "hidtest.vcxproj", "{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Win32 = Debug|Win32 13 | Debug|x64 = Debug|x64 14 | Release|Win32 = Release|Win32 15 | Release|x64 = Release|x64 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|Win32.ActiveCfg = Debug|Win32 19 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|Win32.Build.0 = Debug|Win32 20 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|x64.ActiveCfg = Debug|x64 21 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|x64.Build.0 = Debug|x64 22 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|Win32.ActiveCfg = Release|Win32 23 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|Win32.Build.0 = Release|Win32 24 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|x64.ActiveCfg = Release|x64 25 | {A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|x64.Build.0 = Release|x64 26 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|Win32.ActiveCfg = Debug|Win32 27 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|Win32.Build.0 = Debug|Win32 28 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|x64.ActiveCfg = Debug|x64 29 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|x64.Build.0 = Debug|x64 30 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|Win32.ActiveCfg = Release|Win32 31 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|Win32.Build.0 = Release|Win32 32 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|x64.ActiveCfg = Release|x64 33 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|x64.Build.0 = Release|x64 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {8749E535-9C65-4A89-840E-78D7578C7866} 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /hidapi/windows/hidapi.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 17 | 18 | 19 | 26 | 29 | 32 | 35 | 38 | 41 | 53 | 56 | 59 | 62 | 70 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 92 | 100 | 103 | 106 | 109 | 112 | 115 | 127 | 130 | 133 | 136 | 146 | 149 | 152 | 155 | 158 | 161 | 164 | 167 | 168 | 169 | 170 | 171 | 172 | 177 | 180 | 181 | 182 | 187 | 190 | 191 | 192 | 197 | 198 | 199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /hidapi/windows/hidapi.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {A107C21C-418A-4697-BB10-20C3AA60E2E4} 23 | hidapi 24 | Win32Proj 25 | 26 | 27 | 28 | DynamicLibrary 29 | v140 30 | Unicode 31 | true 32 | 33 | 34 | DynamicLibrary 35 | v140 36 | Unicode 37 | true 38 | 39 | 40 | DynamicLibrary 41 | v140 42 | Unicode 43 | 44 | 45 | DynamicLibrary 46 | v140 47 | Unicode 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | <_ProjectFileVersion>14.0.25431.1 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | Disabled 75 | ..\hidapi;%(AdditionalIncludeDirectories) 76 | WIN32;_DEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions) 77 | true 78 | EnableFastChecks 79 | MultiThreadedDebugDLL 80 | 81 | Level3 82 | EditAndContinue 83 | 84 | 85 | setupapi.lib;%(AdditionalDependencies) 86 | true 87 | Windows 88 | MachineX86 89 | 90 | 91 | 92 | 93 | Disabled 94 | ..\hidapi;%(AdditionalIncludeDirectories) 95 | WIN32;_DEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions) 96 | EnableFastChecks 97 | MultiThreadedDebugDLL 98 | 99 | 100 | Level3 101 | EditAndContinue 102 | 103 | 104 | setupapi.lib;%(AdditionalDependencies) 105 | true 106 | Windows 107 | 108 | 109 | 110 | 111 | MaxSpeed 112 | true 113 | ..\hidapi;%(AdditionalIncludeDirectories) 114 | WIN32;NDEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions) 115 | MultiThreaded 116 | true 117 | 118 | Level3 119 | ProgramDatabase 120 | 121 | 122 | setupapi.lib;%(AdditionalDependencies) 123 | true 124 | Windows 125 | true 126 | true 127 | MachineX86 128 | 129 | 130 | 131 | 132 | MaxSpeed 133 | true 134 | ..\hidapi;%(AdditionalIncludeDirectories) 135 | WIN32;NDEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions) 136 | MultiThreaded 137 | true 138 | 139 | 140 | Level3 141 | ProgramDatabase 142 | 143 | 144 | setupapi.lib;%(AdditionalDependencies) 145 | true 146 | Windows 147 | true 148 | true 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /hidapi/windows/hidtest.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 25 | 28 | 31 | 34 | 37 | 40 | 50 | 53 | 56 | 59 | 67 | 70 | 73 | 76 | 79 | 82 | 85 | 90 | 91 | 99 | 102 | 105 | 108 | 111 | 114 | 124 | 127 | 130 | 133 | 143 | 146 | 149 | 152 | 155 | 158 | 161 | 166 | 167 | 168 | 169 | 170 | 171 | 176 | 179 | 180 | 181 | 186 | 187 | 192 | 193 | 194 | 195 | 196 | 197 | -------------------------------------------------------------------------------- /hidapi/windows/hidtest.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {23E9FF6A-49D1-4993-B2B5-BBB992C6C712} 23 | hidtest 24 | 25 | 26 | 27 | Application 28 | v140 29 | MultiByte 30 | true 31 | 32 | 33 | Application 34 | v140 35 | MultiByte 36 | true 37 | 38 | 39 | Application 40 | v140 41 | MultiByte 42 | 43 | 44 | Application 45 | v140 46 | MultiByte 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | <_ProjectFileVersion>14.0.25431.1 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | Disabled 74 | ..\hidapi;%(AdditionalIncludeDirectories) 75 | true 76 | EnableFastChecks 77 | MultiThreadedDebugDLL 78 | Level3 79 | EditAndContinue 80 | 81 | 82 | hidapi.lib;%(AdditionalDependencies) 83 | $(SolutionDir)$(Configuration);%(AdditionalLibraryDirectories) 84 | true 85 | Console 86 | MachineX86 87 | 88 | 89 | 90 | 91 | Disabled 92 | ..\hidapi;%(AdditionalIncludeDirectories) 93 | EnableFastChecks 94 | MultiThreadedDebugDLL 95 | Level3 96 | EditAndContinue 97 | 98 | 99 | hidapi.lib;%(AdditionalDependencies) 100 | $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) 101 | true 102 | Console 103 | 104 | 105 | 106 | 107 | MaxSpeed 108 | true 109 | ..\hidapi;%(AdditionalIncludeDirectories) 110 | MultiThreaded 111 | true 112 | Level3 113 | ProgramDatabase 114 | 115 | 116 | hidapi.lib;%(AdditionalDependencies) 117 | $(SolutionDir)$(Configuration);%(AdditionalLibraryDirectories) 118 | true 119 | Console 120 | true 121 | true 122 | MachineX86 123 | 124 | 125 | 126 | 127 | MaxSpeed 128 | true 129 | ..\hidapi;%(AdditionalIncludeDirectories) 130 | MultiThreaded 131 | true 132 | Level3 133 | ProgramDatabase 134 | 135 | 136 | hidapi.lib;%(AdditionalDependencies) 137 | $(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories) 138 | true 139 | Console 140 | true 141 | true 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | {a107c21c-418a-4697-bb10-20c3aa60e2e4} 150 | false 151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /img/Logo.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/img/Logo.icns -------------------------------------------------------------------------------- /img/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/img/Logo.png -------------------------------------------------------------------------------- /img/Logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 42 | 44 | Created by potrace 1.13, written by Peter Selinger 2001-2015 45 | 46 | 48 | image/svg+xml 49 | 51 | 52 | 53 | 54 | 55 | 60 | 65 | 68 | 76 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /img/batt_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/img/batt_0.png -------------------------------------------------------------------------------- /img/batt_0_chr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/img/batt_0_chr.png -------------------------------------------------------------------------------- /img/batt_100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/img/batt_100.png -------------------------------------------------------------------------------- /img/batt_100_chr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/img/batt_100_chr.png -------------------------------------------------------------------------------- /img/batt_25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/img/batt_25.png -------------------------------------------------------------------------------- /img/batt_25_chr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/img/batt_25_chr.png -------------------------------------------------------------------------------- /img/batt_50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/img/batt_50.png -------------------------------------------------------------------------------- /img/batt_50_chr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/img/batt_50_chr.png -------------------------------------------------------------------------------- /img/batt_75.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/img/batt_75.png -------------------------------------------------------------------------------- /img/batt_75_chr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikmwerner/QJoyControl/0c6495329d13d62b42ef26271646a1393028e4e2/img/batt_75_chr.png -------------------------------------------------------------------------------- /img/retail_colors.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /inputmappanel.cpp: -------------------------------------------------------------------------------- 1 | #include "inputmappanel.h" 2 | #include "ui_inputmappanel.h" 3 | 4 | InputMapPanel::InputMapPanel(QWidget *parent) : 5 | QWidget(parent), 6 | ui(new Ui::InputMapPanel) 7 | { 8 | ui->setupUi(this); 9 | } 10 | 11 | InputMapPanel::~InputMapPanel() 12 | { 13 | delete ui; 14 | } 15 | 16 | InputMapWidget* InputMapPanel::addMapper(InputMapWidget* mapper) 17 | { 18 | // row, col, row span, col span 19 | ui->gridLayout->addWidget(mapper, ui->gridLayout->rowCount(), 0, 1, 3); 20 | return mapper; 21 | } 22 | 23 | void InputMapPanel::setName(QString name) 24 | { 25 | ui->groupBox->setTitle(name); 26 | } 27 | -------------------------------------------------------------------------------- /inputmappanel.h: -------------------------------------------------------------------------------- 1 | #ifndef INPUTMAPPANEL_H 2 | #define INPUTMAPPANEL_H 3 | 4 | #include 5 | #include "inputmapwidget.h" 6 | 7 | class InputMapWidget; 8 | 9 | namespace Ui { 10 | class InputMapPanel; 11 | } 12 | 13 | class InputMapPanel : public QWidget 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit InputMapPanel(QWidget *parent = nullptr); 19 | ~InputMapPanel(); 20 | InputMapWidget *addMapper(InputMapWidget* mapper); 21 | void setName(QString name); 22 | 23 | private: 24 | Ui::InputMapPanel *ui; 25 | }; 26 | 27 | #endif // INPUTMAPPANEL_H 28 | -------------------------------------------------------------------------------- /inputmappanel.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | InputMapPanel 4 | 5 | 6 | 7 | 0 8 | 0 9 | 116 10 | 57 11 | 12 | 13 | 14 | 15 | 10 16 | 17 | 18 | 19 | Form 20 | 21 | 22 | 23 | 24 | 25 | 26 | 10 27 | 28 | 29 | 30 | groupbox 31 | 32 | 33 | 34 | 0 35 | 36 | 37 | 0 38 | 39 | 40 | 2 41 | 42 | 43 | 44 | 45 | 46 | 10 47 | 48 | 49 | 50 | Button 51 | 52 | 53 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 10 62 | 63 | 64 | 65 | Key 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /inputmapwidget.cpp: -------------------------------------------------------------------------------- 1 | #include "inputmapwidget.h" 2 | #include "ui_inputmapwidget.h" 3 | #include 4 | #include 5 | #include "mainwindow.h" 6 | #include "eventhandler.h" 7 | 8 | #include 9 | #include 10 | 11 | InputMapWidget::InputMapWidget(QString button_name, int button_mask, int key_code, EventHandler* handler, QWidget *parent) : 12 | QWidget(parent), 13 | ui(new Ui::InputMapWidget), 14 | _handler(handler), 15 | _grab_timer(new QTimer(this)), 16 | _button_mask(button_mask), 17 | _button_name(button_name), 18 | _key_code(key_code), 19 | _wait_key(false) 20 | { 21 | ui->setupUi(this); 22 | QSettings settings; 23 | if(settings.contains("key-map/" + QString::number(_button_mask)) ) { 24 | int code = settings.value("key-map/" + QString::number(_button_mask)).toInt(); 25 | _key_code = code; 26 | } 27 | 28 | connect(_grab_timer,SIGNAL(timeout()),this,SLOT(onGrabTimerTimeout())); 29 | ui->labelButton->setText(button_name); 30 | displayKeyCodeString(); 31 | handler->addMapping(_button_mask, _key_code); 32 | } 33 | 34 | InputMapWidget::~InputMapWidget() 35 | { 36 | QSettings settings;//("werner", "QJoyControl"); 37 | settings.beginGroup("key-map"); 38 | settings.setValue(QString::number(_button_mask), _key_code); 39 | settings.endGroup(); 40 | 41 | delete ui; 42 | } 43 | 44 | void InputMapWidget::displayKeyCodeString() 45 | { 46 | Qt::Key key = (Qt::Key)_key_code; 47 | ui->labelKeyCode->setText(QKeySequence(key).toString()); 48 | } 49 | 50 | void InputMapWidget::on_toolButtonSet_clicked() 51 | { 52 | // get the next keypress 53 | _wait_key = true; 54 | grab_timer_count = 0; 55 | ui->toolButtonSet->setText(QString::number(10 - grab_timer_count) + "..."); 56 | ui->toolButtonSet->setEnabled(false); 57 | grabKeyboard(); 58 | _grab_timer->start(1000); 59 | } 60 | 61 | void InputMapWidget::keyPressEvent(QKeyEvent *event) 62 | { 63 | if(_wait_key){ 64 | _key_code = event->key(); 65 | _handler->addMapping(_button_mask, _key_code); 66 | displayKeyCodeString(); 67 | _grab_timer->stop(); 68 | onGrabKeyFinished(); 69 | } 70 | else { 71 | QWidget::keyPressEvent(event); 72 | } 73 | } 74 | 75 | void InputMapWidget::onGrabTimerTimeout() 76 | { 77 | grab_timer_count++; 78 | ui->toolButtonSet->setText(QString::number(10 - grab_timer_count) + "..."); 79 | if(grab_timer_count > 10) 80 | { 81 | onGrabKeyFinished(); 82 | } 83 | } 84 | 85 | void InputMapWidget::onGrabKeyFinished() 86 | { 87 | _wait_key = false; 88 | // release the keyboard 89 | releaseKeyboard(); 90 | _grab_timer->stop(); 91 | ui->toolButtonSet->setText("Set"); 92 | ui->toolButtonSet->setEnabled(true); 93 | } 94 | 95 | void InputMapWidget::setClickMap(int code) 96 | { 97 | if(code == 0) { // no click 98 | setEnabled(true); 99 | _handler->addMapping(_button_mask, _key_code); 100 | } 101 | else if(code == 1) { // right click 102 | setEnabled(false); 103 | _handler->mapToMouseButton(_button_mask, 1); 104 | //_handler->addMapping(_button_mask, kCGEventRightMouseDown); 105 | } 106 | else if (code == 2) { // left click 107 | setEnabled(false); 108 | _handler->mapToMouseButton(_button_mask, 2); 109 | // _handler->addMapping(_button_mask, kCGEventLeftMouseDown); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /inputmapwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef INPUTMAPWIDGET_H 2 | #define INPUTMAPWIDGET_H 3 | 4 | #include 5 | 6 | class EventHandler; 7 | 8 | namespace Ui { 9 | class InputMapWidget; 10 | } 11 | 12 | class InputMapWidget : public QWidget 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit InputMapWidget(QString button_name, int button_mask, int key_code, EventHandler* handler, QWidget *parent = nullptr); 18 | ~InputMapWidget(); 19 | 20 | void setClickMap(int code); 21 | protected: 22 | void keyPressEvent(QKeyEvent *event); 23 | 24 | private slots: 25 | void on_toolButtonSet_clicked(); 26 | void onGrabTimerTimeout(); 27 | void onGrabKeyFinished(); 28 | 29 | private: 30 | void displayKeyCodeString(); 31 | 32 | Ui::InputMapWidget *ui; 33 | EventHandler* _handler = nullptr; 34 | QTimer* _grab_timer = nullptr; 35 | int grab_timer_count = 0; 36 | int _button_mask = 0; 37 | QString _button_name; 38 | int _key_code; 39 | bool _wait_key;; 40 | }; 41 | 42 | #endif // INPUTMAPWIDGET_H 43 | -------------------------------------------------------------------------------- /inputmapwidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | InputMapWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 103 10 | 19 11 | 12 | 13 | 14 | 15 | 10 16 | 17 | 18 | 19 | Form 20 | 21 | 22 | 23 | 24 | 25 | 26 | 0 27 | 28 | 29 | 0 30 | 31 | 32 | 0 33 | 34 | 35 | 0 36 | 37 | 38 | 6 39 | 40 | 41 | 0 42 | 43 | 44 | 45 | 46 | Set 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 10 55 | 56 | 57 | 58 | Value 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 10 67 | 68 | 69 | 70 | Button 71 | 72 | 73 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /ir_sensor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // crc-8-ccitt / polynomial 0x07 look up table 4 | static uint8_t mcu_crc8_table[256] = { 5 | 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, 6 | 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 7 | 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, 8 | 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, 9 | 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 10 | 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, 11 | 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, 12 | 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, 13 | 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, 14 | 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, 15 | 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 16 | 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, 17 | 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, 18 | 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 19 | 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, 20 | 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 21 | }; 22 | 23 | // ARGB Ironbow palette 24 | static uint32_t iron_palette[] = { 25 | 0xff000014, 0xff000025, 0xff00002a, 0xff000032, 0xff000036, 0xff00003e, 0xff000042, 0xff00004f, 26 | 0xff010055, 0xff010057, 0xff02005c, 0xff03005e, 0xff040063, 0xff050065, 0xff070069, 0xff0a0070, 27 | 0xff0b0073, 0xff0d0075, 0xff0d0076, 0xff100078, 0xff120079, 0xff15007c, 0xff17007d, 0xff1c0081, 28 | 0xff200084, 0xff220085, 0xff260087, 0xff280089, 0xff2c008a, 0xff2e008b, 0xff32008d, 0xff38008f, 29 | 0xff390090, 0xff3c0092, 0xff3e0093, 0xff410094, 0xff420095, 0xff450096, 0xff470096, 0xff4c0097, 30 | 0xff4f0097, 0xff510097, 0xff540098, 0xff560098, 0xff5a0099, 0xff5c0099, 0xff5f009a, 0xff64009b, 31 | 0xff66009b, 0xff6a009b, 0xff6c009c, 0xff6f009c, 0xff70009c, 0xff73009d, 0xff75009d, 0xff7a009d, 32 | 0xff7e009d, 0xff7f009d, 0xff83009d, 0xff84009d, 0xff87009d, 0xff89009d, 0xff8b009d, 0xff91009c, 33 | 0xff93009c, 0xff96009b, 0xff98009b, 0xff9b009b, 0xff9c009b, 0xff9f009b, 0xffa0009b, 0xffa4009b, 34 | 0xffa7009a, 0xffa8009a, 0xffaa0099, 0xffab0099, 0xffae0198, 0xffaf0198, 0xffb00198, 0xffb30196, 35 | 0xffb40296, 0xffb60295, 0xffb70395, 0xffb90495, 0xffba0495, 0xffbb0593, 0xffbc0593, 0xffbf0692, 36 | 0xffc00791, 0xffc00791, 0xffc10990, 0xffc20a8f, 0xffc30b8e, 0xffc40c8d, 0xffc60d8b, 0xffc81088, 37 | 0xffc91187, 0xffca1385, 0xffcb1385, 0xffcc1582, 0xffcd1681, 0xffce187e, 0xffcf187c, 0xffd11b78, 38 | 0xffd21c75, 0xffd21d74, 0xffd32071, 0xffd4216f, 0xffd5236b, 0xffd52469, 0xffd72665, 0xffd92a60, 39 | 0xffda2b5e, 0xffdb2e5a, 0xffdb2f57, 0xffdd3051, 0xffdd314e, 0xffde3347, 0xffdf3444, 0xffe0373a, 40 | 0xffe03933, 0xffe13a30, 0xffe23c2a, 0xffe33d26, 0xffe43f20, 0xffe4411d, 0xffe5431b, 0xffe64616, 41 | 0xffe74715, 0xffe74913, 0xffe84a12, 0xffe84c0f, 0xffe94d0e, 0xffea4e0c, 0xffea4f0c, 0xffeb520a, 42 | 0xffec5409, 0xffec5608, 0xffec5808, 0xffed5907, 0xffed5b06, 0xffee5c06, 0xffee5d05, 0xffef6004, 43 | 0xffef6104, 0xfff06303, 0xfff06403, 0xfff16603, 0xfff16603, 0xfff16803, 0xfff16902, 0xfff16b02, 44 | 0xfff26d01, 0xfff26e01, 0xfff37001, 0xfff37101, 0xfff47300, 0xfff47400, 0xfff47600, 0xfff47a00, 45 | 0xfff57b00, 0xfff57e00, 0xfff57f00, 0xfff68100, 0xfff68200, 0xfff78400, 0xfff78500, 0xfff88800, 46 | 0xfff88900, 0xfff88a00, 0xfff88c00, 0xfff98d00, 0xfff98e00, 0xfff98f00, 0xfff99100, 0xfffa9400, 47 | 0xfffa9500, 0xfffb9800, 0xfffb9900, 0xfffb9c00, 0xfffc9d00, 0xfffca000, 0xfffca100, 0xfffda400, 48 | 0xfffda700, 0xfffda800, 0xfffdab00, 0xfffdac00, 0xfffdae00, 0xfffeaf00, 0xfffeb100, 0xfffeb400, 49 | 0xfffeb500, 0xfffeb800, 0xfffeb900, 0xfffeba00, 0xfffebb00, 0xfffebd00, 0xfffebe00, 0xfffec200, 50 | 0xfffec400, 0xfffec500, 0xfffec700, 0xfffec800, 0xfffeca01, 0xfffeca01, 0xfffecc02, 0xfffecf04, 51 | 0xfffecf04, 0xfffed106, 0xfffed308, 0xfffed50a, 0xfffed60a, 0xfffed80c, 0xfffed90d, 0xffffdb10, 52 | 0xffffdc14, 0xffffdd16, 0xffffde1b, 0xffffdf1e, 0xffffe122, 0xffffe224, 0xffffe328, 0xffffe531, 53 | 0xffffe635, 0xffffe73c, 0xffffe83f, 0xffffea46, 0xffffeb49, 0xffffec50, 0xffffed54, 0xffffee5f, 54 | 0xffffef67, 0xfffff06a, 0xfffff172, 0xfffff177, 0xfffff280, 0xfffff285, 0xfffff38e, 0xfffff49a, 55 | 0xfffff59e, 0xfffff5a6, 0xfffff6aa, 0xfffff7b3, 0xfffff7b6, 0xfffff8bd, 0xfffff8c1, 0xfffff9ca, 56 | 0xfffffad1, 0xfffffad4, 0xfffffcdb, 0xfffffcdf, 0xfffffde5, 0xfffffde8, 0xfffffeee, 0xfffffff6 57 | }; 58 | 59 | -------------------------------------------------------------------------------- /joyconworker.h: -------------------------------------------------------------------------------- 1 | #ifndef JOYCONTHREAD_H 2 | #define JOYCONTHREAD_H 3 | 4 | #include 5 | #include 6 | //#include 7 | #include "hidapi.h" 8 | #include 9 | 10 | //struct hid_device; 11 | //#include 12 | 13 | class EventHandler; 14 | 15 | Q_DECLARE_METATYPE(QList) 16 | Q_DECLARE_METATYPE(QList) 17 | Q_DECLARE_METATYPE(QList) 18 | 19 | const unsigned short NINTENDO = 1406; // 0x057e 20 | const unsigned short JOYCON_L = 8198; // 0x2006 21 | const unsigned short JOYCON_R = 8199; // 0x2007 22 | const unsigned short PRO_CONTROLLER = 8201; // 0x2009 23 | 24 | 25 | // Limit a value to the range [low, high] 26 | template T CLAMP(const T& value, const T& low, const T& high) 27 | { 28 | return value < low ? low : (value > high ? high : value); 29 | } 30 | 31 | // From: https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/bluetooth_hid_notes.md 32 | enum JC_CMD { 33 | // outputs: 34 | RUMBLE_PLUS = 0x01, // Output. Send a rumble and subcommand 35 | MCU_FW_UPDATE = 0x03, // Output. Send a FW update packet to the STM32 (IR/NFC MCU) 36 | RUMBLE_ONLY = 0x10, // Output. Send rumble data only 37 | MCU_DATA = 0x11, // Output. Request data from the STM32. Can also send rumble 38 | //0x12 // Unknown. Does the same as 0x28 39 | 40 | // inputs 41 | PUSH_INPUT = 0x3F, 42 | STANDARD_INPUT = 0x21, // Standard input reports used for subcommand replies 43 | MCU_UPDATE = 0x23, // NFC/IR MCU FW update input report. 44 | FULL_INPUT = 0x30, // Standard full mode - input reports with IMU data instead of subcommand replies. Pushes current state @60Hz, or @120Hz if Pro Controller. 45 | LARGE_PACKET = 0x31, // NFC/IR MCU mode. Pushes large packets with standard input report + NFC/IR MCU data input report. 46 | //0x32, // Unknown. Sends standard input reports. 47 | //0x33, // Unknown. Sends standard input reports. 48 | 49 | // feature reports 50 | GET_LAST_SUB = 0x02, // Get last subcommand reply 51 | ENABLE_OTA_FW = 0x70, // Enable OTA FW upgrade 52 | SETUP_MEM_READ = 0x71, // Setup memory read 53 | MEM_READ = 0x72, // Memory read 54 | MEM_ERASE = 0x73, // Memory sector erase 55 | MEM_WRITE = 0x74, // Memory sector write 56 | REBOOT = 0x75 // Reboots and executes the firmware rom in the given address 57 | // 0xCC, // Unknown send feature report 58 | // 0xFE, // Unknown get feature report 59 | }; 60 | 61 | enum JC_SUBCMD { 62 | GET_STATE = 0x00, 63 | BT_PAIR = 0x01, 64 | GET_INFO = 0x02, 65 | SET_INPUT_MODE = 0x03, 66 | TRIGGER_ELAPSED = 0x04, 67 | GET_PAGE_LIST_STATE = 0x05, 68 | SET_HCI_STATE = 0x06, 69 | RESET_PAIR = 0x07, 70 | LOW_POWER = 0x08, 71 | SPI_READ = 0x10, 72 | SPI_WRITE = 0x11, 73 | SPI_ERASE = 0x12, 74 | STM32_RESET = 0x20, 75 | STM32_CONFIG = 0x21, 76 | STM32_SET_STATE = 0x22, 77 | // 0x24, 78 | // 0x25, 79 | // 0x28, 80 | // 0x29 81 | SET_GPIO2_VALUE = 0x2A, 82 | GET_STM32_Data = 0x2B, 83 | SET_PLAYER_LED = 0x30, 84 | GET_PLAYER_LED = 0x31, 85 | SET_HOME_LED = 0x38, 86 | ENABLE_IMU = 0x40, 87 | CONFIG_IMU = 0x41, 88 | WRITE_IMU = 0x42, 89 | READ_IMU = 0x43, 90 | ENABLE_VIB = 0x48, 91 | GET_VREG = 0x50, 92 | SET_GPIO1_VALUE = 0x51, 93 | GET_GPIO_VALUE = 0x52 94 | }; 95 | 96 | #pragma pack(push, 1) // set current alignment packing value to 1 (MSVC) 97 | 98 | // a structure to hold a 99 | struct brcm_hdr { // 10 bytes total 100 | uint8_t cmd; // 0 101 | uint8_t timer; // 1 102 | uint8_t rumble_l[4]; // 2-5 103 | uint8_t rumble_r[4]; // 6-9 104 | }; 105 | 106 | struct brcm_cmd_01 { // 49 bytes long 107 | uint8_t subcmd; 108 | union { 109 | struct { 110 | uint32_t offset; 111 | uint8_t size; 112 | } spi_data; 113 | 114 | struct { 115 | uint8_t arg1; 116 | uint8_t arg2; 117 | } subcmd_arg; 118 | 119 | struct { 120 | uint8_t mcu_cmd; 121 | uint8_t mcu_subcmd; 122 | uint8_t mcu_mode; 123 | } subcmd_21_21; 124 | 125 | struct { 126 | uint8_t mcu_cmd; 127 | uint8_t mcu_subcmd; 128 | uint8_t no_of_reg; 129 | uint16_t reg1_addr; 130 | uint8_t reg1_val; 131 | uint16_t reg2_addr; 132 | uint8_t reg2_val; 133 | uint16_t reg3_addr; 134 | uint8_t reg3_val; 135 | uint16_t reg4_addr; 136 | uint8_t reg4_val; 137 | uint16_t reg5_addr; 138 | uint8_t reg5_val; 139 | uint16_t reg6_addr; 140 | uint8_t reg6_val; 141 | uint16_t reg7_addr; 142 | uint8_t reg7_val; 143 | uint16_t reg8_addr; 144 | uint8_t reg8_val; 145 | uint16_t reg9_addr; 146 | uint8_t reg9_val; 147 | } subcmd_21_23_04; 148 | 149 | struct { 150 | uint8_t mcu_cmd; 151 | uint8_t mcu_subcmd; 152 | uint8_t mcu_ir_mode; 153 | uint8_t no_of_frags; 154 | uint16_t mcu_major_v; 155 | uint16_t mcu_minor_v; 156 | } subcmd_21_23_01; 157 | }; 158 | }; 159 | 160 | struct ir_image_config { 161 | uint8_t ir_res_reg; 162 | uint16_t ir_exposure; 163 | uint8_t ir_leds; // Leds to enable, Strobe/Flashlight modes 164 | uint16_t ir_leds_intensity; // MSByte: Leds 1/2, LSB: Leds 3/4 165 | uint8_t ir_digital_gain; 166 | uint8_t ir_ex_light_filter; 167 | uint32_t ir_custom_register; // MSByte: Enable/Disable, Middle Byte: Edge smoothing, LSB: Color interpolation 168 | uint16_t ir_buffer_update_time; 169 | uint8_t ir_hand_analysis_mode; 170 | uint8_t ir_hand_analysis_threshold; 171 | uint32_t ir_denoise; // MSByte: Enable/Disable, Middle Byte: Edge smoothing, LSB: Color interpolation 172 | uint8_t ir_flip; 173 | int width; 174 | int height; 175 | uint8_t max_fragment_no;// = 0xff; 176 | }; 177 | Q_DECLARE_METATYPE(ir_image_config) 178 | 179 | #pragma pack(pop) // remove the last pack pragma 180 | 181 | class JoyConWorker : public QObject 182 | { 183 | Q_OBJECT 184 | public: 185 | explicit JoyConWorker(QObject *parent = nullptr); 186 | ~JoyConWorker(); 187 | 188 | signals: 189 | 190 | //< returns an empty QString and zero if nothing is connected 191 | void deviceConnectionChanged(QString, const unsigned short); 192 | 193 | void deviceStatusMessage(QString); //< send messages to display on the status bar 194 | 195 | void newDeviceInfo(QList, int); 196 | void newTemperatureData(float); 197 | void newBatteryData(int, int, int); 198 | void newCameraImage(QImage); 199 | 200 | //< digital input data, analog input data 201 | void newInputData(QList, QList); 202 | 203 | void finished(); 204 | 205 | public slots: 206 | void setup(); 207 | void onConnectHID(unsigned short vendor_id, 208 | unsigned short product_id, 209 | const wchar_t *serial_number); 210 | void onDisconnectHID(); 211 | 212 | void requestDeviceInfo(); 213 | void requestTemperature(); 214 | void requestBattery(); 215 | void requestJoyConInputs(); 216 | 217 | void onInputStreamingEnabled(bool enabled); 218 | 219 | void onIrConfigUpdated(ir_image_config ir_new_config); 220 | int get_raw_ir_image(unsigned char show_status = 0); //tk show status? 221 | 222 | private slots: 223 | void onInputPollTimerTimeout(); 224 | void onDeviceStatusTimerTimeout(); 225 | void onIrCaptureTimerTimeout(); 226 | 227 | private: 228 | QTimer* _input_poll_timer = nullptr; // 3 | struct lut_amp { 4 | float amp_float[101]; 5 | uint8_t ha[101]; 6 | uint16_t la[101]; 7 | }; 8 | 9 | static lut_amp lut_joy_amp{ 10 | { 0.00000f, 0.007843f, 0.011823f, 0.014061f, 0.01672f, 0.019885f, 0.023648f, 0.028123f, 11 | 0.033442f, 0.039771f, 0.047296f, 0.056246f, 0.066886f, 0.079542f, 0.094592f, 0.112491f, 12 | 0.117471f, 0.122671f, 0.128102f, 0.133774f, 0.139697f, 0.145882f, 0.152341f, 0.159085f, 13 | 0.166129f, 0.173484f, 0.181166f, 0.189185f, 0.197561f, 0.206308f, 0.215442f, 0.224982f, 14 | 0.229908f, 0.234943f, 0.240087f, 0.245345f, 0.250715f, 0.256206f, 0.261816f, 0.267549f, 15 | 0.273407f, 0.279394f, 0.285514f, 0.291765f, 0.298154f, 0.304681f, 0.311353f, 0.318171f, 16 | 0.325138f, 0.332258f, 0.339534f, 0.346969f, 0.354566f, 0.362331f, 0.370265f, 0.378372f, 17 | 0.386657f, 0.395124f, 0.403777f, 0.412619f, 0.421652f, 0.430885f, 0.440321f, 0.449964f, 18 | 0.459817f, 0.469885f, 0.480174f, 0.490689f, 0.501433f, 0.512413f, 0.523633f, 0.535100f, 19 | 0.546816f, 0.558790f, 0.571027f, 0.583530f, 0.596307f, 0.609365f, 0.622708f, 0.636344f, 20 | 0.650279f, 0.664518f, 0.679069f, 0.693939f, 0.709133f, 0.724662f, 0.740529f, 0.756745f, 21 | 0.773316f, 0.790249f, 0.807554f, 0.825237f, 0.843307f, 0.861772f, 0.880643f, 0.899928f, 22 | 0.919633f, 0.939771f, 0.960348f, 0.981378f, 1.002867f }, 23 | 24 | { 0x0, 0x2, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 25 | 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 26 | 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 27 | 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 28 | 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 29 | 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 30 | 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 31 | 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 32 | 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 33 | 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 34 | 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 35 | 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, 36 | 0xc0, 0xc2, 0xc4, 0xc6, 0xc8 }, 37 | 38 | { 0x0040, 0x8040, 0x0041, 0x8041, 0x0042, 0x8042, 0x0043, 0x8043, 39 | 0x0044, 0x8044, 0x0045, 0x8045, 0x0046, 0x8046, 0x0047, 0x8047, 40 | 0x0048, 0x8048, 0x0049, 0x8049, 0x004a, 0x804a, 0x004b, 0x804b, 41 | 0x004c, 0x804c, 0x004d, 0x804d, 0x004e, 0x804e, 0x004f, 0x804f, 42 | 0x0050, 0x8050, 0x0051, 0x8051, 0x0052, 0x8052, 0x0053, 0x8053, 43 | 0x0054, 0x8054, 0x0055, 0x8055, 0x0056, 0x8056, 0x0057, 0x8057, 44 | 0x0058, 0x8058, 0x0059, 0x8059, 0x005a, 0x805a, 0x005b, 0x805b, 45 | 0x005c, 0x805c, 0x005d, 0x805d, 0x005e, 0x805e, 0x005f, 0x805f, 46 | 0x0060, 0x8060, 0x0061, 0x8061, 0x0062, 0x8062, 0x0063, 0x8063, 47 | 0x0064, 0x8064, 0x0065, 0x8065, 0x0066, 0x8066, 0x0067, 0x8067, 48 | 0x0068, 0x8068, 0x0069, 0x8069, 0x006a, 0x806a, 0x006b, 0x806b, 49 | 0x006c, 0x806c, 0x006d, 0x806d, 0x006e, 0x806e, 0x006f, 0x806f, 50 | 0x0070, 0x8070, 0x0071, 0x8071, 0x0072 } 51 | }; 52 | 53 | -------------------------------------------------------------------------------- /mac/.gitignore: -------------------------------------------------------------------------------- 1 | Debug 2 | Release 3 | *.exp 4 | *.ilk 5 | *.lib 6 | *.suo 7 | *.vcproj.* 8 | *.ncb 9 | *.suo 10 | *.dll 11 | *.pdb 12 | *.o 13 | hidapi-hidtest 14 | .deps 15 | .libs 16 | *.la 17 | *.lo 18 | -------------------------------------------------------------------------------- /mac/eventhandler_macos.cpp: -------------------------------------------------------------------------------- 1 | #include "eventhandler.h" 2 | #include 3 | #include 4 | 5 | // key code mappings 6 | // https://stackoverflow.com/questions/1918841/how-to-convert-ascii-character-to-cgkeycode/14529841#14529841][1] 7 | 8 | /* The CGKeyCodes enum is used by 9 | * MacOS Core Graphics to represent the virtual 10 | * key codes used in keyboard events 11 | */ 12 | 13 | /*! 14 | * \brief EventHandler::EventHandler 15 | */ 16 | EventHandler::EventHandler() 17 | { 18 | // CGKeyCodes from Events.h in carbon 19 | // based on US Extended keyboard 20 | qt_to_cg.insert(Qt::Key_A, kVK_ANSI_A); 21 | qt_to_cg.insert(Qt::Key_S, kVK_ANSI_S); 22 | qt_to_cg.insert(Qt::Key_D, kVK_ANSI_D); 23 | qt_to_cg.insert(Qt::Key_F, kVK_ANSI_F); 24 | qt_to_cg.insert(Qt::Key_H, kVK_ANSI_H); 25 | qt_to_cg.insert(Qt::Key_G, kVK_ANSI_G); 26 | qt_to_cg.insert(Qt::Key_Z, kVK_ANSI_Z); 27 | qt_to_cg.insert(Qt::Key_X, kVK_ANSI_X); 28 | qt_to_cg.insert(Qt::Key_C, kVK_ANSI_C); 29 | qt_to_cg.insert(Qt::Key_V, kVK_ANSI_V); 30 | qt_to_cg.insert(Qt::Key_B, kVK_ANSI_B); 31 | qt_to_cg.insert(Qt::Key_Q, kVK_ANSI_Q); 32 | qt_to_cg.insert(Qt::Key_W, kVK_ANSI_W); 33 | qt_to_cg.insert(Qt::Key_E, kVK_ANSI_E); 34 | qt_to_cg.insert(Qt::Key_R, kVK_ANSI_R); 35 | qt_to_cg.insert(Qt::Key_T, kVK_ANSI_T); 36 | qt_to_cg.insert(Qt::Key_Y, kVK_ANSI_Y); 37 | 38 | qt_to_cg.insert(Qt::Key_1, kVK_ANSI_1); 39 | qt_to_cg.insert(Qt::Key_2, kVK_ANSI_2); 40 | qt_to_cg.insert(Qt::Key_3, kVK_ANSI_3); 41 | qt_to_cg.insert(Qt::Key_4, kVK_ANSI_4); 42 | qt_to_cg.insert(Qt::Key_6, kVK_ANSI_6); 43 | qt_to_cg.insert(Qt::Key_5, kVK_ANSI_5); 44 | qt_to_cg.insert(Qt::Key_Equal, kVK_ANSI_Equal); 45 | qt_to_cg.insert(Qt::Key_9, kVK_ANSI_9); 46 | qt_to_cg.insert(Qt::Key_7, kVK_ANSI_7); 47 | qt_to_cg.insert(Qt::Key_Minus, kVK_ANSI_Minus); 48 | qt_to_cg.insert(Qt::Key_8, kVK_ANSI_8); 49 | qt_to_cg.insert(Qt::Key_0, kVK_ANSI_0); 50 | qt_to_cg.insert(Qt::Key_BracketRight, kVK_ANSI_RightBracket); 51 | qt_to_cg.insert(Qt::Key_O, kVK_ANSI_O); 52 | qt_to_cg.insert(Qt::Key_U, kVK_ANSI_U); 53 | qt_to_cg.insert(Qt::Key_BracketLeft, kVK_ANSI_LeftBracket); 54 | qt_to_cg.insert(Qt::Key_I, kVK_ANSI_I); 55 | qt_to_cg.insert(Qt::Key_P, kVK_ANSI_P); 56 | qt_to_cg.insert(Qt::Key_L, kVK_ANSI_L); 57 | qt_to_cg.insert(Qt::Key_J, kVK_ANSI_J); 58 | qt_to_cg.insert(Qt::Key_QuoteLeft, kVK_ANSI_Quote); 59 | qt_to_cg.insert(Qt::Key_K, kVK_ANSI_K); 60 | qt_to_cg.insert(Qt::Key_Semicolon, kVK_ANSI_Semicolon); 61 | qt_to_cg.insert(Qt::Key_Backslash, kVK_ANSI_Backslash); 62 | qt_to_cg.insert(Qt::Key_Comma, kVK_ANSI_Comma); 63 | qt_to_cg.insert(Qt::Key_Slash, kVK_ANSI_Slash); 64 | qt_to_cg.insert(Qt::Key_N, kVK_ANSI_N); 65 | qt_to_cg.insert(Qt::Key_M, kVK_ANSI_M); 66 | qt_to_cg.insert(Qt::Key_Period, kVK_ANSI_Period); 67 | qt_to_cg.insert(Qt::Key_Dead_Grave, kVK_ANSI_Grave); 68 | // there are more ansi... 69 | 70 | qt_to_cg.insert(Qt::Key_Return, kVK_Return); 71 | qt_to_cg.insert(Qt::Key_Tab, kVK_Tab); 72 | qt_to_cg.insert(Qt::Key_Space, kVK_Space); 73 | qt_to_cg.insert(Qt::Key_Delete, kVK_Delete); 74 | qt_to_cg.insert(Qt::Key_Escape, kVK_Escape); 75 | qt_to_cg.insert(Qt::Key_Control, kVK_Command); 76 | qt_to_cg.insert(Qt::Key_Period, kVK_Shift); 77 | qt_to_cg.insert(Qt::Key_CapsLock, kVK_CapsLock); 78 | qt_to_cg.insert(Qt::Key_Option, kVK_Option); 79 | qt_to_cg.insert(Qt::Key_Meta, kVK_Control); 80 | //qt_to_cg.insert(Qt::Key_Func kVK_Function); 81 | qt_to_cg.insert(Qt::Key_F17, kVK_F17); 82 | qt_to_cg.insert(Qt::Key_VolumeUp, kVK_VolumeUp); 83 | qt_to_cg.insert(Qt::Key_VolumeDown, kVK_VolumeDown); 84 | //qt_to_cg.insert(Qt::Key_Mute, kVK_Mute); 85 | qt_to_cg.insert(Qt::Key_F18, kVK_F18); 86 | qt_to_cg.insert(Qt::Key_F19, kVK_F19); 87 | qt_to_cg.insert(Qt::Key_F20, kVK_F20); 88 | qt_to_cg.insert(Qt::Key_F5, kVK_F5); 89 | qt_to_cg.insert(Qt::Key_F6, kVK_F6); 90 | qt_to_cg.insert(Qt::Key_F7, kVK_F7); 91 | qt_to_cg.insert(Qt::Key_F3, kVK_F3); 92 | qt_to_cg.insert(Qt::Key_F8, kVK_F8); 93 | qt_to_cg.insert(Qt::Key_F9, kVK_F9); 94 | qt_to_cg.insert(Qt::Key_F11, kVK_F11); 95 | qt_to_cg.insert(Qt::Key_F13, kVK_F13); 96 | qt_to_cg.insert(Qt::Key_F16, kVK_F16); 97 | qt_to_cg.insert(Qt::Key_F14, kVK_F14); 98 | qt_to_cg.insert(Qt::Key_F10, kVK_F10); 99 | qt_to_cg.insert(Qt::Key_F12, kVK_F12); 100 | qt_to_cg.insert(Qt::Key_F15, kVK_F15); 101 | qt_to_cg.insert(Qt::Key_Help, kVK_Help); 102 | qt_to_cg.insert(Qt::Key_Home, kVK_Home); 103 | qt_to_cg.insert(Qt::Key_PageUp, kVK_PageUp); 104 | qt_to_cg.insert(Qt::Key_Forward, kVK_ForwardDelete); 105 | qt_to_cg.insert(Qt::Key_F4, kVK_F4); 106 | qt_to_cg.insert(Qt::Key_End, kVK_End); 107 | qt_to_cg.insert(Qt::Key_F2, kVK_F2); 108 | qt_to_cg.insert(Qt::Key_PageDown, kVK_PageDown); 109 | qt_to_cg.insert(Qt::Key_F1, kVK_F1); 110 | qt_to_cg.insert(Qt::Key_Left, kVK_LeftArrow); 111 | qt_to_cg.insert(Qt::Key_Right, kVK_RightArrow); 112 | qt_to_cg.insert(Qt::Key_Down, kVK_DownArrow); 113 | qt_to_cg.insert(Qt::Key_Up, kVK_UpArrow); 114 | } 115 | 116 | void EventHandler::addMapping(int from, int to) 117 | { 118 | keyCodeMap.insert(from, to); 119 | } 120 | 121 | void EventHandler::mapToMouseButton(int mask, int button) 122 | { 123 | if(button == 1) { 124 | addMapping(mask, kCGEventRightMouseDown); 125 | } 126 | else if (button == 2) { 127 | addMapping(mask, kCGEventLeftMouseDown); 128 | } 129 | } 130 | 131 | void EventHandler::handleMouseMove(double dx, double dy){ 132 | CGEventRef get = CGEventCreate(nullptr); 133 | CGPoint mouse = CGEventGetLocation(get); 134 | 135 | CGPoint pos; 136 | pos.x = mouse.x + dx; 137 | pos.y = mouse.y + dy; 138 | 139 | // see https://github.com/debauchee/barrier/blob/master/src/lib/platform/OSXScreen.mm 140 | // check if cursor position is valid on the client display configuration 141 | // stkamp@users.sourceforge.net 142 | CGDisplayCount displayCount = 0; 143 | CGGetDisplaysWithPoint(pos, 0, nullptr, &displayCount); 144 | if (displayCount == 0) { 145 | // cursor position invalid - clamp to bounds of last valid display. 146 | // find the last valid display using the last cursor position. 147 | displayCount = 0; 148 | CGDirectDisplayID displayID; 149 | CGGetDisplaysWithPoint(CGPointMake(mouse.x, mouse.y), 1, 150 | &displayID, &displayCount); 151 | if (displayCount != 0) { 152 | CGRect displayRect = CGDisplayBounds(displayID); 153 | if (pos.x < displayRect.origin.x) { 154 | pos.x = displayRect.origin.x; 155 | } 156 | else if (pos.x > displayRect.origin.x + 157 | displayRect.size.width - 1) { 158 | pos.x = displayRect.origin.x + displayRect.size.width - 1; 159 | } 160 | if (pos.y < displayRect.origin.y) { 161 | pos.y = displayRect.origin.y; 162 | } 163 | else if (pos.y > displayRect.origin.y + 164 | displayRect.size.height - 1) { 165 | pos.y = displayRect.origin.y + displayRect.size.height - 1; 166 | } 167 | } 168 | } 169 | CGEventType event_type = kCGEventMouseMoved; 170 | CGMouseButton button = kCGMouseButtonLeft; 171 | if(_left_button_down) { 172 | event_type = kCGEventLeftMouseDragged; 173 | } 174 | if(_right_button_down) { 175 | event_type = kCGEventRightMouseDragged; 176 | button = kCGMouseButtonRight; 177 | } 178 | CGEventRef mouseEv = CGEventCreateMouseEvent( 179 | nullptr, event_type, 180 | pos, button); 181 | 182 | double final_dx = pos.x - mouse.x; 183 | double final_dy = pos.y - mouse.y; 184 | 185 | CGEventSetIntegerValueField(mouseEv, kCGMouseEventDeltaX, (int)final_dx); 186 | CGEventSetIntegerValueField(mouseEv, kCGMouseEventDeltaY, (int)final_dy); 187 | 188 | CGEventSetDoubleValueField(mouseEv, kCGMouseEventDeltaX, final_dx); 189 | CGEventSetDoubleValueField(mouseEv, kCGMouseEventDeltaY, final_dy); 190 | 191 | CGEventPost(kCGHIDEventTap, mouseEv); 192 | CFRelease(mouseEv); 193 | } 194 | 195 | /*! 196 | * \brief EventHandler::handleButtonPress 197 | * \param button_mask 198 | */ 199 | void EventHandler::handleButtonPress(int button_mask){ 200 | // check if a mouse button is mapped to the button 201 | if(keyCodeMap.value(button_mask) == kCGEventLeftMouseDown){ 202 | 203 | CGEventRef get = CGEventCreate(nullptr); 204 | CGPoint mouse = CGEventGetLocation(get); 205 | int64_t x = mouse.x; 206 | int64_t y = mouse.y; 207 | 208 | CGEventRef mouseEv1 = CGEventCreateMouseEvent( 209 | nullptr, kCGEventLeftMouseDown, 210 | CGPointMake(x, y), 211 | kCGMouseButtonLeft); 212 | CGEventPost(kCGHIDEventTap, mouseEv1); 213 | CFRelease(mouseEv1); 214 | _left_button_down = true; 215 | } 216 | else if(keyCodeMap.value(button_mask) == kCGEventRightMouseDown){ 217 | 218 | CGEventRef get = CGEventCreate(nullptr); 219 | CGPoint mouse = CGEventGetLocation(get); 220 | int64_t x = mouse.x; 221 | int64_t y = mouse.y; 222 | 223 | CGEventRef mouseEv1 = CGEventCreateMouseEvent( 224 | nullptr, kCGEventRightMouseDown, 225 | CGPointMake(x, y), 226 | kCGMouseButtonLeft); 227 | CGEventPost(kCGHIDEventTap, mouseEv1); 228 | CFRelease(mouseEv1); 229 | _right_button_down = true; 230 | } 231 | // otherwise, get the key code value for the button 232 | else { 233 | int qt_key = keyCodeMap.value(button_mask, Qt::Key_Enter); 234 | unsigned short cg_key = qt_to_cg.value(qt_key); 235 | CGEventRef keyEvent = CGEventCreateKeyboardEvent( nullptr, cg_key, true ) ; 236 | CGEventPost( kCGHIDEventTap, keyEvent ) ; 237 | CFRelease( keyEvent ) ; 238 | } 239 | } 240 | 241 | void EventHandler::handleButtonRelease(int button_mask){ 242 | if(keyCodeMap.value(button_mask) == kCGEventLeftMouseDown ){ 243 | 244 | CGEventRef get = CGEventCreate(nullptr); 245 | CGPoint mouse = CGEventGetLocation(get); 246 | int64_t x = mouse.x; 247 | int64_t y = mouse.y; 248 | 249 | CGEventRef mouseEv2 = CGEventCreateMouseEvent( 250 | nullptr, kCGEventLeftMouseUp, 251 | CGPointMake(x, y), 252 | kCGMouseButtonLeft); 253 | CGEventPost(kCGHIDEventTap, mouseEv2); 254 | CFRelease(mouseEv2); 255 | _left_button_down = false; 256 | } 257 | if(keyCodeMap.value(button_mask) == kCGEventRightMouseDown ){ 258 | 259 | CGEventRef get = CGEventCreate(nullptr); 260 | CGPoint mouse = CGEventGetLocation(get); 261 | int64_t x = mouse.x; 262 | int64_t y = mouse.y; 263 | 264 | CGEventRef mouseEv2 = CGEventCreateMouseEvent( 265 | nullptr, kCGEventRightMouseUp, 266 | CGPointMake(x, y), 267 | kCGMouseButtonLeft); 268 | CGEventPost(kCGHIDEventTap, mouseEv2); 269 | CFRelease(mouseEv2); 270 | _right_button_down = false; 271 | } 272 | else { 273 | int qt_key = keyCodeMap.value(button_mask, Qt::Key_Enter); 274 | unsigned short cg_key = qt_to_cg.value(qt_key); 275 | CGEventRef keyEvent = CGEventCreateKeyboardEvent( nullptr, cg_key, false ) ; 276 | CGEventPost( kCGHIDEventTap, keyEvent ) ; 277 | CFRelease( keyEvent ) ; 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /mac/powertools.h: -------------------------------------------------------------------------------- 1 | #ifndef POWERTOOLS_H 2 | #define POWERTOOLS_H 3 | 4 | #if !defined(__cplusplus) 5 | #define C_API extern 6 | #else 7 | #define C_API extern "C" 8 | #endif 9 | 10 | #include 11 | 12 | /* Power Tools 13 | * A few tools to control power management features in MacOS that 14 | * can cause problems with scientific applications. Designed for use with Qt. 15 | * 16 | * To use: 17 | * HEADERS += powertools.h 18 | * OBJECTIVE_SOURCES += powertools.mm 19 | * LIBS += -framework Foundation 20 | * 21 | * App Nap (timer coalescing, introduced in 10.9) 22 | * Disable App Nap if continued processing is needed 23 | * when the application is in the background 24 | * API from: https://developer.apple.com/documentation/foundation/nsprocessinfo 25 | * Based on the thread at: https://stackoverflow.com/questions/30686488/qapplication-is-lazy-or-making-other-threads-lazy-in-the-app 26 | * 27 | * User Sleep 28 | * Prevent the computer or display and computer from sleeping after 29 | * spending too long without user input 30 | * API from: https://developer.apple.com/documentation/iokit/iopmlib_h?language=objc 31 | * 32 | * License: MIT 33 | * Copyright 2019 Erik Werner 34 | * Permission is hereby granted, free of charge, to any person obtaining a copy 35 | * of this software and associated documentation files (the "Software"), to 36 | * deal in the Software without restriction, including without limitation the 37 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 38 | * sell copies of the Software, and to permit persons to whom the Software is 39 | * furnished to do so, subject to the following conditions: 40 | 41 | * The above copyright notice and this permission notice shall be included 42 | * in all copies or substantial portions of the Software. 43 | 44 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 45 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 46 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 47 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 48 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 49 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 50 | * DEALINGS IN THE SOFTWARE. 51 | */ 52 | 53 | 54 | C_API void disableAppNap(const QString reason_string = "Disable App Nap"); 55 | C_API void enableAppNap(); 56 | C_API bool preventSleep(const QString assert_type = "PreventUserIdleDisplaySleep", 57 | const QString reason_string = "Program is running"); 58 | C_API bool allowSleep(); 59 | 60 | #endif // POWERTOOLS_H 61 | -------------------------------------------------------------------------------- /mac/powertools.mm: -------------------------------------------------------------------------------- 1 | #include "powertools.h" 2 | #include // App Nap API 3 | #import // Power Management System API 4 | 5 | static id activity; //< keep track of the activity ID for app nap control 6 | static IOPMAssertionID assertionID; //< keep track of the assertion ID for sleep control 7 | 8 | /*! 9 | * \brief disableAppNap 10 | * \param reason_string a description of the activity preventing app nap. Used for debugging. 11 | */ 12 | void disableAppNap(const QString reason_string) { 13 | NSString* nss = [[NSString alloc] initWithUTF8String:reason_string.toUtf8().data()]; 14 | activity = [[NSProcessInfo processInfo] beginActivityWithOptions:NSActivityLatencyCritical | NSActivityUserInitiated 15 | reason:nss]; 16 | } 17 | 18 | /*! 19 | * \brief enableAppNap 20 | */ 21 | void enableAppNap() { 22 | [[NSProcessInfo processInfo] endActivity:activity]; 23 | } 24 | 25 | /*! 26 | * \brief preventSleep 27 | * \param assert_type the assertion type to request from the power management system 28 | * Use "PreventUserIdleSystemSleep" to prevent system sleep, but allow display sleeping. 29 | * Use "PreventUserIdleDisplaySleep" to prevent both system and display sleeping (this is the default) 30 | * \param reason_string a string describing the activity preventing sleep. Max length is 128 characters 31 | * \return true if the assertion was successfully activated 32 | */ 33 | bool preventSleep(const QString assert_type, const QString reason_string){ 34 | CFStringRef reason_c = reason_string.toCFString(); 35 | CFStringRef assertion_c = assert_type.toCFString(); 36 | IOReturn success = IOPMAssertionCreateWithName(assertion_c, 37 | kIOPMAssertionLevelOn, reason_c, &assertionID); 38 | if (success == kIOReturnSuccess){ 39 | return true; 40 | } else { 41 | return false; 42 | } 43 | } 44 | 45 | /*! 46 | * \brief allowSleep 47 | * \return true if the assertio was successfully released 48 | */ 49 | bool allowSleep(){ 50 | IOReturn success = IOPMAssertionRelease(assertionID); 51 | if (success == kIOReturnSuccess){ 52 | return true; 53 | } else { 54 | return false; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include "powertools.h" 3 | #include 4 | 5 | #ifndef QT_NO_SYSTEMTRAYICON 6 | 7 | #include 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | int id1 = qRegisterMetaType >(); 12 | int id2 = qRegisterMetaType >(); 13 | int id3 = qRegisterMetaType >(); 14 | int id4 = qRegisterMetaType(); 15 | 16 | Q_INIT_RESOURCE(resources); 17 | QApplication a(argc, argv); 18 | disableAppNap(); 19 | if (!QSystemTrayIcon::isSystemTrayAvailable()) { 20 | QMessageBox::critical(nullptr, QObject::tr("Systray"), 21 | QObject::tr("Unable to detect a system tray " 22 | "on this system.")); 23 | return 1; 24 | } 25 | QApplication::setQuitOnLastWindowClosed(false); 26 | MainWindow w; 27 | 28 | w.show(); 29 | 30 | int code = a.exec(); 31 | enableAppNap(); 32 | return code; 33 | } 34 | 35 | #else 36 | 37 | #include 38 | #include 39 | 40 | int main(int argc, char *argv[]) 41 | { 42 | QApplication app(argc, argv); 43 | QString text("QSystemTrayIcon is not supported on this platform"); 44 | 45 | QLabel *label = new QLabel(text); 46 | label->setWordWrap(true); 47 | 48 | label->show(); 49 | qDebug() << text; 50 | 51 | app.exec(); 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include 5 | #include 6 | 7 | #include "joyconworker.h" 8 | 9 | // https://stackoverflow.com/questions/40599038/on-linux-whats-a-good-way-to-to-use-hid-reports-over-usb 10 | 11 | class QThread; 12 | class StatusWidget; 13 | class InputMapWidget; 14 | 15 | namespace Ui { 16 | class MainWindow; 17 | } 18 | 19 | /*! 20 | * \brief The MainWindow class is the root of the QJoyControl GUI. 21 | * It can be shown or hidden, but it will remain alive until the application 22 | * is closed. 23 | */ 24 | class MainWindow : public QMainWindow 25 | { 26 | Q_OBJECT 27 | 28 | public: 29 | /*! 30 | * \brief MainWindow default constructor 31 | * \param parent usually a nullptr 32 | */ 33 | explicit MainWindow(QWidget *parent = nullptr); 34 | ~MainWindow() override; 35 | 36 | protected: 37 | void closeEvent(QCloseEvent *event) override; 38 | void resizeEvent(QResizeEvent *event) override; 39 | 40 | public slots: 41 | void onShow(); 42 | void onHide(); 43 | 44 | void onCameraImageData(QImage img); 45 | void hideAndClose(); 46 | 47 | void onNewInputData(QList button_data, QList analog_data); 48 | void onDeviceConnectionChanged(QString sn, const unsigned short pid); 49 | void onJoyConStatusMessage(QString message); 50 | 51 | signals: 52 | void connectHID(unsigned short vendor_id, 53 | unsigned short product_id, 54 | const wchar_t *serial_number); 55 | 56 | void disconnectHID(); 57 | 58 | void enableInputStreaming(bool); 59 | 60 | void updateIrConfig(ir_image_config); 61 | void captureImage(unsigned char); 62 | 63 | private slots: 64 | void onDeviceInfoData(QList device_info, int joycon_type); 65 | void onTemperatureData(float temp_c); 66 | void onBatteryData(int volt, int percent, int status); 67 | 68 | void on_pushButtonCapture_clicked(); 69 | void on_pushButtonStream_clicked(); 70 | 71 | void on_checkBoxDiagnostics_toggled(bool checked); 72 | void on_checkBoxAppNap_toggled(bool checked); 73 | void on_checkBoxIdleSleep_toggled(bool checked); 74 | 75 | void on_toolButtonRefresh_clicked(); 76 | void on_toolButtonConnect_clicked(); 77 | void on_toolButtonDisconnect_clicked(); 78 | 79 | void on_checkBoxInvertIcon_toggled(bool checked); 80 | 81 | void on_pushButtonSaveImage_clicked(); 82 | 83 | void on_comboBoxColorMap_currentIndexChanged(int index); 84 | 85 | void showAbout(); 86 | 87 | void on_checkBoxLeftClick_toggled(bool checked); 88 | 89 | void on_checkBoxRightClick_toggled(bool checked); 90 | 91 | private: 92 | Ui::MainWindow *ui; 93 | StatusWidget* _status_widget; 94 | EventHandler* _event_handler = nullptr; 95 | QSystemTrayIcon *_tray_icon = nullptr; 96 | QMenu *_tray_icon_menu; 97 | JoyConWorker* _worker; 98 | QThread* _thread; 99 | 100 | QAction *_hide_action; 101 | QAction *_show_action; 102 | QAction *_about_action; 103 | QAction *_quit_action; 104 | 105 | bool _force_close = false; 106 | 107 | unsigned short _joycon_pid = 0; 108 | QString _joycon_sn = QString(); 109 | // hold the last button state received 110 | int _last_button_state[3] = {0,0,0}; 111 | QImage _current_image = QImage(); 112 | QVector _color_table; 113 | InputMapWidget* _l_mapper = nullptr; 114 | InputMapWidget* _zl_mapper = nullptr; 115 | InputMapWidget* _r_mapper = nullptr; 116 | InputMapWidget* _zr_mapper = nullptr; 117 | 118 | qint64 _time_last_update; // keep track of the last time the GUI was updated 119 | 120 | 121 | void loadSettings(); 122 | void setupThread(); 123 | void addHidItem(struct hid_device_info* info); 124 | void sendCameraConfig(); 125 | void saveSettings(); 126 | void handleButtons(QList buttons); 127 | double scaleAnalog(double input); 128 | void createTrayIcon(bool is_inverted); 129 | void testButton(int last_button_state, int _last_button_state, int mask); 130 | }; 131 | 132 | #endif // MAINWINDOW_H 133 | -------------------------------------------------------------------------------- /resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | img/batt_0.png 4 | img/batt_0_chr.png 5 | img/batt_100.png 6 | img/batt_100_chr.png 7 | img/batt_25.png 8 | img/batt_25_chr.png 9 | img/batt_50.png 10 | img/batt_50_chr.png 11 | img/batt_75.png 12 | img/batt_75_chr.png 13 | img/retail_colors.xml 14 | img/Logo.icns 15 | img/Logo.png 16 | img/Logo.svg 17 | 18 | 19 | -------------------------------------------------------------------------------- /statuswidget.cpp: -------------------------------------------------------------------------------- 1 | #include "statuswidget.h" 2 | #include "ui_statuswidget.h" 3 | #include 4 | #include 5 | 6 | StatusWidget::StatusWidget(QWidget *parent) : 7 | QWidget(parent), 8 | ui(new Ui::StatusWidget), 9 | _battery_pixmap(QPixmap()) 10 | { 11 | ui->setupUi(this); 12 | } 13 | 14 | StatusWidget::~StatusWidget() 15 | { 16 | delete ui; 17 | } 18 | 19 | void StatusWidget::onBatteryData(int batt, QString text){ 20 | ui->labelBatteryText->setText(text); 21 | 22 | // Update Battery icon from input report value. 23 | switch (batt) { 24 | case 0: 25 | _battery_pixmap.load(":/img/batt_0.png"); 26 | break; 27 | case 1: 28 | _battery_pixmap.load(":/img/batt_0_chr.png"); 29 | break; 30 | case 2: 31 | _battery_pixmap.load(":/img/batt_25.png"); 32 | break; 33 | case 3: 34 | _battery_pixmap.load(":/img/batt_25_cr.png"); 35 | break; 36 | case 4: 37 | _battery_pixmap.load(":/img/batt_50.png"); 38 | break; 39 | case 5: 40 | _battery_pixmap.load(":/img/batt_50_cr.png"); 41 | break; 42 | case 6: 43 | _battery_pixmap.load(":/img/batt_75.png"); 44 | break; 45 | case 7: 46 | _battery_pixmap.load(":/img/batt_75_cr.png"); 47 | break; 48 | case 8: 49 | _battery_pixmap.load(":/img/batt_100.png"); 50 | break; 51 | case 9: 52 | _battery_pixmap.load(":/img/batt_100_cr.png"); 53 | break; 54 | default: 55 | _battery_pixmap.load(":/img/batt_0.png"); 56 | } 57 | 58 | ui->labelBatteryGraphic->setPixmap(_battery_pixmap.scaled(24,9)); 59 | } 60 | 61 | void StatusWidget::onTemperatureData(float temp){ 62 | QString text_string("Temp: "); 63 | text_string += QString::number(temp, 'f', 1); 64 | text_string +=("ºC "); 65 | ui->labelTempText->setText(text_string); 66 | } 67 | -------------------------------------------------------------------------------- /statuswidget.h: -------------------------------------------------------------------------------- 1 | #ifndef STATUSWIDGET_H 2 | #define STATUSWIDGET_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class StatusWidget; 8 | } 9 | 10 | class StatusWidget : public QWidget 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit StatusWidget(QWidget *parent = nullptr); 16 | ~StatusWidget(); 17 | 18 | public slots: 19 | void onBatteryData(int batt, QString text); 20 | void onTemperatureData(float temp); 21 | private: 22 | Ui::StatusWidget *ui; 23 | QPixmap _battery_pixmap; 24 | }; 25 | 26 | #endif // STATUSWIDGET_H 27 | -------------------------------------------------------------------------------- /statuswidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | StatusWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 439 10 | 38 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 0 39 | 0 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | --------------------------------------------------------------------------------