old data
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
|
||||
HIDAPI Authors:
|
||||
|
||||
Alan Ott <alan@signal11.us>:
|
||||
Original Author and Maintainer
|
||||
Linux, Windows, and Mac implementations
|
||||
|
||||
Ludovic Rousseau <rousseau@debian.org>:
|
||||
Formatting for Doxygen documentation
|
||||
Bug fixes
|
||||
Correctness fixes
|
||||
|
||||
libusb/hidapi Team:
|
||||
Development/maintenance since June 4th 2019
|
||||
|
||||
For a comprehensive list of contributions, see the commit list at github:
|
||||
https://github.com/libusb/hidapi/graphs/contributors
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
cmake_minimum_required(VERSION 3.1.3...3.25 FATAL_ERROR)
|
||||
|
||||
if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
add_subdirectory(src)
|
||||
# compatibility with find_package() vs add_subdirectory
|
||||
set(hidapi_VERSION "${hidapi_VERSION}" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
# All of the below in this file is meant for a standalone build.
|
||||
# When building as a subdirectory of a larger project, most of the options may not make sense for it,
|
||||
# so it is up to developer to configure those, e.g.:
|
||||
#
|
||||
# # a subfolder of a master project, e.g.: 3rdparty/hidapi/CMakeLists.txt
|
||||
#
|
||||
# set(HIDAPI_WITH_HIDRAW OFF)
|
||||
# set(CMAKE_FRAMEWORK ON)
|
||||
# # and keep everything else to their defaults
|
||||
# add_subdirectory(hidapi)
|
||||
#
|
||||
|
||||
set(DEFAULT_CMAKE_BUILD_TYPES "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
if(NOT DEFINED CMAKE_BUILD_TYPE OR NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "${DEFAULT_CMAKE_BUILD_TYPES}" FORCE)
|
||||
endif()
|
||||
# This part is for convenience, when used one of the standard build types with cmake-gui
|
||||
list(FIND DEFAULT_CMAKE_BUILD_TYPES "${CMAKE_BUILD_TYPE}" _build_type_index)
|
||||
if(${_build_type_index} GREATER -1)
|
||||
# set it optionally, so a custom CMAKE_BUILD_TYPE can be used as well, if needed
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${DEFAULT_CMAKE_BUILD_TYPES})
|
||||
endif()
|
||||
unset(_build_type_index)
|
||||
#
|
||||
|
||||
project(hidapi LANGUAGES C)
|
||||
|
||||
if(APPLE)
|
||||
if(NOT CMAKE_VERSION VERSION_LESS "3.15")
|
||||
option(CMAKE_FRAMEWORK "Build macOS/iOS Framework version of the library" OFF)
|
||||
endif()
|
||||
elseif(NOT WIN32)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
option(HIDAPI_WITH_HIDRAW "Build HIDRAW-based implementation of HIDAPI" ON)
|
||||
option(HIDAPI_WITH_LIBUSB "Build LIBUSB-based implementation of HIDAPI" ON)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "NetBSD")
|
||||
option(HIDAPI_WITH_NETBSD "Build NetBSD/UHID implementation of HIDAPI" ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(BUILD_SHARED_LIBS "Build shared version of the libraries, otherwise build statically" ON)
|
||||
|
||||
set(HIDAPI_INSTALL_TARGETS ON)
|
||||
set(HIDAPI_PRINT_VERSION ON)
|
||||
|
||||
set(IS_DEBUG_BUILD OFF)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(IS_DEBUG_BUILD ON)
|
||||
endif()
|
||||
|
||||
option(HIDAPI_ENABLE_ASAN "Build HIDAPI with ASAN address sanitizer instrumentation" OFF)
|
||||
|
||||
if(HIDAPI_ENABLE_ASAN)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
|
||||
if(MSVC)
|
||||
# the default is to have "/INCREMENTAL" which causes a warning when "-fsanitize=address" is present
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /INCREMENTAL:NO")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /INCREMENTAL:NO")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /INCREMENTAL:NO")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /INCREMENTAL:NO")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
# so far only Windows has tests
|
||||
option(HIDAPI_WITH_TESTS "Build HIDAPI (unit-)tests" ${IS_DEBUG_BUILD})
|
||||
else()
|
||||
set(HIDAPI_WITH_TESTS OFF)
|
||||
endif()
|
||||
|
||||
if(HIDAPI_WITH_TESTS)
|
||||
enable_testing()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
option(HIDAPI_BUILD_PP_DATA_DUMP "Build small Windows console application pp_data_dump.exe" ${IS_DEBUG_BUILD})
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
option(HIDAPI_BUILD_HIDTEST "Build small console test application hidtest" ${IS_DEBUG_BUILD})
|
||||
if(HIDAPI_BUILD_HIDTEST)
|
||||
add_subdirectory(hidtest)
|
||||
endif()
|
||||
|
||||
if(HIDAPI_ENABLE_ASAN)
|
||||
if(NOT MSVC)
|
||||
# MSVC doesn't recognize those options, other compilers - requiring it
|
||||
foreach(HIDAPI_TARGET hidapi_winapi hidapi_darwin hidapi_hidraw hidapi_libusb hidtest_hidraw hidtest_libusb hidtest)
|
||||
if(TARGET ${HIDAPI_TARGET})
|
||||
if(BUILD_SHARED_LIBS)
|
||||
target_link_options(${HIDAPI_TARGET} PRIVATE -fsanitize=address)
|
||||
else()
|
||||
target_link_options(${HIDAPI_TARGET} PUBLIC -fsanitize=address)
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,19 @@
|
||||
This file is mostly for the maintainer.
|
||||
|
||||
Updating a Version:
|
||||
1. Update VERSION file.
|
||||
2. HID_API_VERSION_MAJOR/HID_API_VERSION_MINOR/HID_API_VERSION_PATCH in hidapi.h.
|
||||
|
||||
Before firing a new release:
|
||||
1. Run the "Checks" Githtub Action
|
||||
2. Make sure no defects are found at: https://scan.coverity.com/projects/hidapi
|
||||
3. Fix if any
|
||||
|
||||
Firing a new release:
|
||||
1. Update the Version (if not yet updated).
|
||||
2. Prepare the Release Notes.
|
||||
3. Store the Release Notes into a file.
|
||||
4. Create locally an annotated git tag with release notes attached, e.g.: `git tag -aF ../hidapi_release_notes hidapi-<VERSION>`
|
||||
5. Push newly created tag: `git push origin hidapi-<VERSION>`
|
||||
6. Grab the hidapi-win.zip from Summary page of "GitHub Builds" Action for latest master build.
|
||||
7. Create a Github Release with hidapi-win.zip attached, for newly created tag.
|
||||
@@ -0,0 +1,26 @@
|
||||
Copyright (c) 2010, Alan Ott, Signal 11 Software
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Signal 11 Software nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
@@ -0,0 +1,9 @@
|
||||
HIDAPI - Multi-Platform library for
|
||||
communication with HID devices.
|
||||
|
||||
Copyright 2009, Alan Ott, Signal 11 Software.
|
||||
All Rights Reserved.
|
||||
|
||||
This software may be used by anyone for any reason so
|
||||
long as the copyright notice in the source files
|
||||
remains intact.
|
||||
@@ -0,0 +1,13 @@
|
||||
HIDAPI can be used under one of three licenses.
|
||||
|
||||
1. The GNU General Public License, version 3.0, in LICENSE-gpl3.txt
|
||||
2. A BSD-Style License, in LICENSE-bsd.txt.
|
||||
3. The more liberal original HIDAPI license. LICENSE-orig.txt
|
||||
|
||||
The license chosen is at the discretion of the user of HIDAPI. For example:
|
||||
1. An author of GPL software would likely use HIDAPI under the terms of the
|
||||
GPL.
|
||||
|
||||
2. An author of commercial closed-source software would likely use HIDAPI
|
||||
under the terms of the BSD-style license or the original HIDAPI license.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/* The implementation for Android is in a separate .cpp file */
|
||||
#undef HIDAPI_H__
|
||||
#include "hidapi/hidapi.h"
|
||||
#define HAVE_PLATFORM_BACKEND 1
|
||||
#define udev_ctx 1
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
|
||||
/* Return true if the HIDAPI should ignore a device during enumeration */
|
||||
extern bool SDL_HIDAPI_ShouldIgnoreDevice(int bus_type, Uint16 vendor_id, Uint16 product_id, Uint16 usage_page, Uint16 usage);
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI
|
||||
#ifdef HAVE_LIBUSB
|
||||
#define HAVE_ENABLE_GAMECUBE_ADAPTORS
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ENABLE_GAMECUBE_ADAPTORS
|
||||
extern void SDL_EnableGameCubeAdaptors(void);
|
||||
#endif
|
||||
#endif /* SDL_JOYSTICK_HIDAPI */
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/* The implementation for iOS and tvOS is in a separate .m file */
|
||||
#undef HIDAPI_H__
|
||||
#include "hidapi/hidapi.h"
|
||||
#define HAVE_PLATFORM_BACKEND 1
|
||||
#define udev_ctx 1
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/* Define standard library functions in terms of SDL */
|
||||
|
||||
/* #pragma push_macro/pop_macro works correctly only as of gcc >= 4.4.3
|
||||
clang-3.0 _seems_ to be OK. */
|
||||
#pragma push_macro("calloc")
|
||||
#pragma push_macro("malloc")
|
||||
#pragma push_macro("realloc")
|
||||
#pragma push_macro("free")
|
||||
#pragma push_macro("iconv_t")
|
||||
#pragma push_macro("iconv")
|
||||
#pragma push_macro("iconv_open")
|
||||
#pragma push_macro("iconv_close")
|
||||
#pragma push_macro("setlocale")
|
||||
#pragma push_macro("snprintf")
|
||||
#pragma push_macro("strcmp")
|
||||
#pragma push_macro("strdup")
|
||||
#pragma push_macro("strncpy")
|
||||
#pragma push_macro("tolower")
|
||||
#pragma push_macro("wcscmp")
|
||||
#pragma push_macro("wcsdup")
|
||||
#pragma push_macro("wcsncpy")
|
||||
|
||||
#undef calloc
|
||||
#undef malloc
|
||||
#undef realloc
|
||||
#undef free
|
||||
#undef iconv_t
|
||||
#undef iconv
|
||||
#undef iconv_open
|
||||
#undef iconv_close
|
||||
#undef setlocale
|
||||
#undef snprintf
|
||||
#undef strcmp
|
||||
#undef strdup
|
||||
#undef strncpy
|
||||
#undef tolower
|
||||
#undef wcscmp
|
||||
#undef wcsdup
|
||||
#undef wcsncpy
|
||||
|
||||
#define calloc SDL_calloc
|
||||
#define malloc SDL_malloc
|
||||
#define realloc SDL_realloc
|
||||
#define free SDL_free
|
||||
#define iconv_t SDL_iconv_t
|
||||
#ifndef ICONV_CONST
|
||||
#define ICONV_CONST
|
||||
#define UNDEF_ICONV_CONST
|
||||
#endif
|
||||
#define iconv(a,b,c,d,e) SDL_iconv(a, (const char **)b, c, d, e)
|
||||
#define iconv_open SDL_iconv_open
|
||||
#define iconv_close SDL_iconv_close
|
||||
#define setlocale(X, Y) NULL
|
||||
#define snprintf SDL_snprintf
|
||||
#define strcmp SDL_strcmp
|
||||
#define strdup SDL_strdup
|
||||
#define strncpy SDL_strlcpy
|
||||
#define tolower SDL_tolower
|
||||
#define wcscmp SDL_wcscmp
|
||||
#define wcsdup SDL_wcsdup
|
||||
#define wcsncpy SDL_wcslcpy
|
||||
|
||||
|
||||
#ifndef SDL_PLATFORM_FREEBSD
|
||||
/* this is awkwardly inlined, so we need to re-implement it here
|
||||
* so we can override the libusb_control_transfer call */
|
||||
static int SDL_libusb_get_string_descriptor(libusb_device_handle *dev,
|
||||
uint8_t descriptor_index, uint16_t lang_id,
|
||||
unsigned char *data, int length)
|
||||
{
|
||||
return libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN | 0x0, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | descriptor_index, lang_id,
|
||||
data, (uint16_t)length, 1000); /* Endpoint 0 IN */
|
||||
}
|
||||
#define libusb_get_string_descriptor SDL_libusb_get_string_descriptor
|
||||
#endif /* SDL_PLATFORM_FREEBSD */
|
||||
|
||||
#define HIDAPI_THREAD_MODEL_INCLUDE "hidapi_thread_sdl.h"
|
||||
#ifndef LIBUSB_API_VERSION
|
||||
#ifdef LIBUSBX_API_VERSION
|
||||
#define LIBUSB_API_VERSION LIBUSBX_API_VERSION
|
||||
#else
|
||||
#define LIBUSB_API_VERSION 0x0
|
||||
#endif
|
||||
#endif
|
||||
/* we need libusb >= 1.0.16 because of libusb_get_port_numbers */
|
||||
/* we don't need libusb_wrap_sys_device: */
|
||||
#define HIDAPI_TARGET_LIBUSB_API_VERSION 0x01000102
|
||||
|
||||
#undef HIDAPI_H__
|
||||
#include "libusb/hid.c"
|
||||
|
||||
/* restore libc function macros */
|
||||
#ifdef UNDEF_ICONV_CONST
|
||||
#undef ICONV_CONST
|
||||
#undef UNDEF_ICONV_CONST
|
||||
#endif
|
||||
#pragma pop_macro("calloc")
|
||||
#pragma pop_macro("malloc")
|
||||
#pragma pop_macro("realloc")
|
||||
#pragma pop_macro("free")
|
||||
#pragma pop_macro("iconv_t")
|
||||
#pragma pop_macro("iconv")
|
||||
#pragma pop_macro("iconv_open")
|
||||
#pragma pop_macro("iconv_close")
|
||||
#pragma pop_macro("setlocale")
|
||||
#pragma pop_macro("snprintf")
|
||||
#pragma pop_macro("strcmp")
|
||||
#pragma pop_macro("strdup")
|
||||
#pragma pop_macro("strncpy")
|
||||
#pragma pop_macro("tolower")
|
||||
#pragma pop_macro("wcscmp")
|
||||
#pragma pop_macro("wcsdup")
|
||||
#pragma pop_macro("wcsncpy")
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifdef SDL_USE_LIBUDEV
|
||||
static const SDL_UDEV_Symbols *udev_ctx = NULL;
|
||||
|
||||
#define udev_device_get_devnode udev_ctx->udev_device_get_devnode
|
||||
#define udev_device_get_parent_with_subsystem_devtype udev_ctx->udev_device_get_parent_with_subsystem_devtype
|
||||
#define udev_device_get_sysattr_value udev_ctx->udev_device_get_sysattr_value
|
||||
#define udev_device_get_syspath udev_ctx->udev_device_get_syspath
|
||||
#define udev_device_new_from_devnum udev_ctx->udev_device_new_from_devnum
|
||||
#define udev_device_new_from_syspath udev_ctx->udev_device_new_from_syspath
|
||||
#define udev_device_unref udev_ctx->udev_device_unref
|
||||
#define udev_enumerate_add_match_subsystem udev_ctx->udev_enumerate_add_match_subsystem
|
||||
#define udev_enumerate_get_list_entry udev_ctx->udev_enumerate_get_list_entry
|
||||
#define udev_enumerate_new udev_ctx->udev_enumerate_new
|
||||
#define udev_enumerate_scan_devices udev_ctx->udev_enumerate_scan_devices
|
||||
#define udev_enumerate_unref udev_ctx->udev_enumerate_unref
|
||||
#define udev_list_entry_get_name udev_ctx->udev_list_entry_get_name
|
||||
#define udev_list_entry_get_next udev_ctx->udev_list_entry_get_next
|
||||
#define udev_new udev_ctx->udev_new
|
||||
#define udev_unref udev_ctx->udev_unref
|
||||
|
||||
#undef HIDAPI_H__
|
||||
#define HIDAPI_ALLOW_BUILD_WORKAROUND_KERNEL_2_6_39
|
||||
#include "linux/hid.c"
|
||||
#define HAVE_PLATFORM_BACKEND 1
|
||||
|
||||
#endif /* SDL_USE_LIBUDEV */
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#undef HIDAPI_H__
|
||||
#include "mac/hid.c"
|
||||
#define HAVE_PLATFORM_BACKEND 1
|
||||
#define udev_ctx 1
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#undef HIDAPI_H__
|
||||
#include "netbsd/hid.c"
|
||||
#define HAVE_PLATFORM_BACKEND 1
|
||||
#define udev_ctx 1
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#undef HIDAPI_H__
|
||||
#include "steamxbox/hid.c"
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/* Define standard library functions in terms of SDL */
|
||||
|
||||
/* #pragma push_macro/pop_macro works correctly only as of gcc >= 4.4.3
|
||||
clang-3.0 _seems_ to be OK. */
|
||||
#pragma push_macro("calloc")
|
||||
#pragma push_macro("free")
|
||||
#pragma push_macro("malloc")
|
||||
#pragma push_macro("memcmp")
|
||||
#pragma push_macro("swprintf")
|
||||
#pragma push_macro("towupper")
|
||||
#pragma push_macro("wcscmp")
|
||||
#pragma push_macro("_wcsdup")
|
||||
#pragma push_macro("wcslen")
|
||||
#pragma push_macro("wcsncpy")
|
||||
#pragma push_macro("wcsstr")
|
||||
#pragma push_macro("wcstol")
|
||||
|
||||
#undef calloc
|
||||
#undef free
|
||||
#undef malloc
|
||||
#undef memcmp
|
||||
#undef swprintf
|
||||
#undef towupper
|
||||
#undef wcscmp
|
||||
#undef _wcsdup
|
||||
#undef wcslen
|
||||
#undef wcsncpy
|
||||
#undef wcsstr
|
||||
#undef wcstol
|
||||
|
||||
#define calloc SDL_calloc
|
||||
#define free SDL_free
|
||||
#define malloc SDL_malloc
|
||||
#define memcmp SDL_memcmp
|
||||
#define swprintf SDL_swprintf
|
||||
#define towupper (wchar_t)SDL_toupper
|
||||
#define wcscmp SDL_wcscmp
|
||||
#define _wcsdup SDL_wcsdup
|
||||
#define wcslen SDL_wcslen
|
||||
#define wcsncpy SDL_wcslcpy
|
||||
#define wcsstr SDL_wcsstr
|
||||
#define wcstol SDL_wcstol
|
||||
|
||||
// These functions conflict when linking both SDL and hidapi statically
|
||||
#define hid_winapi_descriptor_reconstruct_pp_data SDL_hid_winapi_descriptor_reconstruct_pp_data
|
||||
#define hid_winapi_get_container_id SDL_hid_winapi_get_container_id
|
||||
|
||||
#undef HIDAPI_H__
|
||||
#include "windows/hid.c"
|
||||
#define HAVE_PLATFORM_BACKEND 1
|
||||
#define udev_ctx 1
|
||||
|
||||
/* restore libc function macros */
|
||||
#pragma pop_macro("calloc")
|
||||
#pragma pop_macro("free")
|
||||
#pragma pop_macro("malloc")
|
||||
#pragma pop_macro("memcmp")
|
||||
#pragma pop_macro("swprintf")
|
||||
#pragma pop_macro("towupper")
|
||||
#pragma pop_macro("wcscmp")
|
||||
#pragma pop_macro("_wcsdup")
|
||||
#pragma pop_macro("wcslen")
|
||||
#pragma pop_macro("wcsncpy")
|
||||
#pragma pop_macro("wcsstr")
|
||||
#pragma pop_macro("wcstol")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 2022 Valve Corporation
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
// Purpose: Exporting table containing HIDDeviceManager native methods
|
||||
|
||||
#ifndef SDL_android_hid_h_
|
||||
#define SDL_android_hid_h_
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern JNINativeMethod HIDDeviceManager_tab[8];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,634 @@
|
||||
/*******************************************************
|
||||
HIDAPI - Multi-Platform library for
|
||||
communication with HID devices.
|
||||
|
||||
Alan Ott
|
||||
Signal 11 Software
|
||||
|
||||
libusb/hidapi Team
|
||||
|
||||
Copyright 2023, All Rights Reserved.
|
||||
|
||||
At the discretion of the user of this library,
|
||||
this software may be licensed under the terms of the
|
||||
GNU General Public License v3, a BSD-Style license, or the
|
||||
original HIDAPI license as outlined in the LICENSE.txt,
|
||||
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
|
||||
files located at the root of the source distribution.
|
||||
These files may also be found in the public source
|
||||
code repository located at:
|
||||
https://github.com/libusb/hidapi .
|
||||
********************************************************/
|
||||
|
||||
/** @file
|
||||
* @defgroup API hidapi API
|
||||
*/
|
||||
|
||||
#ifndef HIDAPI_H__
|
||||
#define HIDAPI_H__
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
/* #480: this is to be refactored properly for v1.0 */
|
||||
#ifdef _WIN32
|
||||
#ifndef HID_API_NO_EXPORT_DEFINE
|
||||
#define HID_API_EXPORT __declspec(dllexport)
|
||||
#endif
|
||||
#endif
|
||||
#ifndef HID_API_EXPORT
|
||||
#define HID_API_EXPORT /**< API export macro */
|
||||
#endif
|
||||
/* To be removed in v1.0 */
|
||||
#define HID_API_CALL /**< API call macro */
|
||||
|
||||
#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/
|
||||
|
||||
/** @brief Static/compile-time major version of the library.
|
||||
|
||||
@ingroup API
|
||||
*/
|
||||
#define HID_API_VERSION_MAJOR 0
|
||||
/** @brief Static/compile-time minor version of the library.
|
||||
|
||||
@ingroup API
|
||||
*/
|
||||
#define HID_API_VERSION_MINOR 14
|
||||
/** @brief Static/compile-time patch version of the library.
|
||||
|
||||
@ingroup API
|
||||
*/
|
||||
#define HID_API_VERSION_PATCH 0
|
||||
|
||||
/* Helper macros */
|
||||
#define HID_API_AS_STR_IMPL(x) #x
|
||||
#define HID_API_AS_STR(x) HID_API_AS_STR_IMPL(x)
|
||||
#define HID_API_TO_VERSION_STR(v1, v2, v3) HID_API_AS_STR(v1.v2.v3)
|
||||
|
||||
/** @brief Coverts a version as Major/Minor/Patch into a number:
|
||||
<8 bit major><16 bit minor><8 bit patch>.
|
||||
|
||||
This macro was added in version 0.12.0.
|
||||
|
||||
Convenient function to be used for compile-time checks, like:
|
||||
@code{.c}
|
||||
#if HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
|
||||
@endcode
|
||||
|
||||
@ingroup API
|
||||
*/
|
||||
#define HID_API_MAKE_VERSION(mj, mn, p) (((mj) << 24) | ((mn) << 8) | (p))
|
||||
|
||||
/** @brief Static/compile-time version of the library.
|
||||
|
||||
This macro was added in version 0.12.0.
|
||||
|
||||
@see @ref HID_API_MAKE_VERSION.
|
||||
|
||||
@ingroup API
|
||||
*/
|
||||
#define HID_API_VERSION HID_API_MAKE_VERSION(HID_API_VERSION_MAJOR, HID_API_VERSION_MINOR, HID_API_VERSION_PATCH)
|
||||
|
||||
/** @brief Static/compile-time string version of the library.
|
||||
|
||||
@ingroup API
|
||||
*/
|
||||
#define HID_API_VERSION_STR HID_API_TO_VERSION_STR(HID_API_VERSION_MAJOR, HID_API_VERSION_MINOR, HID_API_VERSION_PATCH)
|
||||
|
||||
/** @brief Maximum expected HID Report descriptor size in bytes.
|
||||
|
||||
Since version 0.13.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 13, 0)
|
||||
|
||||
@ingroup API
|
||||
*/
|
||||
#define HID_API_MAX_REPORT_DESCRIPTOR_SIZE 4096
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#ifndef DEFINED_HID_TYPES
|
||||
#define DEFINED_HID_TYPES
|
||||
/** A structure to hold the version numbers. */
|
||||
struct hid_api_version {
|
||||
int major; /**< major version number */
|
||||
int minor; /**< minor version number */
|
||||
int patch; /**< patch version number */
|
||||
};
|
||||
|
||||
struct hid_device_;
|
||||
typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
|
||||
|
||||
/** @brief HID underlying bus types.
|
||||
|
||||
@ingroup API
|
||||
*/
|
||||
typedef enum {
|
||||
/** Unknown bus type */
|
||||
HID_API_BUS_UNKNOWN = 0x00,
|
||||
|
||||
/** USB bus
|
||||
Specifications:
|
||||
https://usb.org/hid */
|
||||
HID_API_BUS_USB = 0x01,
|
||||
|
||||
/** Bluetooth or Bluetooth LE bus
|
||||
Specifications:
|
||||
https://www.bluetooth.com/specifications/specs/human-interface-device-profile-1-1-1/
|
||||
https://www.bluetooth.com/specifications/specs/hid-service-1-0/
|
||||
https://www.bluetooth.com/specifications/specs/hid-over-gatt-profile-1-0/ */
|
||||
HID_API_BUS_BLUETOOTH = 0x02,
|
||||
|
||||
/** I2C bus
|
||||
Specifications:
|
||||
https://docs.microsoft.com/previous-versions/windows/hardware/design/dn642101(v=vs.85) */
|
||||
HID_API_BUS_I2C = 0x03,
|
||||
|
||||
/** SPI bus
|
||||
Specifications:
|
||||
https://www.microsoft.com/download/details.aspx?id=103325 */
|
||||
HID_API_BUS_SPI = 0x04,
|
||||
} hid_bus_type;
|
||||
|
||||
/** hidapi info structure */
|
||||
struct hid_device_info {
|
||||
/** Platform-specific device path */
|
||||
char *path;
|
||||
/** Device Vendor ID */
|
||||
unsigned short vendor_id;
|
||||
/** Device Product ID */
|
||||
unsigned short product_id;
|
||||
/** Serial Number */
|
||||
wchar_t *serial_number;
|
||||
/** Device Release Number in binary-coded decimal,
|
||||
also known as Device Version Number */
|
||||
unsigned short release_number;
|
||||
/** Manufacturer String */
|
||||
wchar_t *manufacturer_string;
|
||||
/** Product string */
|
||||
wchar_t *product_string;
|
||||
/** Usage Page for this Device/Interface
|
||||
(Windows/Mac/hidraw only) */
|
||||
unsigned short usage_page;
|
||||
/** Usage for this Device/Interface
|
||||
(Windows/Mac/hidraw only) */
|
||||
unsigned short usage;
|
||||
/** The USB interface which this logical device
|
||||
represents.
|
||||
|
||||
Valid only if the device is a USB HID device.
|
||||
Set to -1 in all other cases.
|
||||
*/
|
||||
int interface_number;
|
||||
|
||||
/** Pointer to the next device */
|
||||
struct hid_device_info *next;
|
||||
|
||||
/** Underlying bus type
|
||||
Since version 0.13.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 13, 0)
|
||||
*/
|
||||
hid_bus_type bus_type;
|
||||
|
||||
/** Additional information about the USB interface.
|
||||
(libusb only) */
|
||||
int interface_class;
|
||||
int interface_subclass;
|
||||
int interface_protocol;
|
||||
};
|
||||
|
||||
#endif /* DEFINED_HID_TYPES */
|
||||
|
||||
|
||||
/** @brief Initialize the HIDAPI library.
|
||||
|
||||
This function initializes the HIDAPI library. Calling it is not
|
||||
strictly necessary, as it will be called automatically by
|
||||
hid_enumerate() and any of the hid_open_*() functions if it is
|
||||
needed. This function should be called at the beginning of
|
||||
execution however, if there is a chance of HIDAPI handles
|
||||
being opened by different threads simultaneously.
|
||||
|
||||
@ingroup API
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
Call hid_error(NULL) to get the failure reason.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_init(void);
|
||||
|
||||
/** @brief Finalize the HIDAPI library.
|
||||
|
||||
This function frees all of the static data associated with
|
||||
HIDAPI. It should be called at the end of execution to avoid
|
||||
memory leaks.
|
||||
|
||||
@ingroup API
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_exit(void);
|
||||
|
||||
/** @brief Enumerate the HID Devices.
|
||||
|
||||
This function returns a linked list of all the HID devices
|
||||
attached to the system which match vendor_id and product_id.
|
||||
If @p vendor_id is set to 0 then any vendor matches.
|
||||
If @p product_id is set to 0 then any product matches.
|
||||
If @p vendor_id and @p product_id are both set to 0, then
|
||||
all HID devices will be returned.
|
||||
|
||||
@ingroup API
|
||||
@param vendor_id The Vendor ID (VID) of the types of device
|
||||
to open.
|
||||
@param product_id The Product ID (PID) of the types of
|
||||
device to open.
|
||||
|
||||
@returns
|
||||
This function returns a pointer to a linked list of type
|
||||
struct #hid_device_info, containing information about the HID devices
|
||||
attached to the system,
|
||||
or NULL in the case of failure or if no HID devices present in the system.
|
||||
Call hid_error(NULL) to get the failure reason.
|
||||
|
||||
@note The returned value by this function must to be freed by calling hid_free_enumeration(),
|
||||
when not needed anymore.
|
||||
*/
|
||||
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
|
||||
|
||||
/** @brief Free an enumeration Linked List
|
||||
|
||||
This function frees a linked list created by hid_enumerate().
|
||||
|
||||
@ingroup API
|
||||
@param devs Pointer to a list of struct_device returned from
|
||||
hid_enumerate().
|
||||
*/
|
||||
void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
|
||||
|
||||
/** @brief Open a HID device using a Vendor ID (VID), Product ID
|
||||
(PID) and optionally a serial number.
|
||||
|
||||
If @p serial_number is NULL, the first device with the
|
||||
specified VID and PID is opened.
|
||||
|
||||
@ingroup API
|
||||
@param vendor_id The Vendor ID (VID) of the device to open.
|
||||
@param product_id The Product ID (PID) of the device to open.
|
||||
@param serial_number The Serial Number of the device to open
|
||||
(Optionally NULL).
|
||||
|
||||
@returns
|
||||
This function returns a pointer to a #hid_device object on
|
||||
success or NULL on failure.
|
||||
Call hid_error(NULL) to get the failure reason.
|
||||
|
||||
@note The returned object must be freed by calling hid_close(),
|
||||
when not needed anymore.
|
||||
*/
|
||||
HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);
|
||||
|
||||
/** @brief Open a HID device by its path name.
|
||||
|
||||
The path name be determined by calling hid_enumerate(), or a
|
||||
platform-specific path name can be used (eg: /dev/hidraw0 on
|
||||
Linux).
|
||||
|
||||
@ingroup API
|
||||
@param path The path name of the device to open
|
||||
|
||||
@returns
|
||||
This function returns a pointer to a #hid_device object on
|
||||
success or NULL on failure.
|
||||
Call hid_error(NULL) to get the failure reason.
|
||||
|
||||
@note The returned object must be freed by calling hid_close(),
|
||||
when not needed anymore.
|
||||
*/
|
||||
HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);
|
||||
|
||||
/** @brief Write an Output report to a HID device.
|
||||
|
||||
The first byte of @p data[] must contain the Report ID. For
|
||||
devices which only support a single report, this must be set
|
||||
to 0x0. The remaining bytes contain the report data. Since
|
||||
the Report ID is mandatory, calls to hid_write() will always
|
||||
contain one more byte than the report contains. For example,
|
||||
if a hid report is 16 bytes long, 17 bytes must be passed to
|
||||
hid_write(), the Report ID (or 0x0, for devices with a
|
||||
single report), followed by the report data (16 bytes). In
|
||||
this example, the length passed in would be 17.
|
||||
|
||||
hid_write() will send the data on the first OUT endpoint, if
|
||||
one exists. If it does not, it will send the data through
|
||||
the Control Endpoint (Endpoint 0).
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param data The data to send, including the report number as
|
||||
the first byte.
|
||||
@param length The length in bytes of the data to send.
|
||||
|
||||
@returns
|
||||
This function returns the actual number of bytes written and
|
||||
-1 on error.
|
||||
Call hid_error(dev) to get the failure reason.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length);
|
||||
|
||||
/** @brief Read an Input report from a HID device with timeout.
|
||||
|
||||
Input reports are returned
|
||||
to the host through the INTERRUPT IN endpoint. The first byte will
|
||||
contain the Report number if the device uses numbered reports.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param data A buffer to put the read data into.
|
||||
@param length The number of bytes to read. For devices with
|
||||
multiple reports, make sure to read an extra byte for
|
||||
the report number.
|
||||
@param milliseconds timeout in milliseconds or -1 for blocking wait.
|
||||
|
||||
@returns
|
||||
This function returns the actual number of bytes read and
|
||||
-1 on error.
|
||||
Call hid_error(dev) to get the failure reason.
|
||||
If no packet was available to be read within
|
||||
the timeout period, this function returns 0.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
|
||||
|
||||
/** @brief Read an Input report from a HID device.
|
||||
|
||||
Input reports are returned
|
||||
to the host through the INTERRUPT IN endpoint. The first byte will
|
||||
contain the Report number if the device uses numbered reports.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param data A buffer to put the read data into.
|
||||
@param length The number of bytes to read. For devices with
|
||||
multiple reports, make sure to read an extra byte for
|
||||
the report number.
|
||||
|
||||
@returns
|
||||
This function returns the actual number of bytes read and
|
||||
-1 on error.
|
||||
Call hid_error(dev) to get the failure reason.
|
||||
If no packet was available to be read and
|
||||
the handle is in non-blocking mode, this function returns 0.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length);
|
||||
|
||||
/** @brief Set the device handle to be non-blocking.
|
||||
|
||||
In non-blocking mode calls to hid_read() will return
|
||||
immediately with a value of 0 if there is no data to be
|
||||
read. In blocking mode, hid_read() will wait (block) until
|
||||
there is data to read before returning.
|
||||
|
||||
Nonblocking can be turned on and off at any time.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param nonblock enable or not the nonblocking reads
|
||||
- 1 to enable nonblocking
|
||||
- 0 to disable nonblocking.
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
Call hid_error(dev) to get the failure reason.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock);
|
||||
|
||||
/** @brief Send a Feature report to the device.
|
||||
|
||||
Feature reports are sent over the Control endpoint as a
|
||||
Set_Report transfer. The first byte of @p data[] must
|
||||
contain the Report ID. For devices which only support a
|
||||
single report, this must be set to 0x0. The remaining bytes
|
||||
contain the report data. Since the Report ID is mandatory,
|
||||
calls to hid_send_feature_report() will always contain one
|
||||
more byte than the report contains. For example, if a hid
|
||||
report is 16 bytes long, 17 bytes must be passed to
|
||||
hid_send_feature_report(): the Report ID (or 0x0, for
|
||||
devices which do not use numbered reports), followed by the
|
||||
report data (16 bytes). In this example, the length passed
|
||||
in would be 17.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param data The data to send, including the report number as
|
||||
the first byte.
|
||||
@param length The length in bytes of the data to send, including
|
||||
the report number.
|
||||
|
||||
@returns
|
||||
This function returns the actual number of bytes written and
|
||||
-1 on error.
|
||||
Call hid_error(dev) to get the failure reason.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length);
|
||||
|
||||
/** @brief Get a feature report from a HID device.
|
||||
|
||||
Set the first byte of @p data[] to the Report ID of the
|
||||
report to be read. Make sure to allow space for this
|
||||
extra byte in @p data[]. Upon return, the first byte will
|
||||
still contain the Report ID, and the report data will
|
||||
start in data[1].
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param data A buffer to put the read data into, including
|
||||
the Report ID. Set the first byte of @p data[] to the
|
||||
Report ID of the report to be read, or set it to zero
|
||||
if your device does not use numbered reports.
|
||||
@param length The number of bytes to read, including an
|
||||
extra byte for the report ID. The buffer can be longer
|
||||
than the actual report.
|
||||
|
||||
@returns
|
||||
This function returns the number of bytes read plus
|
||||
one for the report ID (which is still in the first
|
||||
byte), or -1 on error.
|
||||
Call hid_error(dev) to get the failure reason.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length);
|
||||
|
||||
/** @brief Get a input report from a HID device.
|
||||
|
||||
Since version 0.10.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 10, 0)
|
||||
|
||||
Set the first byte of @p data[] to the Report ID of the
|
||||
report to be read. Make sure to allow space for this
|
||||
extra byte in @p data[]. Upon return, the first byte will
|
||||
still contain the Report ID, and the report data will
|
||||
start in data[1].
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param data A buffer to put the read data into, including
|
||||
the Report ID. Set the first byte of @p data[] to the
|
||||
Report ID of the report to be read, or set it to zero
|
||||
if your device does not use numbered reports.
|
||||
@param length The number of bytes to read, including an
|
||||
extra byte for the report ID. The buffer can be longer
|
||||
than the actual report.
|
||||
|
||||
@returns
|
||||
This function returns the number of bytes read plus
|
||||
one for the report ID (which is still in the first
|
||||
byte), or -1 on error.
|
||||
Call hid_error(dev) to get the failure reason.
|
||||
*/
|
||||
int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length);
|
||||
|
||||
/** @brief Close a HID device.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
*/
|
||||
void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev);
|
||||
|
||||
/** @brief Get The Manufacturer String from a HID device.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param string A wide string buffer to put the data into.
|
||||
@param maxlen The length of the buffer in multiples of wchar_t.
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
Call hid_error(dev) to get the failure reason.
|
||||
*/
|
||||
int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen);
|
||||
|
||||
/** @brief Get The Product String from a HID device.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param string A wide string buffer to put the data into.
|
||||
@param maxlen The length of the buffer in multiples of wchar_t.
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
Call hid_error(dev) to get the failure reason.
|
||||
*/
|
||||
int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen);
|
||||
|
||||
/** @brief Get The Serial Number String from a HID device.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param string A wide string buffer to put the data into.
|
||||
@param maxlen The length of the buffer in multiples of wchar_t.
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
Call hid_error(dev) to get the failure reason.
|
||||
*/
|
||||
int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen);
|
||||
|
||||
/** @brief Get The struct #hid_device_info from a HID device.
|
||||
|
||||
Since version 0.13.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 13, 0)
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
|
||||
@returns
|
||||
This function returns a pointer to the struct #hid_device_info
|
||||
for this hid_device, or NULL in the case of failure.
|
||||
Call hid_error(dev) to get the failure reason.
|
||||
This struct is valid until the device is closed with hid_close().
|
||||
|
||||
@note The returned object is owned by the @p dev, and SHOULD NOT be freed by the user.
|
||||
*/
|
||||
struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_get_device_info(hid_device *dev);
|
||||
|
||||
/** @brief Get a string from a HID device, based on its string index.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param string_index The index of the string to get.
|
||||
@param string A wide string buffer to put the data into.
|
||||
@param maxlen The length of the buffer in multiples of wchar_t.
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
Call hid_error(dev) to get the failure reason.
|
||||
*/
|
||||
int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen);
|
||||
|
||||
/** @brief Get a report descriptor from a HID device.
|
||||
|
||||
Since version 0.14.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 14, 0)
|
||||
|
||||
User has to provide a preallocated buffer where descriptor will be copied to.
|
||||
The recommended size for preallocated buffer is @ref HID_API_MAX_REPORT_DESCRIPTOR_SIZE bytes.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param buf The buffer to copy descriptor into.
|
||||
@param buf_size The size of the buffer in bytes.
|
||||
|
||||
@returns
|
||||
This function returns non-negative number of bytes actually copied, or -1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT_CALL hid_get_report_descriptor(hid_device *dev, unsigned char *buf, size_t buf_size);
|
||||
|
||||
/** @brief Get a string describing the last error which occurred.
|
||||
|
||||
This function is intended for logging/debugging purposes.
|
||||
|
||||
This function guarantees to never return NULL.
|
||||
If there was no error in the last function call -
|
||||
the returned string clearly indicates that.
|
||||
|
||||
Any HIDAPI function that can explicitly indicate an execution failure
|
||||
(e.g. by an error code, or by returning NULL) - may set the error string,
|
||||
to be returned by this function.
|
||||
|
||||
Strings returned from hid_error() must not be freed by the user,
|
||||
i.e. owned by HIDAPI library.
|
||||
Device-specific error string may remain allocated at most until hid_close() is called.
|
||||
Global error string may remain allocated at most until hid_exit() is called.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open(),
|
||||
or NULL to get the last non-device-specific error
|
||||
(e.g. for errors in hid_open() or hid_enumerate()).
|
||||
|
||||
@returns
|
||||
A string describing the last error (if any).
|
||||
*/
|
||||
HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *dev);
|
||||
|
||||
/** @brief Get a runtime version of the library.
|
||||
|
||||
This function is thread-safe.
|
||||
|
||||
@ingroup API
|
||||
|
||||
@returns
|
||||
Pointer to statically allocated struct, that contains version.
|
||||
*/
|
||||
HID_API_EXPORT const struct hid_api_version* HID_API_CALL hid_version(void);
|
||||
|
||||
|
||||
/** @brief Get a runtime version string of the library.
|
||||
|
||||
This function is thread-safe.
|
||||
|
||||
@ingroup API
|
||||
|
||||
@returns
|
||||
Pointer to statically allocated string, that contains version string.
|
||||
*/
|
||||
HID_API_EXPORT const char* HID_API_CALL hid_version_str(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
cmake_minimum_required(VERSION 3.1.3...3.25 FATAL_ERROR)
|
||||
project(hidtest C)
|
||||
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
# hidtest is build as a standalone project
|
||||
|
||||
if(POLICY CMP0074)
|
||||
# allow using hidapi_ROOT if CMake supports it
|
||||
cmake_policy(SET CMP0074 NEW)
|
||||
endif()
|
||||
|
||||
find_package(hidapi 0.12 REQUIRED)
|
||||
message(STATUS "Using HIDAPI: ${hidapi_VERSION}")
|
||||
else()
|
||||
# hidtest is built as part of the main HIDAPI build
|
||||
message(STATUS "Building hidtest")
|
||||
endif()
|
||||
|
||||
set(HIDAPI_HIDTEST_TARGETS)
|
||||
if(NOT WIN32 AND NOT APPLE AND CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
if(TARGET hidapi::hidraw)
|
||||
add_executable(hidtest_hidraw test.c)
|
||||
target_link_libraries(hidtest_hidraw hidapi::hidraw)
|
||||
list(APPEND HIDAPI_HIDTEST_TARGETS hidtest_hidraw)
|
||||
endif()
|
||||
if(TARGET hidapi::libusb)
|
||||
add_executable(hidtest_libusb test.c)
|
||||
target_compile_definitions(hidtest_libusb PRIVATE USING_HIDAPI_LIBUSB)
|
||||
target_link_libraries(hidtest_libusb hidapi::libusb)
|
||||
list(APPEND HIDAPI_HIDTEST_TARGETS hidtest_libusb)
|
||||
endif()
|
||||
else()
|
||||
add_executable(hidtest test.c)
|
||||
target_link_libraries(hidtest hidapi::hidapi)
|
||||
list(APPEND HIDAPI_HIDTEST_TARGETS hidtest)
|
||||
endif()
|
||||
|
||||
install(TARGETS ${HIDAPI_HIDTEST_TARGETS}
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
)
|
||||
@@ -0,0 +1,316 @@
|
||||
/*******************************************************
|
||||
HIDAPI - Multi-Platform library for
|
||||
communication with HID devices.
|
||||
|
||||
Alan Ott
|
||||
Signal 11 Software
|
||||
|
||||
libusb/hidapi Team
|
||||
|
||||
Copyright 2022.
|
||||
|
||||
This contents of this file may be used by anyone
|
||||
for any reason without any conditions and may be
|
||||
used as a starting point for your own applications
|
||||
which use HIDAPI.
|
||||
********************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <wchar.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <hidapi.h>
|
||||
|
||||
// Headers needed for sleeping.
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
// Fallback/example
|
||||
#ifndef HID_API_MAKE_VERSION
|
||||
#define HID_API_MAKE_VERSION(mj, mn, p) (((mj) << 24) | ((mn) << 8) | (p))
|
||||
#endif
|
||||
#ifndef HID_API_VERSION
|
||||
#define HID_API_VERSION HID_API_MAKE_VERSION(HID_API_VERSION_MAJOR, HID_API_VERSION_MINOR, HID_API_VERSION_PATCH)
|
||||
#endif
|
||||
|
||||
//
|
||||
// Sample using platform-specific headers
|
||||
#if defined(__APPLE__) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
|
||||
#include <hidapi_darwin.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
|
||||
#include <hidapi_winapi.h>
|
||||
#endif
|
||||
|
||||
#if defined(USING_HIDAPI_LIBUSB) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
|
||||
#include <hidapi_libusb.h>
|
||||
#endif
|
||||
//
|
||||
|
||||
const char *hid_bus_name(hid_bus_type bus_type) {
|
||||
static const char *const HidBusTypeName[] = {
|
||||
"Unknown",
|
||||
"USB",
|
||||
"Bluetooth",
|
||||
"I2C",
|
||||
"SPI",
|
||||
};
|
||||
|
||||
if ((int)bus_type < 0)
|
||||
bus_type = HID_API_BUS_UNKNOWN;
|
||||
if ((int)bus_type >= (int)(sizeof(HidBusTypeName) / sizeof(HidBusTypeName[0])))
|
||||
bus_type = HID_API_BUS_UNKNOWN;
|
||||
|
||||
return HidBusTypeName[bus_type];
|
||||
}
|
||||
|
||||
void print_device(struct hid_device_info *cur_dev) {
|
||||
printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
|
||||
printf("\n");
|
||||
printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string);
|
||||
printf(" Product: %ls\n", cur_dev->product_string);
|
||||
printf(" Release: %hx\n", cur_dev->release_number);
|
||||
printf(" Interface: %d\n", cur_dev->interface_number);
|
||||
printf(" Usage (page): 0x%hx (0x%hx)\n", cur_dev->usage, cur_dev->usage_page);
|
||||
printf(" Bus type: %u (%s)\n", (unsigned)cur_dev->bus_type, hid_bus_name(cur_dev->bus_type));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void print_hid_report_descriptor_from_device(hid_device *device) {
|
||||
unsigned char descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE];
|
||||
int res = 0;
|
||||
|
||||
printf(" Report Descriptor: ");
|
||||
res = hid_get_report_descriptor(device, descriptor, sizeof(descriptor));
|
||||
if (res < 0) {
|
||||
printf("error getting: %ls", hid_error(device));
|
||||
}
|
||||
else {
|
||||
printf("(%d bytes)", res);
|
||||
}
|
||||
for (int i = 0; i < res; i++) {
|
||||
if (i % 10 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
printf("0x%02x, ", descriptor[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void print_hid_report_descriptor_from_path(const char *path) {
|
||||
hid_device *device = hid_open_path(path);
|
||||
if (device) {
|
||||
print_hid_report_descriptor_from_device(device);
|
||||
hid_close(device);
|
||||
}
|
||||
else {
|
||||
printf(" Report Descriptor: Unable to open device by path\n");
|
||||
}
|
||||
}
|
||||
|
||||
void print_devices(struct hid_device_info *cur_dev) {
|
||||
for (; cur_dev; cur_dev = cur_dev->next) {
|
||||
print_device(cur_dev);
|
||||
}
|
||||
}
|
||||
|
||||
void print_devices_with_descriptor(struct hid_device_info *cur_dev) {
|
||||
for (; cur_dev; cur_dev = cur_dev->next) {
|
||||
print_device(cur_dev);
|
||||
print_hid_report_descriptor_from_path(cur_dev->path);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
int res;
|
||||
unsigned char buf[256];
|
||||
#define MAX_STR 255
|
||||
wchar_t wstr[MAX_STR];
|
||||
hid_device *handle;
|
||||
int i;
|
||||
|
||||
struct hid_device_info *devs;
|
||||
|
||||
printf("hidapi test/example tool. Compiled with hidapi version %s, runtime version %s.\n", HID_API_VERSION_STR, hid_version_str());
|
||||
if (HID_API_VERSION == HID_API_MAKE_VERSION(hid_version()->major, hid_version()->minor, hid_version()->patch)) {
|
||||
printf("Compile-time version matches runtime version of hidapi.\n\n");
|
||||
}
|
||||
else {
|
||||
printf("Compile-time version is different than runtime version of hidapi.\n]n");
|
||||
}
|
||||
|
||||
if (hid_init())
|
||||
return -1;
|
||||
|
||||
#if defined(__APPLE__) && HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
|
||||
// To work properly needs to be called before hid_open/hid_open_path after hid_init.
|
||||
// Best/recommended option - call it right after hid_init.
|
||||
hid_darwin_set_open_exclusive(0);
|
||||
#endif
|
||||
|
||||
devs = hid_enumerate(0x0, 0x0);
|
||||
print_devices_with_descriptor(devs);
|
||||
hid_free_enumeration(devs);
|
||||
|
||||
// Set up the command buffer.
|
||||
memset(buf,0x00,sizeof(buf));
|
||||
buf[0] = 0x01;
|
||||
buf[1] = 0x81;
|
||||
|
||||
|
||||
// Open the device using the VID, PID,
|
||||
// and optionally the Serial number.
|
||||
////handle = hid_open(0x4d8, 0x3f, L"12345");
|
||||
handle = hid_open(0x4d8, 0x3f, NULL);
|
||||
if (!handle) {
|
||||
printf("unable to open device\n");
|
||||
hid_exit();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Read the Manufacturer String
|
||||
wstr[0] = 0x0000;
|
||||
res = hid_get_manufacturer_string(handle, wstr, MAX_STR);
|
||||
if (res < 0)
|
||||
printf("Unable to read manufacturer string\n");
|
||||
printf("Manufacturer String: %ls\n", wstr);
|
||||
|
||||
// Read the Product String
|
||||
wstr[0] = 0x0000;
|
||||
res = hid_get_product_string(handle, wstr, MAX_STR);
|
||||
if (res < 0)
|
||||
printf("Unable to read product string\n");
|
||||
printf("Product String: %ls\n", wstr);
|
||||
|
||||
// Read the Serial Number String
|
||||
wstr[0] = 0x0000;
|
||||
res = hid_get_serial_number_string(handle, wstr, MAX_STR);
|
||||
if (res < 0)
|
||||
printf("Unable to read serial number string\n");
|
||||
printf("Serial Number String: (%d) %ls\n", wstr[0], wstr);
|
||||
|
||||
print_hid_report_descriptor_from_device(handle);
|
||||
|
||||
struct hid_device_info* info = hid_get_device_info(handle);
|
||||
if (info == NULL) {
|
||||
printf("Unable to get device info\n");
|
||||
} else {
|
||||
print_devices(info);
|
||||
}
|
||||
|
||||
// Read Indexed String 1
|
||||
wstr[0] = 0x0000;
|
||||
res = hid_get_indexed_string(handle, 1, wstr, MAX_STR);
|
||||
if (res < 0)
|
||||
printf("Unable to read indexed string 1\n");
|
||||
printf("Indexed String 1: %ls\n", wstr);
|
||||
|
||||
// Set the hid_read() function to be non-blocking.
|
||||
hid_set_nonblocking(handle, 1);
|
||||
|
||||
// Try to read from the device. There should be no
|
||||
// data here, but execution should not block.
|
||||
res = hid_read(handle, buf, 17);
|
||||
|
||||
// Send a Feature Report to the device
|
||||
buf[0] = 0x2;
|
||||
buf[1] = 0xa0;
|
||||
buf[2] = 0x0a;
|
||||
buf[3] = 0x00;
|
||||
buf[4] = 0x00;
|
||||
res = hid_send_feature_report(handle, buf, 17);
|
||||
if (res < 0) {
|
||||
printf("Unable to send a feature report.\n");
|
||||
}
|
||||
|
||||
memset(buf,0,sizeof(buf));
|
||||
|
||||
// Read a Feature Report from the device
|
||||
buf[0] = 0x2;
|
||||
res = hid_get_feature_report(handle, buf, sizeof(buf));
|
||||
if (res < 0) {
|
||||
printf("Unable to get a feature report: %ls\n", hid_error(handle));
|
||||
}
|
||||
else {
|
||||
// Print out the returned buffer.
|
||||
printf("Feature Report\n ");
|
||||
for (i = 0; i < res; i++)
|
||||
printf("%02x ", (unsigned int) buf[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
memset(buf,0,sizeof(buf));
|
||||
|
||||
// Toggle LED (cmd 0x80). The first byte is the report number (0x1).
|
||||
buf[0] = 0x1;
|
||||
buf[1] = 0x80;
|
||||
res = hid_write(handle, buf, 17);
|
||||
if (res < 0) {
|
||||
printf("Unable to write(): %ls\n", hid_error(handle));
|
||||
}
|
||||
|
||||
|
||||
// Request state (cmd 0x81). The first byte is the report number (0x1).
|
||||
buf[0] = 0x1;
|
||||
buf[1] = 0x81;
|
||||
hid_write(handle, buf, 17);
|
||||
if (res < 0) {
|
||||
printf("Unable to write()/2: %ls\n", hid_error(handle));
|
||||
}
|
||||
|
||||
// Read requested state. hid_read() has been set to be
|
||||
// non-blocking by the call to hid_set_nonblocking() above.
|
||||
// This loop demonstrates the non-blocking nature of hid_read().
|
||||
res = 0;
|
||||
i = 0;
|
||||
while (res == 0) {
|
||||
res = hid_read(handle, buf, sizeof(buf));
|
||||
if (res == 0) {
|
||||
printf("waiting...\n");
|
||||
}
|
||||
if (res < 0) {
|
||||
printf("Unable to read(): %ls\n", hid_error(handle));
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
if (i >= 10) { /* 10 tries by 500 ms - 5 seconds of waiting*/
|
||||
printf("read() timeout\n");
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
Sleep(500);
|
||||
#else
|
||||
usleep(500*1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (res > 0) {
|
||||
printf("Data read:\n ");
|
||||
// Print out the returned buffer.
|
||||
for (i = 0; i < res; i++)
|
||||
printf("%02x ", (unsigned int) buf[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
hid_close(handle);
|
||||
|
||||
/* Free static HIDAPI objects. */
|
||||
hid_exit();
|
||||
|
||||
#ifdef _WIN32
|
||||
system("pause");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
cmake_minimum_required(VERSION 3.6.3...3.25 FATAL_ERROR)
|
||||
|
||||
list(APPEND HIDAPI_PUBLIC_HEADERS "hidapi_libusb.h")
|
||||
|
||||
add_library(hidapi_libusb
|
||||
${HIDAPI_PUBLIC_HEADERS}
|
||||
hid.c
|
||||
)
|
||||
target_link_libraries(hidapi_libusb PUBLIC hidapi_include)
|
||||
|
||||
if(TARGET usb-1.0)
|
||||
target_link_libraries(hidapi_libusb PRIVATE usb-1.0)
|
||||
else()
|
||||
include(FindPkgConfig)
|
||||
pkg_check_modules(libusb REQUIRED IMPORTED_TARGET libusb-1.0>=1.0.9)
|
||||
target_link_libraries(hidapi_libusb PRIVATE PkgConfig::libusb)
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(hidapi_libusb PRIVATE Threads::Threads)
|
||||
|
||||
if(HIDAPI_NO_ICONV)
|
||||
target_compile_definitions(hidapi_libusb PRIVATE NO_ICONV)
|
||||
else()
|
||||
if(NOT ANDROID)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.11)
|
||||
message(STATUS "Check for Iconv")
|
||||
find_package(Iconv)
|
||||
if(Iconv_FOUND)
|
||||
if(NOT Iconv_IS_BUILT_IN)
|
||||
target_link_libraries(hidapi_libusb PRIVATE Iconv::Iconv)
|
||||
set(CMAKE_REQUIRED_LIBRARIES "Iconv::Iconv")
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
set(HIDAPI_NEED_EXPORT_ICONV TRUE PARENT_SCOPE)
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Iconv Explicitly check '-liconv'")
|
||||
# Sometime the build environment is not setup
|
||||
# in a way CMake can find Iconv on its own by default.
|
||||
# But if we simply link against iconv (-liconv), the build may succeed
|
||||
# due to other compiler/link flags.
|
||||
set(CMAKE_REQUIRED_LIBRARIES "iconv")
|
||||
check_c_source_compiles("
|
||||
#include <stddef.h>
|
||||
#include <iconv.h>
|
||||
int main() {
|
||||
char *a, *b;
|
||||
size_t i, j;
|
||||
iconv_t ic;
|
||||
ic = iconv_open(\"to\", \"from\");
|
||||
iconv(ic, &a, &i, &b, &j);
|
||||
iconv_close(ic);
|
||||
}
|
||||
"
|
||||
Iconv_EXPLICITLY_AT_ENV)
|
||||
if(Iconv_EXPLICITLY_AT_ENV)
|
||||
message(STATUS "Iconv Explicitly check '-liconv' - Available")
|
||||
target_link_libraries(hidapi_libusb PRIVATE iconv)
|
||||
else()
|
||||
message(FATAL_ERROR "Iconv is not found, make sure to provide it in the build environment")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
# otherwise there is 2 options:
|
||||
# 1) iconv is provided by Standard C library and the build will be just fine
|
||||
# 2) The _user_ has to provide additional compilation options for this project/target
|
||||
endif()
|
||||
|
||||
# check for error: "conflicting types for 'iconv'"
|
||||
check_c_source_compiles("#include<iconv.h>
|
||||
extern size_t iconv (iconv_t cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
|
||||
int main() {}"
|
||||
HIDAPI_ICONV_CONST)
|
||||
if(HIDAPI_ICONV_CONST)
|
||||
target_compile_definitions(hidapi_libusb PRIVATE "ICONV_CONST=const")
|
||||
endif()
|
||||
else()
|
||||
# On Android Iconv is disabled on the code level anyway, so no issue;
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_target_properties(hidapi_libusb
|
||||
PROPERTIES
|
||||
EXPORT_NAME "libusb"
|
||||
OUTPUT_NAME "hidapi-libusb"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
PUBLIC_HEADER "${HIDAPI_PUBLIC_HEADERS}"
|
||||
)
|
||||
|
||||
# compatibility with find_package()
|
||||
add_library(hidapi::libusb ALIAS hidapi_libusb)
|
||||
# compatibility with raw library link
|
||||
add_library(hidapi-libusb ALIAS hidapi_libusb)
|
||||
|
||||
if(HIDAPI_INSTALL_TARGETS)
|
||||
install(TARGETS hidapi_libusb EXPORT hidapi
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/hidapi"
|
||||
)
|
||||
endif()
|
||||
|
||||
hidapi_configure_pc("${PROJECT_ROOT}/pc/hidapi-libusb.pc.in")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,56 @@
|
||||
/*******************************************************
|
||||
HIDAPI - Multi-Platform library for
|
||||
communication with HID devices.
|
||||
|
||||
libusb/hidapi Team
|
||||
|
||||
Copyright 2021, All Rights Reserved.
|
||||
|
||||
At the discretion of the user of this library,
|
||||
this software may be licensed under the terms of the
|
||||
GNU General Public License v3, a BSD-Style license, or the
|
||||
original HIDAPI license as outlined in the LICENSE.txt,
|
||||
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
|
||||
files located at the root of the source distribution.
|
||||
These files may also be found in the public source
|
||||
code repository located at:
|
||||
https://github.com/libusb/hidapi .
|
||||
********************************************************/
|
||||
|
||||
/** @file
|
||||
* @defgroup API hidapi API
|
||||
|
||||
* Since version 0.11.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 11, 0).
|
||||
*/
|
||||
|
||||
#ifndef HIDAPI_LIBUSB_H__
|
||||
#define HIDAPI_LIBUSB_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../hidapi/hidapi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Open a HID device using libusb_wrap_sys_device.
|
||||
See https://libusb.sourceforge.io/api-1.0/group__libusb__dev.html#ga98f783e115ceff4eaf88a60e6439563c,
|
||||
for details on libusb_wrap_sys_device.
|
||||
|
||||
@ingroup API
|
||||
@param sys_dev Platform-specific file descriptor that can be recognised by libusb.
|
||||
@param interface_num USB interface number of the device to be used as HID interface.
|
||||
Pass -1 to select first HID interface of the device.
|
||||
|
||||
@returns
|
||||
This function returns a pointer to a #hid_device object on
|
||||
success or NULL on failure.
|
||||
*/
|
||||
HID_API_EXPORT hid_device * HID_API_CALL hid_libusb_wrap_sys_device(intptr_t sys_dev, int interface_num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,174 @@
|
||||
/*******************************************************
|
||||
HIDAPI - Multi-Platform library for
|
||||
communication with HID devices.
|
||||
|
||||
Alan Ott
|
||||
Signal 11 Software
|
||||
|
||||
libusb/hidapi Team
|
||||
|
||||
Sam Lantinga
|
||||
|
||||
Copyright 2023, All Rights Reserved.
|
||||
|
||||
At the discretion of the user of this library,
|
||||
this software may be licensed under the terms of the
|
||||
GNU General Public License v3, a BSD-Style license, or the
|
||||
original HIDAPI license as outlined in the LICENSE.txt,
|
||||
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
|
||||
files located at the root of the source distribution.
|
||||
These files may also be found in the public source
|
||||
code repository located at:
|
||||
https://github.com/libusb/hidapi .
|
||||
********************************************************/
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#if defined(__ANDROID__) && __ANDROID_API__ < __ANDROID_API_N__
|
||||
|
||||
/* Barrier implementation because Android/Bionic don't have pthread_barrier.
|
||||
This implementation came from Brent Priddy and was posted on
|
||||
StackOverflow. It is used with his permission. */
|
||||
typedef int pthread_barrierattr_t;
|
||||
typedef struct pthread_barrier {
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
int count;
|
||||
int trip_count;
|
||||
} pthread_barrier_t;
|
||||
|
||||
static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
|
||||
{
|
||||
if(count == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pthread_mutex_init(&barrier->mutex, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(pthread_cond_init(&barrier->cond, 0) < 0) {
|
||||
pthread_mutex_destroy(&barrier->mutex);
|
||||
return -1;
|
||||
}
|
||||
barrier->trip_count = count;
|
||||
barrier->count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pthread_barrier_destroy(pthread_barrier_t *barrier)
|
||||
{
|
||||
pthread_cond_destroy(&barrier->cond);
|
||||
pthread_mutex_destroy(&barrier->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pthread_barrier_wait(pthread_barrier_t *barrier)
|
||||
{
|
||||
pthread_mutex_lock(&barrier->mutex);
|
||||
++(barrier->count);
|
||||
if(barrier->count >= barrier->trip_count) {
|
||||
barrier->count = 0;
|
||||
pthread_cond_broadcast(&barrier->cond);
|
||||
pthread_mutex_unlock(&barrier->mutex);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
pthread_cond_wait(&barrier->cond, &(barrier->mutex));
|
||||
pthread_mutex_unlock(&barrier->mutex);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define HIDAPI_THREAD_TIMED_OUT ETIMEDOUT
|
||||
|
||||
typedef struct timespec hidapi_timespec;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
pthread_t thread;
|
||||
pthread_mutex_t mutex; /* Protects input_reports */
|
||||
pthread_cond_t condition;
|
||||
pthread_barrier_t barrier; /* Ensures correct startup sequence */
|
||||
|
||||
} hidapi_thread_state;
|
||||
|
||||
static void hidapi_thread_state_init(hidapi_thread_state *state)
|
||||
{
|
||||
pthread_mutex_init(&state->mutex, NULL);
|
||||
pthread_cond_init(&state->condition, NULL);
|
||||
pthread_barrier_init(&state->barrier, NULL, 2);
|
||||
}
|
||||
|
||||
static void hidapi_thread_state_destroy(hidapi_thread_state *state)
|
||||
{
|
||||
pthread_barrier_destroy(&state->barrier);
|
||||
pthread_cond_destroy(&state->condition);
|
||||
pthread_mutex_destroy(&state->mutex);
|
||||
}
|
||||
|
||||
#define hidapi_thread_cleanup_push pthread_cleanup_push
|
||||
#define hidapi_thread_cleanup_pop pthread_cleanup_pop
|
||||
|
||||
static void hidapi_thread_mutex_lock(hidapi_thread_state *state)
|
||||
{
|
||||
pthread_mutex_lock(&state->mutex);
|
||||
}
|
||||
|
||||
static void hidapi_thread_mutex_unlock(hidapi_thread_state *state)
|
||||
{
|
||||
pthread_mutex_unlock(&state->mutex);
|
||||
}
|
||||
|
||||
static void hidapi_thread_cond_wait(hidapi_thread_state *state)
|
||||
{
|
||||
pthread_cond_wait(&state->condition, &state->mutex);
|
||||
}
|
||||
|
||||
static int hidapi_thread_cond_timedwait(hidapi_thread_state *state, hidapi_timespec *ts)
|
||||
{
|
||||
return pthread_cond_timedwait(&state->condition, &state->mutex, ts);
|
||||
}
|
||||
|
||||
static void hidapi_thread_cond_signal(hidapi_thread_state *state)
|
||||
{
|
||||
pthread_cond_signal(&state->condition);
|
||||
}
|
||||
|
||||
static void hidapi_thread_cond_broadcast(hidapi_thread_state *state)
|
||||
{
|
||||
pthread_cond_broadcast(&state->condition);
|
||||
}
|
||||
|
||||
static void hidapi_thread_barrier_wait(hidapi_thread_state *state)
|
||||
{
|
||||
pthread_barrier_wait(&state->barrier);
|
||||
}
|
||||
|
||||
static void hidapi_thread_create(hidapi_thread_state *state, void *(*func)(void*), void *func_arg)
|
||||
{
|
||||
pthread_create(&state->thread, NULL, func, func_arg);
|
||||
}
|
||||
|
||||
static void hidapi_thread_join(hidapi_thread_state *state)
|
||||
{
|
||||
pthread_join(state->thread, NULL);
|
||||
}
|
||||
|
||||
static void hidapi_thread_gettime(hidapi_timespec *ts)
|
||||
{
|
||||
clock_gettime(CLOCK_REALTIME, ts);
|
||||
}
|
||||
|
||||
static void hidapi_thread_addtime(hidapi_timespec *ts, int milliseconds)
|
||||
{
|
||||
ts->tv_sec += milliseconds / 1000;
|
||||
ts->tv_nsec += (milliseconds % 1000) * 1000000;
|
||||
if (ts->tv_nsec >= 1000000000L) {
|
||||
ts->tv_sec++;
|
||||
ts->tv_nsec -= 1000000000L;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/* Barrier implementation because Android/Bionic don't have pthread_barrier.
|
||||
This implementation came from Brent Priddy and was posted on
|
||||
StackOverflow. It is used with his permission. */
|
||||
|
||||
typedef struct _SDL_ThreadBarrier
|
||||
{
|
||||
SDL_Mutex *mutex;
|
||||
SDL_Condition *cond;
|
||||
Uint32 count;
|
||||
Uint32 trip_count;
|
||||
} SDL_ThreadBarrier;
|
||||
|
||||
static int SDL_CreateThreadBarrier(SDL_ThreadBarrier *barrier, Uint32 count)
|
||||
{
|
||||
SDL_assert(barrier != NULL);
|
||||
SDL_assert(count != 0);
|
||||
|
||||
barrier->mutex = SDL_CreateMutex();
|
||||
if (barrier->mutex == NULL) {
|
||||
return -1; /* Error set by CreateMutex */
|
||||
}
|
||||
barrier->cond = SDL_CreateCondition();
|
||||
if (barrier->cond == NULL) {
|
||||
return -1; /* Error set by CreateCond */
|
||||
}
|
||||
|
||||
barrier->trip_count = count;
|
||||
barrier->count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void SDL_DestroyThreadBarrier(SDL_ThreadBarrier *barrier)
|
||||
{
|
||||
SDL_DestroyCondition(barrier->cond);
|
||||
SDL_DestroyMutex(barrier->mutex);
|
||||
}
|
||||
|
||||
static int SDL_WaitThreadBarrier(SDL_ThreadBarrier *barrier)
|
||||
{
|
||||
SDL_LockMutex(barrier->mutex);
|
||||
barrier->count += 1;
|
||||
if (barrier->count >= barrier->trip_count) {
|
||||
barrier->count = 0;
|
||||
SDL_BroadcastCondition(barrier->cond);
|
||||
SDL_UnlockMutex(barrier->mutex);
|
||||
return 1;
|
||||
}
|
||||
SDL_WaitCondition(barrier->cond, barrier->mutex);
|
||||
SDL_UnlockMutex(barrier->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "../../thread/SDL_systhread.h"
|
||||
|
||||
#define HIDAPI_THREAD_TIMED_OUT 1
|
||||
|
||||
typedef Uint64 hidapi_timespec;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SDL_Thread *thread;
|
||||
SDL_Mutex *mutex; /* Protects input_reports */
|
||||
SDL_Condition *condition;
|
||||
SDL_ThreadBarrier barrier; /* Ensures correct startup sequence */
|
||||
|
||||
} hidapi_thread_state;
|
||||
|
||||
static void hidapi_thread_state_init(hidapi_thread_state *state)
|
||||
{
|
||||
state->mutex = SDL_CreateMutex();
|
||||
state->condition = SDL_CreateCondition();
|
||||
SDL_CreateThreadBarrier(&state->barrier, 2);
|
||||
}
|
||||
|
||||
static void hidapi_thread_state_destroy(hidapi_thread_state *state)
|
||||
{
|
||||
SDL_DestroyThreadBarrier(&state->barrier);
|
||||
SDL_DestroyCondition(state->condition);
|
||||
SDL_DestroyMutex(state->mutex);
|
||||
}
|
||||
|
||||
static void hidapi_thread_cleanup_push(void (*routine)(void *), void *arg)
|
||||
{
|
||||
/* There isn't an equivalent in SDL, and it's only useful for threads calling hid_read_timeout() */
|
||||
}
|
||||
|
||||
static void hidapi_thread_cleanup_pop(int execute)
|
||||
{
|
||||
}
|
||||
|
||||
static void hidapi_thread_mutex_lock(hidapi_thread_state *state)
|
||||
{
|
||||
SDL_LockMutex(state->mutex);
|
||||
}
|
||||
|
||||
static void hidapi_thread_mutex_unlock(hidapi_thread_state *state)
|
||||
{
|
||||
SDL_UnlockMutex(state->mutex);
|
||||
}
|
||||
|
||||
static void hidapi_thread_cond_wait(hidapi_thread_state *state)
|
||||
{
|
||||
SDL_WaitCondition(state->condition, state->mutex);
|
||||
}
|
||||
|
||||
static int hidapi_thread_cond_timedwait(hidapi_thread_state *state, hidapi_timespec *ts)
|
||||
{
|
||||
Sint64 timeout_ns;
|
||||
Sint32 timeout_ms;
|
||||
|
||||
timeout_ns = (Sint64)(*ts - SDL_GetTicksNS());
|
||||
if (timeout_ns <= 0) {
|
||||
timeout_ms = 0;
|
||||
} else {
|
||||
timeout_ms = (Sint32)SDL_NS_TO_MS(timeout_ns);
|
||||
}
|
||||
if (SDL_WaitConditionTimeout(state->condition, state->mutex, timeout_ms)) {
|
||||
return 0;
|
||||
} else {
|
||||
return HIDAPI_THREAD_TIMED_OUT;
|
||||
}
|
||||
}
|
||||
|
||||
static void hidapi_thread_cond_signal(hidapi_thread_state *state)
|
||||
{
|
||||
SDL_SignalCondition(state->condition);
|
||||
}
|
||||
|
||||
static void hidapi_thread_cond_broadcast(hidapi_thread_state *state)
|
||||
{
|
||||
SDL_BroadcastCondition(state->condition);
|
||||
}
|
||||
|
||||
static void hidapi_thread_barrier_wait(hidapi_thread_state *state)
|
||||
{
|
||||
SDL_WaitThreadBarrier(&state->barrier);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *(*func)(void*);
|
||||
void *func_arg;
|
||||
|
||||
} RunInputThreadParam;
|
||||
|
||||
static int RunInputThread(void *param)
|
||||
{
|
||||
RunInputThreadParam *data = (RunInputThreadParam *)param;
|
||||
void *(*func)(void*) = data->func;
|
||||
void *func_arg = data->func_arg;
|
||||
SDL_free(data);
|
||||
func(func_arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hidapi_thread_create(hidapi_thread_state *state, void *(*func)(void*), void *func_arg)
|
||||
{
|
||||
RunInputThreadParam *param = (RunInputThreadParam *)malloc(sizeof(*param));
|
||||
/* Note that the hidapi code didn't check for thread creation failure.
|
||||
* We'll crash if malloc() fails
|
||||
*/
|
||||
param->func = func;
|
||||
param->func_arg = func_arg;
|
||||
state->thread = SDL_CreateThread(RunInputThread, "libusb", param);
|
||||
}
|
||||
|
||||
static void hidapi_thread_join(hidapi_thread_state *state)
|
||||
{
|
||||
SDL_WaitThread(state->thread, NULL);
|
||||
}
|
||||
|
||||
static void hidapi_thread_gettime(hidapi_timespec *ts)
|
||||
{
|
||||
*ts = SDL_GetTicksNS();
|
||||
}
|
||||
|
||||
static void hidapi_thread_addtime(hidapi_timespec *ts, int milliseconds)
|
||||
{
|
||||
*ts += SDL_MS_TO_NS(milliseconds);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
cmake_minimum_required(VERSION 3.6.3...3.25 FATAL_ERROR)
|
||||
|
||||
add_library(hidapi_hidraw
|
||||
${HIDAPI_PUBLIC_HEADERS}
|
||||
hid.c
|
||||
)
|
||||
target_link_libraries(hidapi_hidraw PUBLIC hidapi_include)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
include(FindPkgConfig)
|
||||
pkg_check_modules(libudev REQUIRED IMPORTED_TARGET libudev)
|
||||
|
||||
target_link_libraries(hidapi_hidraw PRIVATE PkgConfig::libudev Threads::Threads)
|
||||
|
||||
set_target_properties(hidapi_hidraw
|
||||
PROPERTIES
|
||||
EXPORT_NAME "hidraw"
|
||||
OUTPUT_NAME "hidapi-hidraw"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
PUBLIC_HEADER "${HIDAPI_PUBLIC_HEADERS}"
|
||||
)
|
||||
|
||||
# compatibility with find_package()
|
||||
add_library(hidapi::hidraw ALIAS hidapi_hidraw)
|
||||
# compatibility with raw library link
|
||||
add_library(hidapi-hidraw ALIAS hidapi_hidraw)
|
||||
|
||||
if(HIDAPI_INSTALL_TARGETS)
|
||||
install(TARGETS hidapi_hidraw EXPORT hidapi
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/hidapi"
|
||||
)
|
||||
endif()
|
||||
|
||||
hidapi_configure_pc("${PROJECT_ROOT}/pc/hidapi-hidraw.pc.in")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,48 @@
|
||||
cmake_minimum_required(VERSION 3.4.3...3.25 FATAL_ERROR)
|
||||
|
||||
list(APPEND HIDAPI_PUBLIC_HEADERS "hidapi_darwin.h")
|
||||
|
||||
add_library(hidapi_darwin
|
||||
${HIDAPI_PUBLIC_HEADERS}
|
||||
hid.c
|
||||
)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
target_link_libraries(hidapi_darwin
|
||||
PUBLIC hidapi_include
|
||||
PRIVATE Threads::Threads
|
||||
PRIVATE "-framework IOKit" "-framework CoreFoundation"
|
||||
)
|
||||
|
||||
set_target_properties(hidapi_darwin
|
||||
PROPERTIES
|
||||
EXPORT_NAME "darwin"
|
||||
OUTPUT_NAME "hidapi"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
MACHO_COMPATIBILITY_VERSION ${PROJECT_VERSION_MAJOR}
|
||||
FRAMEWORK_VERSION ${PROJECT_VERSION_MAJOR}
|
||||
PUBLIC_HEADER "${HIDAPI_PUBLIC_HEADERS}"
|
||||
)
|
||||
|
||||
# compatibility with find_package()
|
||||
add_library(hidapi::darwin ALIAS hidapi_darwin)
|
||||
# compatibility with raw library link
|
||||
add_library(hidapi ALIAS hidapi_darwin)
|
||||
|
||||
set(PUBLIC_HEADER_DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
if(NOT CMAKE_FRAMEWORK)
|
||||
set(PUBLIC_HEADER_DESTINATION "${PUBLIC_HEADER_DESTINATION}/hidapi")
|
||||
endif()
|
||||
|
||||
if(HIDAPI_INSTALL_TARGETS)
|
||||
install(TARGETS hidapi_darwin EXPORT hidapi
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
FRAMEWORK DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
PUBLIC_HEADER DESTINATION "${PUBLIC_HEADER_DESTINATION}"
|
||||
)
|
||||
endif()
|
||||
|
||||
hidapi_configure_pc("${PROJECT_ROOT}/pc/hidapi.pc.in")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,98 @@
|
||||
/*******************************************************
|
||||
HIDAPI - Multi-Platform library for
|
||||
communication with HID devices.
|
||||
|
||||
libusb/hidapi Team
|
||||
|
||||
Copyright 2022, All Rights Reserved.
|
||||
|
||||
At the discretion of the user of this library,
|
||||
this software may be licensed under the terms of the
|
||||
GNU General Public License v3, a BSD-Style license, or the
|
||||
original HIDAPI license as outlined in the LICENSE.txt,
|
||||
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
|
||||
files located at the root of the source distribution.
|
||||
These files may also be found in the public source
|
||||
code repository located at:
|
||||
https://github.com/libusb/hidapi .
|
||||
********************************************************/
|
||||
|
||||
/** @file
|
||||
* @defgroup API hidapi API
|
||||
|
||||
* Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
|
||||
*/
|
||||
|
||||
#ifndef HIDAPI_DARWIN_H__
|
||||
#define HIDAPI_DARWIN_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "../hidapi/hidapi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Get the location ID for a HID device.
|
||||
|
||||
Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param location_id The device's location ID on return.
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT_CALL hid_darwin_get_location_id(hid_device *dev, uint32_t *location_id);
|
||||
|
||||
|
||||
/** @brief Changes the behavior of all further calls to @ref hid_open or @ref hid_open_path.
|
||||
|
||||
By default on Darwin platform all devices opened by HIDAPI with @ref hid_open or @ref hid_open_path
|
||||
are opened in exclusive mode (see kIOHIDOptionsTypeSeizeDevice).
|
||||
|
||||
Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
|
||||
|
||||
@ingroup API
|
||||
@param open_exclusive When set to 0 - all further devices will be opened
|
||||
in non-exclusive mode. Otherwise - all further devices will be opened
|
||||
in exclusive mode.
|
||||
|
||||
@note During the initialisation by @ref hid_init - this property is set to 1 (TRUE).
|
||||
This is done to preserve full backward compatibility with previous behavior.
|
||||
|
||||
@note Calling this function before @ref hid_init or after @ref hid_exit has no effect.
|
||||
*/
|
||||
void HID_API_EXPORT_CALL hid_darwin_set_open_exclusive(int open_exclusive);
|
||||
|
||||
/** @brief Getter for option set by @ref hid_darwin_set_open_exclusive.
|
||||
|
||||
Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
|
||||
|
||||
@ingroup API
|
||||
@return 1 if all further devices will be opened in exclusive mode.
|
||||
|
||||
@note Value returned by this function before calling to @ref hid_init or after @ref hid_exit
|
||||
is not reliable.
|
||||
*/
|
||||
int HID_API_EXPORT_CALL hid_darwin_get_open_exclusive(void);
|
||||
|
||||
/** @brief Check how the device was opened.
|
||||
|
||||
Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
|
||||
|
||||
@ingroup API
|
||||
@param dev A device to get property from.
|
||||
|
||||
@return 1 if the device is opened in exclusive mode, 0 - opened in non-exclusive,
|
||||
-1 - if dev is invalid.
|
||||
*/
|
||||
int HID_API_EXPORT_CALL hid_darwin_is_device_open_exclusive(hid_device *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
cmake_minimum_required(VERSION 3.6.3...3.25 FATAL_ERROR)
|
||||
|
||||
add_library(hidapi_netbsd
|
||||
${HIDAPI_PUBLIC_HEADERS}
|
||||
hid.c
|
||||
)
|
||||
target_link_libraries(hidapi_netbsd PUBLIC hidapi_include)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
target_link_libraries(hidapi_netbsd PRIVATE Threads::Threads)
|
||||
|
||||
set_target_properties(hidapi_netbsd
|
||||
PROPERTIES
|
||||
EXPORT_NAME "netbsd"
|
||||
OUTPUT_NAME "hidapi-netbsd"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
PUBLIC_HEADER "${HIDAPI_PUBLIC_HEADERS}"
|
||||
)
|
||||
|
||||
# compatibility with find_package()
|
||||
add_library(hidapi::netbsd ALIAS hidapi_netbsd)
|
||||
# compatibility with raw library link
|
||||
add_library(hidapi-netbsd ALIAS hidapi_netbsd)
|
||||
|
||||
if(HIDAPI_INSTALL_TARGETS)
|
||||
install(TARGETS hidapi_netbsd EXPORT hidapi
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/hidapi"
|
||||
)
|
||||
endif()
|
||||
|
||||
hidapi_configure_pc("${PROJECT_ROOT}/pc/hidapi-netbsd.pc.in")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,206 @@
|
||||
get_filename_component(PROJECT_ROOT "${CMAKE_CURRENT_LIST_DIR}/.." ABSOLUTE)
|
||||
|
||||
# Read version from file
|
||||
file(READ "${PROJECT_ROOT}/VERSION" RAW_VERSION_STR)
|
||||
string(REGEX MATCH "^([0-9]+\\.[0-9]+\\.[0-9]+)(.*)" VERSION_STR "${RAW_VERSION_STR}")
|
||||
|
||||
if(NOT VERSION_STR)
|
||||
message(FATAL_ERROR "Broken VERSION file, couldn't parse '${PROJECT_ROOT}/VERSION' with content: '${RAW_VERSION_STR}'")
|
||||
endif()
|
||||
|
||||
set(VERSION "${CMAKE_MATCH_1}")
|
||||
string(STRIP "${CMAKE_MATCH_2}" VERSION_SUFFIX)
|
||||
# compatibility with find_package() vs add_subdirectory
|
||||
set(hidapi_VERSION "${VERSION}" PARENT_SCOPE)
|
||||
#
|
||||
|
||||
if(DEFINED HIDAPI_PRINT_VERSION AND HIDAPI_PRINT_VERSION)
|
||||
set(HIDAPI_PRINT_VERSION "hidapi: v${VERSION}")
|
||||
if(VERSION_SUFFIX)
|
||||
set(HIDAPI_PRINT_VERSION "${HIDAPI_PRINT_VERSION} (${VERSION_SUFFIX})")
|
||||
endif()
|
||||
message(STATUS "${HIDAPI_PRINT_VERSION}")
|
||||
endif()
|
||||
|
||||
project(hidapi VERSION "${VERSION}" LANGUAGES C)
|
||||
|
||||
# Defaults and required options
|
||||
|
||||
if(NOT DEFINED HIDAPI_WITH_TESTS)
|
||||
set(HIDAPI_WITH_TESTS OFF)
|
||||
endif()
|
||||
if(NOT DEFINED BUILD_SHARED_LIBS)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif()
|
||||
if(NOT DEFINED HIDAPI_INSTALL_TARGETS)
|
||||
set(HIDAPI_INSTALL_TARGETS OFF)
|
||||
endif()
|
||||
if(NOT DEFINED CMAKE_POSITION_INDEPENDENT_CODE)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
get_directory_property(IS_EXCLUDE_FROM_ALL EXCLUDE_FROM_ALL)
|
||||
if(IS_EXCLUDE_FROM_ALL)
|
||||
if(HIDAPI_INSTALL_TARGETS)
|
||||
message(WARNING "Installing EXCLUDE_FROM_ALL targets in an undefined behavior in CMake.\nDon't add 'hidapi' sundirectory with 'EXCLUDE_FROM_ALL' property, or don't set 'HIDAPI_INSTALL_TARGETS' to TRUE.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Helper(s)
|
||||
|
||||
function(hidapi_configure_pc PC_IN_FILE)
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/pc")
|
||||
|
||||
set(VERSION "${VERSION}${VERSION_SUFFIX}")
|
||||
set(prefix "${CMAKE_INSTALL_PREFIX}")
|
||||
set(exec_prefix "\${prefix}")
|
||||
if(IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}")
|
||||
set(libdir "${CMAKE_INSTALL_LIBDIR}")
|
||||
else()
|
||||
set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
if(IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
set(includedir "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
else()
|
||||
set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
endif()
|
||||
|
||||
get_filename_component(PC_IN_FILENAME "${PC_IN_FILE}" NAME_WE)
|
||||
set(PC_FILE "${CMAKE_CURRENT_BINARY_DIR}/pc/${PC_IN_FILENAME}.pc")
|
||||
configure_file("${PC_IN_FILE}" "${PC_FILE}" @ONLY)
|
||||
if(HIDAPI_INSTALL_TARGETS)
|
||||
install(FILES "${PC_FILE}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig/")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# The library
|
||||
|
||||
if(HIDAPI_INSTALL_TARGETS)
|
||||
include(GNUInstallDirs)
|
||||
endif()
|
||||
|
||||
add_library(hidapi_include INTERFACE)
|
||||
target_include_directories(hidapi_include INTERFACE
|
||||
"$<BUILD_INTERFACE:${PROJECT_ROOT}/hidapi>"
|
||||
)
|
||||
if(APPLE AND CMAKE_FRAMEWORK)
|
||||
# FIXME: https://github.com/libusb/hidapi/issues/492: it is untrivial to set the include path for Framework correctly
|
||||
else()
|
||||
target_include_directories(hidapi_include INTERFACE
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/hidapi>"
|
||||
)
|
||||
endif()
|
||||
set_target_properties(hidapi_include PROPERTIES EXPORT_NAME "include")
|
||||
set(HIDAPI_PUBLIC_HEADERS "${PROJECT_ROOT}/hidapi/hidapi.h")
|
||||
|
||||
add_library(hidapi::include ALIAS hidapi_include)
|
||||
|
||||
if(HIDAPI_INSTALL_TARGETS)
|
||||
install(TARGETS hidapi_include EXPORT hidapi)
|
||||
endif()
|
||||
|
||||
set(EXPORT_ALIAS)
|
||||
set(EXPORT_COMPONENTS)
|
||||
|
||||
set(HIDAPI_NEED_EXPORT_THREADS FALSE)
|
||||
set(HIDAPI_NEED_EXPORT_LIBUSB FALSE)
|
||||
set(HIDAPI_NEED_EXPORT_LIBUDEV FALSE)
|
||||
set(HIDAPI_NEED_EXPORT_ICONV FALSE)
|
||||
|
||||
if(WIN32)
|
||||
target_include_directories(hidapi_include INTERFACE
|
||||
"$<BUILD_INTERFACE:${PROJECT_ROOT}/windows>"
|
||||
)
|
||||
add_subdirectory("${PROJECT_ROOT}/windows" windows)
|
||||
set(EXPORT_ALIAS winapi)
|
||||
list(APPEND EXPORT_COMPONENTS winapi)
|
||||
elseif(APPLE)
|
||||
target_include_directories(hidapi_include INTERFACE
|
||||
"$<BUILD_INTERFACE:${PROJECT_ROOT}/mac>"
|
||||
)
|
||||
add_subdirectory("${PROJECT_ROOT}/mac" mac)
|
||||
set(EXPORT_ALIAS darwin)
|
||||
list(APPEND EXPORT_COMPONENTS darwin)
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
set(HIDAPI_NEED_EXPORT_THREADS TRUE)
|
||||
endif()
|
||||
else()
|
||||
if(NOT DEFINED HIDAPI_WITH_LIBUSB)
|
||||
set(HIDAPI_WITH_LIBUSB ON)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
if(NOT DEFINED HIDAPI_WITH_HIDRAW)
|
||||
set(HIDAPI_WITH_HIDRAW ON)
|
||||
endif()
|
||||
if(HIDAPI_WITH_HIDRAW)
|
||||
add_subdirectory("${PROJECT_ROOT}/linux" linux)
|
||||
list(APPEND EXPORT_COMPONENTS hidraw)
|
||||
set(EXPORT_ALIAS hidraw)
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
set(HIDAPI_NEED_EXPORT_THREADS TRUE)
|
||||
set(HIDAPI_NEED_EXPORT_LIBUDEV TRUE)
|
||||
endif()
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_NAME MATCHES "NetBSD")
|
||||
if(NOT DEFINED HIDAPI_WITH_NETBSD)
|
||||
set(HIDAPI_WITH_NETBSD ON)
|
||||
endif()
|
||||
if(HIDAPI_WITH_NETBSD)
|
||||
add_subdirectory("${PROJECT_ROOT}/netbsd" netbsd)
|
||||
list(APPEND EXPORT_COMPONENTS netbsd)
|
||||
set(EXPORT_ALIAS netbsd)
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
set(HIDAPI_NEED_EXPORT_THREADS TRUE)
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
set(HIDAPI_WITH_LIBUSB ON)
|
||||
endif()
|
||||
if(HIDAPI_WITH_LIBUSB)
|
||||
target_include_directories(hidapi_include INTERFACE
|
||||
"$<BUILD_INTERFACE:${PROJECT_ROOT}/libusb>"
|
||||
)
|
||||
if(NOT DEFINED HIDAPI_NO_ICONV)
|
||||
set(HIDAPI_NO_ICONV OFF)
|
||||
endif()
|
||||
add_subdirectory("${PROJECT_ROOT}/libusb" libusb)
|
||||
list(APPEND EXPORT_COMPONENTS libusb)
|
||||
if(NOT EXPORT_ALIAS)
|
||||
set(EXPORT_ALIAS libusb)
|
||||
endif()
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
set(HIDAPI_NEED_EXPORT_THREADS TRUE)
|
||||
if(NOT TARGET usb-1.0)
|
||||
set(HIDAPI_NEED_EXPORT_LIBUSB TRUE)
|
||||
endif()
|
||||
endif()
|
||||
elseif(NOT TARGET hidapi_hidraw)
|
||||
message(FATAL_ERROR "Select at least one option to build: HIDAPI_WITH_LIBUSB or HIDAPI_WITH_HIDRAW")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(hidapi::hidapi ALIAS hidapi_${EXPORT_ALIAS})
|
||||
|
||||
if(HIDAPI_INSTALL_TARGETS)
|
||||
include(CMakePackageConfigHelpers)
|
||||
set(EXPORT_DENERATED_LOCATION "${CMAKE_BINARY_DIR}/export_generated")
|
||||
set(EXPORT_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/hidapi")
|
||||
write_basic_package_version_file("${EXPORT_DENERATED_LOCATION}/hidapi-config-version.cmake"
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
configure_package_config_file("cmake/hidapi-config.cmake.in" "${EXPORT_DENERATED_LOCATION}/hidapi-config.cmake"
|
||||
INSTALL_DESTINATION "${EXPORT_DESTINATION}"
|
||||
NO_SET_AND_CHECK_MACRO
|
||||
)
|
||||
|
||||
install(EXPORT hidapi
|
||||
DESTINATION "${EXPORT_DESTINATION}"
|
||||
NAMESPACE hidapi::
|
||||
FILE "libhidapi.cmake"
|
||||
)
|
||||
install(FILES
|
||||
"${EXPORT_DENERATED_LOCATION}/hidapi-config-version.cmake"
|
||||
"${EXPORT_DENERATED_LOCATION}/hidapi-config.cmake"
|
||||
DESTINATION "${EXPORT_DESTINATION}"
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,10 @@
|
||||
cmake_minimum_required(VERSION 3.1.3...3.25 FATAL_ERROR)
|
||||
project(hidapi LANGUAGES C)
|
||||
|
||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/root")
|
||||
|
||||
foreach(ROOT_ELEMENT CMakeLists.txt hidapi src windows linux mac libusb pc VERSION)
|
||||
file(COPY "${CMAKE_CURRENT_LIST_DIR}/../../${ROOT_ELEMENT}" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/root/")
|
||||
endforeach()
|
||||
|
||||
add_subdirectory("${CMAKE_CURRENT_BINARY_DIR}/root" hidapi_root)
|
||||
@@ -0,0 +1,98 @@
|
||||
#!/bin/bash
|
||||
|
||||
#### Configuration:
|
||||
# The name of the executable. It is assumed
|
||||
# that it is in the current working directory.
|
||||
EXE_NAME=hidapi-testgui
|
||||
# Path to the executable directory inside the bundle.
|
||||
# This must be an absolute path, so use $PWD.
|
||||
EXEPATH=$PWD/TestGUI.app/Contents/MacOS
|
||||
# Libraries to explicitly bundle, even though they
|
||||
# may not be in /opt/local. One per line. These
|
||||
# are used with grep, so only a portion of the name
|
||||
# is required. eg: libFOX, libz, etc.
|
||||
LIBS_TO_BUNDLE=libFOX
|
||||
|
||||
|
||||
function copydeps {
|
||||
local file=$1
|
||||
# echo "Copying deps for $file...."
|
||||
local BASE_OF_EXE=`basename $file`
|
||||
|
||||
# A will contain the dependencies of this library
|
||||
local A=`otool -LX $file |cut -f 1 -d " "`
|
||||
local i
|
||||
for i in $A; do
|
||||
local BASE=`basename $i`
|
||||
|
||||
# See if it's a lib we specifically want to bundle
|
||||
local bundle_this_lib=0
|
||||
local j
|
||||
for j in $LIBS_TO_BUNDLE; do
|
||||
echo $i |grep -q $j
|
||||
if [ $? -eq 0 ]; then
|
||||
bundle_this_lib=1
|
||||
echo "bundling $i because it's in the list."
|
||||
break;
|
||||
fi
|
||||
done
|
||||
|
||||
# See if it's in /opt/local. Bundle all in /opt/local
|
||||
local isOptLocal=0
|
||||
echo $i |grep -q /opt/local
|
||||
if [ $? -eq 0 ]; then
|
||||
isOptLocal=1
|
||||
echo "bundling $i because it's in /opt/local."
|
||||
fi
|
||||
|
||||
# Bundle the library
|
||||
if [ $isOptLocal -ne 0 ] || [ $bundle_this_lib -ne 0 ]; then
|
||||
|
||||
# Copy the file into the bundle if it exists.
|
||||
if [ -f $EXEPATH/$BASE ]; then
|
||||
z=0
|
||||
else
|
||||
cp $i $EXEPATH
|
||||
chmod 755 $EXEPATH/$BASE
|
||||
fi
|
||||
|
||||
|
||||
# echo "$BASE_OF_EXE depends on $BASE"
|
||||
|
||||
# Fix the paths using install_name_tool and then
|
||||
# call this function recursively for each dependency
|
||||
# of this library.
|
||||
if [ $BASE_OF_EXE != $BASE ]; then
|
||||
|
||||
# Fix the paths
|
||||
install_name_tool -id @executable_path/$BASE $EXEPATH/$BASE
|
||||
install_name_tool -change $i @executable_path/$BASE $EXEPATH/$BASE_OF_EXE
|
||||
|
||||
# Call this function (recursive) on
|
||||
# on each dependency of this library.
|
||||
copydeps $EXEPATH/$BASE
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
rm -f $EXEPATH/*
|
||||
mkdir -p $EXEPATH
|
||||
|
||||
# Copy the binary into the bundle. Use ../libtool to do this if it's
|
||||
# available because if $EXE_NAME was built with autotools, it will be
|
||||
# necessary. If ../libtool not available, just use cp to do the copy, but
|
||||
# only if $EXE_NAME is a binary.
|
||||
if [ -x ../libtool ]; then
|
||||
../libtool --mode=install cp $EXE_NAME $EXEPATH
|
||||
else
|
||||
file -bI $EXE_NAME |grep binary
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "There is no ../libtool and $EXE_NAME is not a binary."
|
||||
echo "I'm not sure what to do."
|
||||
exit 1
|
||||
else
|
||||
cp $EXE_NAME $EXEPATH
|
||||
fi
|
||||
fi
|
||||
copydeps $EXEPATH/$EXE_NAME
|
||||
@@ -0,0 +1,17 @@
|
||||
/*******************************
|
||||
Mac support for HID Test GUI
|
||||
|
||||
Alan Ott
|
||||
Signal 11 Software
|
||||
|
||||
*******************************/
|
||||
|
||||
#ifndef MAC_SUPPORT_H__
|
||||
#define MAC_SUPPORT_H__
|
||||
|
||||
extern "C" {
|
||||
void init_apple_message_system();
|
||||
void check_apple_events();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,532 @@
|
||||
/*******************************************************
|
||||
Demo Program for HIDAPI
|
||||
|
||||
Alan Ott
|
||||
Signal 11 Software
|
||||
|
||||
2010-07-20
|
||||
|
||||
Copyright 2010, All Rights Reserved
|
||||
|
||||
This contents of this file may be used by anyone
|
||||
for any reason without any conditions and may be
|
||||
used as a starting point for your own applications
|
||||
which use HIDAPI.
|
||||
********************************************************/
|
||||
|
||||
|
||||
#include <fx.h>
|
||||
|
||||
#include "hidapi.h"
|
||||
#include "mac_support.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
// Thanks Microsoft, but I know how to use strncpy().
|
||||
#pragma warning(disable:4996)
|
||||
#endif
|
||||
|
||||
class MainWindow : public FXMainWindow {
|
||||
FXDECLARE(MainWindow)
|
||||
|
||||
public:
|
||||
enum {
|
||||
ID_FIRST = FXMainWindow::ID_LAST,
|
||||
ID_CONNECT,
|
||||
ID_DISCONNECT,
|
||||
ID_RESCAN,
|
||||
ID_SEND_OUTPUT_REPORT,
|
||||
ID_SEND_FEATURE_REPORT,
|
||||
ID_GET_FEATURE_REPORT,
|
||||
ID_CLEAR,
|
||||
ID_TIMER,
|
||||
ID_MAC_TIMER,
|
||||
ID_LAST,
|
||||
};
|
||||
|
||||
private:
|
||||
FXList *device_list;
|
||||
FXButton *connect_button;
|
||||
FXButton *disconnect_button;
|
||||
FXButton *rescan_button;
|
||||
FXButton *output_button;
|
||||
FXLabel *connected_label;
|
||||
FXTextField *output_text;
|
||||
FXTextField *output_len;
|
||||
FXButton *feature_button;
|
||||
FXButton *get_feature_button;
|
||||
FXTextField *feature_text;
|
||||
FXTextField *feature_len;
|
||||
FXTextField *get_feature_text;
|
||||
FXText *input_text;
|
||||
FXFont *title_font;
|
||||
|
||||
struct hid_device_info *devices;
|
||||
hid_device *connected_device;
|
||||
size_t getDataFromTextField(FXTextField *tf, char *buf, size_t len);
|
||||
int getLengthFromTextField(FXTextField *tf);
|
||||
|
||||
|
||||
protected:
|
||||
MainWindow() {};
|
||||
public:
|
||||
MainWindow(FXApp *a);
|
||||
~MainWindow();
|
||||
virtual void create();
|
||||
|
||||
long onConnect(FXObject *sender, FXSelector sel, void *ptr);
|
||||
long onDisconnect(FXObject *sender, FXSelector sel, void *ptr);
|
||||
long onRescan(FXObject *sender, FXSelector sel, void *ptr);
|
||||
long onSendOutputReport(FXObject *sender, FXSelector sel, void *ptr);
|
||||
long onSendFeatureReport(FXObject *sender, FXSelector sel, void *ptr);
|
||||
long onGetFeatureReport(FXObject *sender, FXSelector sel, void *ptr);
|
||||
long onClear(FXObject *sender, FXSelector sel, void *ptr);
|
||||
long onTimeout(FXObject *sender, FXSelector sel, void *ptr);
|
||||
long onMacTimeout(FXObject *sender, FXSelector sel, void *ptr);
|
||||
};
|
||||
|
||||
// FOX 1.7 changes the timeouts to all be nanoseconds.
|
||||
// Fox 1.6 had all timeouts as milliseconds.
|
||||
#if (FOX_MINOR >= 7)
|
||||
const int timeout_scalar = 1000*1000;
|
||||
#else
|
||||
const int timeout_scalar = 1;
|
||||
#endif
|
||||
|
||||
FXMainWindow *g_main_window;
|
||||
|
||||
|
||||
FXDEFMAP(MainWindow) MainWindowMap [] = {
|
||||
FXMAPFUNC(SEL_COMMAND, MainWindow::ID_CONNECT, MainWindow::onConnect ),
|
||||
FXMAPFUNC(SEL_COMMAND, MainWindow::ID_DISCONNECT, MainWindow::onDisconnect ),
|
||||
FXMAPFUNC(SEL_COMMAND, MainWindow::ID_RESCAN, MainWindow::onRescan ),
|
||||
FXMAPFUNC(SEL_COMMAND, MainWindow::ID_SEND_OUTPUT_REPORT, MainWindow::onSendOutputReport ),
|
||||
FXMAPFUNC(SEL_COMMAND, MainWindow::ID_SEND_FEATURE_REPORT, MainWindow::onSendFeatureReport ),
|
||||
FXMAPFUNC(SEL_COMMAND, MainWindow::ID_GET_FEATURE_REPORT, MainWindow::onGetFeatureReport ),
|
||||
FXMAPFUNC(SEL_COMMAND, MainWindow::ID_CLEAR, MainWindow::onClear ),
|
||||
FXMAPFUNC(SEL_TIMEOUT, MainWindow::ID_TIMER, MainWindow::onTimeout ),
|
||||
FXMAPFUNC(SEL_TIMEOUT, MainWindow::ID_MAC_TIMER, MainWindow::onMacTimeout ),
|
||||
};
|
||||
|
||||
FXIMPLEMENT(MainWindow, FXMainWindow, MainWindowMap, ARRAYNUMBER(MainWindowMap));
|
||||
|
||||
MainWindow::MainWindow(FXApp *app)
|
||||
: FXMainWindow(app, "HIDAPI Test Application", NULL, NULL, DECOR_ALL, 200,100, 425,700)
|
||||
{
|
||||
devices = NULL;
|
||||
connected_device = NULL;
|
||||
|
||||
FXVerticalFrame *vf = new FXVerticalFrame(this, LAYOUT_FILL_Y|LAYOUT_FILL_X);
|
||||
|
||||
FXLabel *label = new FXLabel(vf, "HIDAPI Test Tool");
|
||||
title_font = new FXFont(getApp(), "Arial", 14, FXFont::Bold);
|
||||
label->setFont(title_font);
|
||||
|
||||
new FXLabel(vf,
|
||||
"Select a device and press Connect.", NULL, JUSTIFY_LEFT);
|
||||
new FXLabel(vf,
|
||||
"Output data bytes can be entered in the Output section, \n"
|
||||
"separated by space, comma or brackets. Data starting with 0x\n"
|
||||
"is treated as hex. Data beginning with a 0 is treated as \n"
|
||||
"octal. All other data is treated as decimal.", NULL, JUSTIFY_LEFT);
|
||||
new FXLabel(vf,
|
||||
"Data received from the device appears in the Input section.",
|
||||
NULL, JUSTIFY_LEFT);
|
||||
new FXLabel(vf,
|
||||
"Optionally, a report length may be specified. Extra bytes are\n"
|
||||
"padded with zeros. If no length is specified, the length is \n"
|
||||
"inferred from the data.",
|
||||
NULL, JUSTIFY_LEFT);
|
||||
new FXLabel(vf, "");
|
||||
|
||||
// Device List and Connect/Disconnect buttons
|
||||
FXHorizontalFrame *hf = new FXHorizontalFrame(vf, LAYOUT_FILL_X);
|
||||
//device_list = new FXList(new FXHorizontalFrame(hf,FRAME_SUNKEN|FRAME_THICK, 0,0,0,0, 0,0,0,0), NULL, 0, LISTBOX_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT, 0,0,300,200);
|
||||
device_list = new FXList(new FXHorizontalFrame(hf,FRAME_SUNKEN|FRAME_THICK|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0), NULL, 0, LISTBOX_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,300,200);
|
||||
FXVerticalFrame *buttonVF = new FXVerticalFrame(hf);
|
||||
connect_button = new FXButton(buttonVF, "Connect", NULL, this, ID_CONNECT, BUTTON_NORMAL|LAYOUT_FILL_X);
|
||||
disconnect_button = new FXButton(buttonVF, "Disconnect", NULL, this, ID_DISCONNECT, BUTTON_NORMAL|LAYOUT_FILL_X);
|
||||
disconnect_button->disable();
|
||||
rescan_button = new FXButton(buttonVF, "Re-Scan devices", NULL, this, ID_RESCAN, BUTTON_NORMAL|LAYOUT_FILL_X);
|
||||
new FXHorizontalFrame(buttonVF, 0, 0,0,0,0, 0,0,50,0);
|
||||
|
||||
connected_label = new FXLabel(vf, "Disconnected");
|
||||
|
||||
new FXHorizontalFrame(vf);
|
||||
|
||||
// Output Group Box
|
||||
FXGroupBox *gb = new FXGroupBox(vf, "Output", FRAME_GROOVE|LAYOUT_FILL_X);
|
||||
FXMatrix *matrix = new FXMatrix(gb, 3, MATRIX_BY_COLUMNS|LAYOUT_FILL_X);
|
||||
new FXLabel(matrix, "Data");
|
||||
new FXLabel(matrix, "Length");
|
||||
new FXLabel(matrix, "");
|
||||
|
||||
//hf = new FXHorizontalFrame(gb, LAYOUT_FILL_X);
|
||||
output_text = new FXTextField(matrix, 30, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
|
||||
output_text->setText("1 0x81 0");
|
||||
output_len = new FXTextField(matrix, 5, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
|
||||
output_button = new FXButton(matrix, "Send Output Report", NULL, this, ID_SEND_OUTPUT_REPORT, BUTTON_NORMAL|LAYOUT_FILL_X);
|
||||
output_button->disable();
|
||||
//new FXHorizontalFrame(matrix, LAYOUT_FILL_X);
|
||||
|
||||
//hf = new FXHorizontalFrame(gb, LAYOUT_FILL_X);
|
||||
feature_text = new FXTextField(matrix, 30, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
|
||||
feature_len = new FXTextField(matrix, 5, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
|
||||
feature_button = new FXButton(matrix, "Send Feature Report", NULL, this, ID_SEND_FEATURE_REPORT, BUTTON_NORMAL|LAYOUT_FILL_X);
|
||||
feature_button->disable();
|
||||
|
||||
get_feature_text = new FXTextField(matrix, 30, NULL, 0, TEXTFIELD_NORMAL|LAYOUT_FILL_X|LAYOUT_FILL_COLUMN);
|
||||
new FXWindow(matrix);
|
||||
get_feature_button = new FXButton(matrix, "Get Feature Report", NULL, this, ID_GET_FEATURE_REPORT, BUTTON_NORMAL|LAYOUT_FILL_X);
|
||||
get_feature_button->disable();
|
||||
|
||||
|
||||
// Input Group Box
|
||||
gb = new FXGroupBox(vf, "Input", FRAME_GROOVE|LAYOUT_FILL_X|LAYOUT_FILL_Y);
|
||||
FXVerticalFrame *innerVF = new FXVerticalFrame(gb, LAYOUT_FILL_X|LAYOUT_FILL_Y);
|
||||
input_text = new FXText(new FXHorizontalFrame(innerVF,LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, 0,0,0,0, 0,0,0,0), NULL, 0, LAYOUT_FILL_X|LAYOUT_FILL_Y);
|
||||
input_text->setEditable(false);
|
||||
new FXButton(innerVF, "Clear", NULL, this, ID_CLEAR, BUTTON_NORMAL|LAYOUT_RIGHT);
|
||||
|
||||
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
if (connected_device)
|
||||
hid_close(connected_device);
|
||||
hid_exit();
|
||||
delete title_font;
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::create()
|
||||
{
|
||||
FXMainWindow::create();
|
||||
show();
|
||||
|
||||
onRescan(NULL, 0, NULL);
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
init_apple_message_system();
|
||||
#endif
|
||||
|
||||
getApp()->addTimeout(this, ID_MAC_TIMER,
|
||||
50 * timeout_scalar /*50ms*/);
|
||||
}
|
||||
|
||||
long
|
||||
MainWindow::onConnect(FXObject *sender, FXSelector sel, void *ptr)
|
||||
{
|
||||
if (connected_device != NULL)
|
||||
return 1;
|
||||
|
||||
FXint cur_item = device_list->getCurrentItem();
|
||||
if (cur_item < 0)
|
||||
return -1;
|
||||
FXListItem *item = device_list->getItem(cur_item);
|
||||
if (!item)
|
||||
return -1;
|
||||
struct hid_device_info *device_info = (struct hid_device_info*) item->getData();
|
||||
if (!device_info)
|
||||
return -1;
|
||||
|
||||
connected_device = hid_open_path(device_info->path);
|
||||
|
||||
if (!connected_device) {
|
||||
FXMessageBox::error(this, MBOX_OK, "Device Error", "Unable To Connect to Device");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hid_set_nonblocking(connected_device, 1);
|
||||
|
||||
getApp()->addTimeout(this, ID_TIMER,
|
||||
5 * timeout_scalar /*5ms*/);
|
||||
|
||||
FXString s;
|
||||
s.format("Connected to: %04hx:%04hx -", device_info->vendor_id, device_info->product_id);
|
||||
s += FXString(" ") + device_info->manufacturer_string;
|
||||
s += FXString(" ") + device_info->product_string;
|
||||
connected_label->setText(s);
|
||||
output_button->enable();
|
||||
feature_button->enable();
|
||||
get_feature_button->enable();
|
||||
connect_button->disable();
|
||||
disconnect_button->enable();
|
||||
input_text->setText("");
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
long
|
||||
MainWindow::onDisconnect(FXObject *sender, FXSelector sel, void *ptr)
|
||||
{
|
||||
hid_close(connected_device);
|
||||
connected_device = NULL;
|
||||
connected_label->setText("Disconnected");
|
||||
output_button->disable();
|
||||
feature_button->disable();
|
||||
get_feature_button->disable();
|
||||
connect_button->enable();
|
||||
disconnect_button->disable();
|
||||
|
||||
getApp()->removeTimeout(this, ID_TIMER);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
long
|
||||
MainWindow::onRescan(FXObject *sender, FXSelector sel, void *ptr)
|
||||
{
|
||||
struct hid_device_info *cur_dev;
|
||||
|
||||
device_list->clearItems();
|
||||
|
||||
// List the Devices
|
||||
hid_free_enumeration(devices);
|
||||
devices = hid_enumerate(0x0, 0x0);
|
||||
cur_dev = devices;
|
||||
while (cur_dev) {
|
||||
// Add it to the List Box.
|
||||
FXString s;
|
||||
FXString usage_str;
|
||||
s.format("%04hx:%04hx -", cur_dev->vendor_id, cur_dev->product_id);
|
||||
s += FXString(" ") + cur_dev->manufacturer_string;
|
||||
s += FXString(" ") + cur_dev->product_string;
|
||||
usage_str.format(" (usage: %04hx:%04hx) ", cur_dev->usage_page, cur_dev->usage);
|
||||
s += usage_str;
|
||||
FXListItem *li = new FXListItem(s, NULL, cur_dev);
|
||||
device_list->appendItem(li);
|
||||
|
||||
cur_dev = cur_dev->next;
|
||||
}
|
||||
|
||||
if (device_list->getNumItems() == 0)
|
||||
device_list->appendItem("*** No Devices Connected ***");
|
||||
else {
|
||||
device_list->selectItem(0);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t
|
||||
MainWindow::getDataFromTextField(FXTextField *tf, char *buf, size_t len)
|
||||
{
|
||||
const char *delim = " ,{}\t\r\n";
|
||||
FXString data = tf->getText();
|
||||
const FXchar *d = data.text();
|
||||
size_t i = 0;
|
||||
|
||||
// Copy the string from the GUI.
|
||||
size_t sz = strlen(d);
|
||||
char *str = (char*) malloc(sz+1);
|
||||
strcpy(str, d);
|
||||
|
||||
// For each token in the string, parse and store in buf[].
|
||||
char *token = strtok(str, delim);
|
||||
while (token) {
|
||||
char *endptr;
|
||||
long int val = strtol(token, &endptr, 0);
|
||||
buf[i++] = val;
|
||||
token = strtok(NULL, delim);
|
||||
}
|
||||
|
||||
free(str);
|
||||
return i;
|
||||
}
|
||||
|
||||
/* getLengthFromTextField()
|
||||
Returns length:
|
||||
0: empty text field
|
||||
>0: valid length
|
||||
-1: invalid length */
|
||||
int
|
||||
MainWindow::getLengthFromTextField(FXTextField *tf)
|
||||
{
|
||||
long int len;
|
||||
FXString str = tf->getText();
|
||||
size_t sz = str.length();
|
||||
|
||||
if (sz > 0) {
|
||||
char *endptr;
|
||||
len = strtol(str.text(), &endptr, 0);
|
||||
if (endptr != str.text() && *endptr == '\0') {
|
||||
if (len <= 0) {
|
||||
FXMessageBox::error(this, MBOX_OK, "Invalid length", "Enter a length greater than zero.");
|
||||
return -1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
long
|
||||
MainWindow::onSendOutputReport(FXObject *sender, FXSelector sel, void *ptr)
|
||||
{
|
||||
char buf[256];
|
||||
size_t data_len, len;
|
||||
int textfield_len;
|
||||
|
||||
memset(buf, 0x0, sizeof(buf));
|
||||
textfield_len = getLengthFromTextField(output_len);
|
||||
data_len = getDataFromTextField(output_text, buf, sizeof(buf));
|
||||
|
||||
if (textfield_len < 0) {
|
||||
FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is invalid. Please enter a number in hex, octal, or decimal.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (textfield_len > sizeof(buf)) {
|
||||
FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is too long.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
len = (textfield_len)? textfield_len: data_len;
|
||||
|
||||
int res = hid_write(connected_device, (const unsigned char*)buf, len);
|
||||
if (res < 0) {
|
||||
FXMessageBox::error(this, MBOX_OK, "Error Writing", "Could not write to device. Error reported was: %ls", hid_error(connected_device));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
long
|
||||
MainWindow::onSendFeatureReport(FXObject *sender, FXSelector sel, void *ptr)
|
||||
{
|
||||
char buf[256];
|
||||
size_t data_len, len;
|
||||
int textfield_len;
|
||||
|
||||
memset(buf, 0x0, sizeof(buf));
|
||||
textfield_len = getLengthFromTextField(feature_len);
|
||||
data_len = getDataFromTextField(feature_text, buf, sizeof(buf));
|
||||
|
||||
if (textfield_len < 0) {
|
||||
FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is invalid. Please enter a number in hex, octal, or decimal.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (textfield_len > sizeof(buf)) {
|
||||
FXMessageBox::error(this, MBOX_OK, "Invalid length", "Length field is too long.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
len = (textfield_len)? textfield_len: data_len;
|
||||
|
||||
int res = hid_send_feature_report(connected_device, (const unsigned char*)buf, len);
|
||||
if (res < 0) {
|
||||
FXMessageBox::error(this, MBOX_OK, "Error Writing", "Could not send feature report to device. Error reported was: %ls", hid_error(connected_device));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
long
|
||||
MainWindow::onGetFeatureReport(FXObject *sender, FXSelector sel, void *ptr)
|
||||
{
|
||||
char buf[256];
|
||||
size_t len;
|
||||
|
||||
memset(buf, 0x0, sizeof(buf));
|
||||
len = getDataFromTextField(get_feature_text, buf, sizeof(buf));
|
||||
|
||||
if (len != 1) {
|
||||
FXMessageBox::error(this, MBOX_OK, "Too many numbers", "Enter only a single report number in the text field");
|
||||
}
|
||||
|
||||
int res = hid_get_feature_report(connected_device, (unsigned char*)buf, sizeof(buf));
|
||||
if (res < 0) {
|
||||
FXMessageBox::error(this, MBOX_OK, "Error Getting Report", "Could not get feature report from device. Error reported was: %ls", hid_error(connected_device));
|
||||
}
|
||||
|
||||
if (res > 0) {
|
||||
FXString s;
|
||||
s.format("Returned Feature Report. %d bytes:\n", res);
|
||||
for (int i = 0; i < res; i++) {
|
||||
FXString t;
|
||||
t.format("%02hhx ", buf[i]);
|
||||
s += t;
|
||||
if ((i+1) % 4 == 0)
|
||||
s += " ";
|
||||
if ((i+1) % 16 == 0)
|
||||
s += "\n";
|
||||
}
|
||||
s += "\n";
|
||||
input_text->appendText(s);
|
||||
input_text->setBottomLine(INT_MAX);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
long
|
||||
MainWindow::onClear(FXObject *sender, FXSelector sel, void *ptr)
|
||||
{
|
||||
input_text->setText("");
|
||||
return 1;
|
||||
}
|
||||
|
||||
long
|
||||
MainWindow::onTimeout(FXObject *sender, FXSelector sel, void *ptr)
|
||||
{
|
||||
unsigned char buf[256];
|
||||
int res = hid_read(connected_device, buf, sizeof(buf));
|
||||
|
||||
if (res > 0) {
|
||||
FXString s;
|
||||
s.format("Received %d bytes:\n", res);
|
||||
for (int i = 0; i < res; i++) {
|
||||
FXString t;
|
||||
t.format("%02hhx ", buf[i]);
|
||||
s += t;
|
||||
if ((i+1) % 4 == 0)
|
||||
s += " ";
|
||||
if ((i+1) % 16 == 0)
|
||||
s += "\n";
|
||||
}
|
||||
s += "\n";
|
||||
input_text->appendText(s);
|
||||
input_text->setBottomLine(INT_MAX);
|
||||
}
|
||||
if (res < 0) {
|
||||
input_text->appendText("hid_read() returned error\n");
|
||||
input_text->setBottomLine(INT_MAX);
|
||||
}
|
||||
|
||||
getApp()->addTimeout(this, ID_TIMER,
|
||||
5 * timeout_scalar /*5ms*/);
|
||||
return 1;
|
||||
}
|
||||
|
||||
long
|
||||
MainWindow::onMacTimeout(FXObject *sender, FXSelector sel, void *ptr)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
check_apple_events();
|
||||
|
||||
getApp()->addTimeout(this, ID_MAC_TIMER,
|
||||
50 * timeout_scalar /*50ms*/);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
FXApp app("HIDAPI Test Application", "Signal 11 Software");
|
||||
app.init(argc, argv);
|
||||
g_main_window = new MainWindow(&app);
|
||||
app.create();
|
||||
app.run();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 10.00
|
||||
# Visual C++ Express 2008
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testgui", "testgui.vcproj", "{08769AC3-785A-4DDC-BFC7-1775414B7AB7}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{08769AC3-785A-4DDC-BFC7-1775414B7AB7}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{08769AC3-785A-4DDC-BFC7-1775414B7AB7}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{08769AC3-785A-4DDC-BFC7-1775414B7AB7}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{08769AC3-785A-4DDC-BFC7-1775414B7AB7}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,63 @@
|
||||
list(APPEND HIDAPI_PUBLIC_HEADERS "hidapi_winapi.h")
|
||||
|
||||
set(SOURCES
|
||||
hid.c
|
||||
hidapi_cfgmgr32.h
|
||||
hidapi_descriptor_reconstruct.c
|
||||
hidapi_descriptor_reconstruct.h
|
||||
hidapi_hidclass.h
|
||||
hidapi_hidpi.h
|
||||
hidapi_hidsdi.h
|
||||
)
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
list(APPEND SOURCES hidapi.rc)
|
||||
endif()
|
||||
|
||||
add_library(hidapi_winapi
|
||||
${HIDAPI_PUBLIC_HEADERS}
|
||||
${SOURCES}
|
||||
)
|
||||
target_link_libraries(hidapi_winapi
|
||||
PUBLIC hidapi_include
|
||||
)
|
||||
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(hidapi_winapi
|
||||
# prevent marking functions as __declspec(dllexport) for static library build
|
||||
# #480: this should be refactored for v1.0
|
||||
PUBLIC HID_API_NO_EXPORT_DEFINE
|
||||
)
|
||||
endif()
|
||||
|
||||
set_target_properties(hidapi_winapi
|
||||
PROPERTIES
|
||||
EXPORT_NAME "winapi"
|
||||
OUTPUT_NAME "hidapi"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
PUBLIC_HEADER "${HIDAPI_PUBLIC_HEADERS}"
|
||||
)
|
||||
|
||||
# compatibility with find_package()
|
||||
add_library(hidapi::winapi ALIAS hidapi_winapi)
|
||||
# compatibility with raw library link
|
||||
add_library(hidapi ALIAS hidapi_winapi)
|
||||
|
||||
if(HIDAPI_INSTALL_TARGETS)
|
||||
install(TARGETS hidapi_winapi EXPORT hidapi
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/hidapi"
|
||||
)
|
||||
endif()
|
||||
|
||||
hidapi_configure_pc("${PROJECT_ROOT}/pc/hidapi.pc.in")
|
||||
|
||||
if(HIDAPI_WITH_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
if(DEFINED HIDAPI_BUILD_PP_DATA_DUMP AND HIDAPI_BUILD_PP_DATA_DUMP)
|
||||
add_subdirectory(pp_data_dump)
|
||||
endif()
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.28307.136
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hidapi", "hidapi.vcxproj", "{A107C21C-418A-4697-BB10-20C3AA60E2E4}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hidtest", "hidtest.vcxproj", "{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Debug|x64.Build.0 = Debug|x64
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|Win32.Build.0 = Release|Win32
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|x64.ActiveCfg = Release|x64
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4}.Release|x64.Build.0 = Release|x64
|
||||
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Debug|x64.Build.0 = Debug|x64
|
||||
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|Win32.Build.0 = Release|Win32
|
||||
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|x64.ActiveCfg = Release|x64
|
||||
{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {8749E535-9C65-4A89-840E-78D7578C7866}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,200 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{A107C21C-418A-4697-BB10-20C3AA60E2E4}</ProjectGuid>
|
||||
<RootNamespace>hidapi</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>14.0.25431.1</_ProjectFileVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\hidapi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader />
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>..\hidapi</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_DEBUG</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\hidapi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>..\hidapi</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_DEBUG</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\hidapi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader />
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>..\hidapi</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>NDEBUG</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\hidapi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;HIDAPI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
</Link>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>..\hidapi</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>NDEBUG</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="hid.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\hidapi\hidapi.h" />
|
||||
<ClInclude Include="hidapi_winapi.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="hidapi.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,86 @@
|
||||
/*******************************************************
|
||||
HIDAPI - Multi-Platform library for
|
||||
communication with HID devices.
|
||||
|
||||
libusb/hidapi Team
|
||||
|
||||
Copyright 2022, All Rights Reserved.
|
||||
|
||||
At the discretion of the user of this library,
|
||||
this software may be licensed under the terms of the
|
||||
GNU General Public License v3, a BSD-Style license, or the
|
||||
original HIDAPI license as outlined in the LICENSE.txt,
|
||||
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
|
||||
files located at the root of the source distribution.
|
||||
These files may also be found in the public source
|
||||
code repository located at:
|
||||
https://github.com/libusb/hidapi .
|
||||
********************************************************/
|
||||
|
||||
#ifndef HIDAPI_CFGMGR32_H
|
||||
#define HIDAPI_CFGMGR32_H
|
||||
|
||||
#ifdef HIDAPI_USE_DDK
|
||||
|
||||
#include <cfgmgr32.h>
|
||||
#include <initguid.h>
|
||||
#include <devpkey.h>
|
||||
#include <propkey.h>
|
||||
|
||||
#else
|
||||
|
||||
/* This part of the header mimics cfgmgr32.h,
|
||||
but only what is used by HIDAPI */
|
||||
|
||||
//#include <initguid.h>
|
||||
#include <devpropdef.h>
|
||||
//#include <propkeydef.h>
|
||||
|
||||
#ifndef PROPERTYKEY_DEFINED
|
||||
#define PROPERTYKEY_DEFINED
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GUID fmtid;
|
||||
DWORD pid;
|
||||
} PROPERTYKEY;
|
||||
|
||||
#endif /* PROPERTYKEY_DEFINED */
|
||||
|
||||
typedef DWORD RETURN_TYPE;
|
||||
typedef RETURN_TYPE CONFIGRET;
|
||||
typedef DWORD DEVNODE, DEVINST;
|
||||
typedef DEVNODE* PDEVNODE, * PDEVINST;
|
||||
typedef WCHAR* DEVNODEID_W, * DEVINSTID_W;
|
||||
|
||||
#define CR_SUCCESS (0x00000000)
|
||||
#define CR_BUFFER_SMALL (0x0000001A)
|
||||
#define CR_FAILURE (0x00000013)
|
||||
|
||||
#define CM_LOCATE_DEVNODE_NORMAL 0x00000000
|
||||
|
||||
#define CM_GET_DEVICE_INTERFACE_LIST_PRESENT (0x00000000)
|
||||
|
||||
typedef CONFIGRET(__stdcall* CM_Locate_DevNodeW_)(PDEVINST pdnDevInst, DEVINSTID_W pDeviceID, ULONG ulFlags);
|
||||
typedef CONFIGRET(__stdcall* CM_Get_Parent_)(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags);
|
||||
typedef CONFIGRET(__stdcall* CM_Get_DevNode_PropertyW_)(DEVINST dnDevInst, CONST DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, PULONG PropertyBufferSize, ULONG ulFlags);
|
||||
typedef CONFIGRET(__stdcall* CM_Get_Device_Interface_PropertyW_)(LPCWSTR pszDeviceInterface, CONST DEVPROPKEY* PropertyKey, DEVPROPTYPE* PropertyType, PBYTE PropertyBuffer, PULONG PropertyBufferSize, ULONG ulFlags);
|
||||
typedef CONFIGRET(__stdcall* CM_Get_Device_Interface_List_SizeW_)(PULONG pulLen, LPGUID InterfaceClassGuid, DEVINSTID_W pDeviceID, ULONG ulFlags);
|
||||
typedef CONFIGRET(__stdcall* CM_Get_Device_Interface_ListW_)(LPGUID InterfaceClassGuid, DEVINSTID_W pDeviceID, WCHAR* /*PZZWSTR*/ Buffer, ULONG BufferLen, ULONG ulFlags);
|
||||
|
||||
// from devpkey.h
|
||||
static DEVPROPKEY DEVPKEY_NAME = { { 0xb725f130, 0x47ef, 0x101a, {0xa5, 0xf1, 0x02, 0x60, 0x8c, 0x9e, 0xeb, 0xac} }, 10 }; // DEVPROP_TYPE_STRING
|
||||
static DEVPROPKEY DEVPKEY_Device_Manufacturer = { { 0xa45c254e, 0xdf1c, 0x4efd, {0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0} }, 13 }; // DEVPROP_TYPE_STRING
|
||||
static DEVPROPKEY DEVPKEY_Device_InstanceId = { { 0x78c34fc8, 0x104a, 0x4aca, {0x9e, 0xa4, 0x52, 0x4d, 0x52, 0x99, 0x6e, 0x57} }, 256 }; // DEVPROP_TYPE_STRING
|
||||
static DEVPROPKEY DEVPKEY_Device_HardwareIds = { { 0xa45c254e, 0xdf1c, 0x4efd, {0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0} }, 3 }; // DEVPROP_TYPE_STRING_LIST
|
||||
static DEVPROPKEY DEVPKEY_Device_CompatibleIds = { { 0xa45c254e, 0xdf1c, 0x4efd, {0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0} }, 4 }; // DEVPROP_TYPE_STRING_LIST
|
||||
static DEVPROPKEY DEVPKEY_Device_ContainerId = { { 0x8c7ed206, 0x3f8a, 0x4827, {0xb3, 0xab, 0xae, 0x9e, 0x1f, 0xae, 0xfc, 0x6c} }, 2 }; // DEVPROP_TYPE_GUID
|
||||
|
||||
// from propkey.h
|
||||
static PROPERTYKEY PKEY_DeviceInterface_Bluetooth_DeviceAddress = { { 0x2bd67d8b, 0x8beb, 0x48d5, {0x87, 0xe0, 0x6c, 0xda, 0x34, 0x28, 0x04, 0x0a} }, 1 }; // DEVPROP_TYPE_STRING
|
||||
static PROPERTYKEY PKEY_DeviceInterface_Bluetooth_Manufacturer = { { 0x2bd67d8b, 0x8beb, 0x48d5, {0x87, 0xe0, 0x6c, 0xda, 0x34, 0x28, 0x04, 0x0a} }, 4 }; // DEVPROP_TYPE_STRING
|
||||
static PROPERTYKEY PKEY_DeviceInterface_Bluetooth_ModelNumber = { { 0x2BD67D8B, 0x8BEB, 0x48D5, {0x87, 0xE0, 0x6C, 0xDA, 0x34, 0x28, 0x04, 0x0A} }, 5 }; // DEVPROP_TYPE_STRING
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HIDAPI_CFGMGR32_H */
|
||||
@@ -0,0 +1,990 @@
|
||||
/*******************************************************
|
||||
HIDAPI - Multi-Platform library for
|
||||
communication with HID devices.
|
||||
|
||||
libusb/hidapi Team
|
||||
|
||||
Copyright 2022, All Rights Reserved.
|
||||
|
||||
At the discretion of the user of this library,
|
||||
this software may be licensed under the terms of the
|
||||
GNU General Public License v3, a BSD-Style license, or the
|
||||
original HIDAPI license as outlined in the LICENSE.txt,
|
||||
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
|
||||
files located at the root of the source distribution.
|
||||
These files may also be found in the public source
|
||||
code repository located at:
|
||||
https://github.com/libusb/hidapi .
|
||||
********************************************************/
|
||||
#include "hidapi_descriptor_reconstruct.h"
|
||||
|
||||
/**
|
||||
* @brief References to report descriptor buffer.
|
||||
*
|
||||
*/
|
||||
struct rd_buffer {
|
||||
unsigned char* buf; /* Pointer to the array which stores the reconstructed descriptor */
|
||||
size_t buf_size; /* Size of the buffer in bytes */
|
||||
size_t byte_idx; /* Index of the next report byte to write to buf array */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Function that appends a byte to encoded report descriptor buffer.
|
||||
*
|
||||
* @param[in] byte Single byte to append.
|
||||
* @param rpt_desc Pointer to report descriptor buffer struct.
|
||||
*/
|
||||
static void rd_append_byte(unsigned char byte, struct rd_buffer* rpt_desc) {
|
||||
if (rpt_desc->byte_idx < rpt_desc->buf_size) {
|
||||
rpt_desc->buf[rpt_desc->byte_idx] = byte;
|
||||
rpt_desc->byte_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes a short report descriptor item according USB HID spec 1.11 chapter 6.2.2.2.
|
||||
*
|
||||
* @param[in] rd_item Enumeration identifying type (Main, Global, Local) and function (e.g Usage or Report Count) of the item.
|
||||
* @param[in] data Data (Size depends on rd_item 0,1,2 or 4bytes).
|
||||
* @param rpt_desc Pointer to report descriptor buffer struct.
|
||||
*
|
||||
* @return Returns 0 if successful, -1 for error.
|
||||
*/
|
||||
static int rd_write_short_item(rd_items rd_item, LONG64 data, struct rd_buffer* rpt_desc) {
|
||||
if (rd_item & 0x03) {
|
||||
// Invalid input data, last to bits are reserved for data size
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rd_item == rd_main_collection_end) {
|
||||
// Item without data (1Byte prefix only)
|
||||
unsigned char oneBytePrefix = (unsigned char) rd_item + 0x00;
|
||||
rd_append_byte(oneBytePrefix, rpt_desc);
|
||||
}
|
||||
else if ((rd_item == rd_global_logical_minimum) ||
|
||||
(rd_item == rd_global_logical_maximum) ||
|
||||
(rd_item == rd_global_physical_minimum) ||
|
||||
(rd_item == rd_global_physical_maximum)) {
|
||||
// Item with signed integer data
|
||||
if ((data >= -128) && (data <= 127)) {
|
||||
// 1Byte prefix + 1Byte data
|
||||
unsigned char oneBytePrefix = (unsigned char) rd_item + 0x01;
|
||||
char localData = (char)data;
|
||||
rd_append_byte(oneBytePrefix, rpt_desc);
|
||||
rd_append_byte(localData & 0xFF, rpt_desc);
|
||||
}
|
||||
else if ((data >= -32768) && (data <= 32767)) {
|
||||
// 1Byte prefix + 2Byte data
|
||||
unsigned char oneBytePrefix = (unsigned char) rd_item + 0x02;
|
||||
INT16 localData = (INT16)data;
|
||||
rd_append_byte(oneBytePrefix, rpt_desc);
|
||||
rd_append_byte(localData & 0xFF, rpt_desc);
|
||||
rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
|
||||
}
|
||||
else if ((data >= -2147483648LL) && (data <= 2147483647)) {
|
||||
// 1Byte prefix + 4Byte data
|
||||
unsigned char oneBytePrefix = (unsigned char) rd_item + 0x03;
|
||||
INT32 localData = (INT32)data;
|
||||
rd_append_byte(oneBytePrefix, rpt_desc);
|
||||
rd_append_byte(localData & 0xFF, rpt_desc);
|
||||
rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
|
||||
rd_append_byte(localData >> 16 & 0xFF, rpt_desc);
|
||||
rd_append_byte(localData >> 24 & 0xFF, rpt_desc);
|
||||
}
|
||||
else {
|
||||
// Data out of 32 bit signed integer range
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Item with unsigned integer data
|
||||
if ((data >= 0) && (data <= 0xFF)) {
|
||||
// 1Byte prefix + 1Byte data
|
||||
unsigned char oneBytePrefix = (unsigned char) rd_item + 0x01;
|
||||
unsigned char localData = (unsigned char)data;
|
||||
rd_append_byte(oneBytePrefix, rpt_desc);
|
||||
rd_append_byte(localData & 0xFF, rpt_desc);
|
||||
}
|
||||
else if ((data >= 0) && (data <= 0xFFFF)) {
|
||||
// 1Byte prefix + 2Byte data
|
||||
unsigned char oneBytePrefix = (unsigned char) rd_item + 0x02;
|
||||
UINT16 localData = (UINT16)data;
|
||||
rd_append_byte(oneBytePrefix, rpt_desc);
|
||||
rd_append_byte(localData & 0xFF, rpt_desc);
|
||||
rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
|
||||
}
|
||||
else if ((data >= 0) && (data <= 0xFFFFFFFF)) {
|
||||
// 1Byte prefix + 4Byte data
|
||||
unsigned char oneBytePrefix = (unsigned char) rd_item + 0x03;
|
||||
UINT32 localData = (UINT32)data;
|
||||
rd_append_byte(oneBytePrefix, rpt_desc);
|
||||
rd_append_byte(localData & 0xFF, rpt_desc);
|
||||
rd_append_byte(localData >> 8 & 0xFF, rpt_desc);
|
||||
rd_append_byte(localData >> 16 & 0xFF, rpt_desc);
|
||||
rd_append_byte(localData >> 24 & 0xFF, rpt_desc);
|
||||
}
|
||||
else {
|
||||
// Data out of 32 bit unsigned integer range
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rd_main_item_node * rd_append_main_item_node(int first_bit, int last_bit, rd_node_type type_of_node, int caps_index, int collection_index, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) {
|
||||
struct rd_main_item_node *new_list_node;
|
||||
|
||||
// Determine last node in the list
|
||||
while (*list != NULL)
|
||||
{
|
||||
list = &(*list)->next;
|
||||
}
|
||||
|
||||
new_list_node = malloc(sizeof(*new_list_node)); // Create new list entry
|
||||
new_list_node->FirstBit = first_bit;
|
||||
new_list_node->LastBit = last_bit;
|
||||
new_list_node->TypeOfNode = type_of_node;
|
||||
new_list_node->CapsIndex = caps_index;
|
||||
new_list_node->CollectionIndex = collection_index;
|
||||
new_list_node->MainItemType = main_item_type;
|
||||
new_list_node->ReportID = report_id;
|
||||
new_list_node->next = NULL; // NULL marks last node in the list
|
||||
|
||||
*list = new_list_node;
|
||||
return new_list_node;
|
||||
}
|
||||
|
||||
static struct rd_main_item_node * rd_insert_main_item_node(int first_bit, int last_bit, rd_node_type type_of_node, int caps_index, int collection_index, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) {
|
||||
// Insert item after the main item node referenced by list
|
||||
struct rd_main_item_node *next_item = (*list)->next;
|
||||
(*list)->next = NULL;
|
||||
rd_append_main_item_node(first_bit, last_bit, type_of_node, caps_index, collection_index, main_item_type, report_id, list);
|
||||
(*list)->next->next = next_item;
|
||||
return (*list)->next;
|
||||
}
|
||||
|
||||
static struct rd_main_item_node * rd_search_main_item_list_for_bit_position(int search_bit, rd_main_items main_item_type, unsigned char report_id, struct rd_main_item_node **list) {
|
||||
// Determine first INPUT/OUTPUT/FEATURE main item, where the last bit position is equal or greater than the search bit position
|
||||
|
||||
while (((*list)->next->MainItemType != rd_collection) &&
|
||||
((*list)->next->MainItemType != rd_collection_end) &&
|
||||
!(((*list)->next->LastBit >= search_bit) &&
|
||||
((*list)->next->ReportID == report_id) &&
|
||||
((*list)->next->MainItemType == main_item_type))
|
||||
)
|
||||
{
|
||||
list = &(*list)->next;
|
||||
}
|
||||
return *list;
|
||||
}
|
||||
|
||||
int hid_winapi_descriptor_reconstruct_pp_data(void *preparsed_data, unsigned char *buf, size_t buf_size)
|
||||
{
|
||||
hidp_preparsed_data *pp_data = (hidp_preparsed_data *) preparsed_data;
|
||||
|
||||
// Check if MagicKey is correct, to ensure that pp_data points to an valid preparse data structure
|
||||
if (memcmp(pp_data->MagicKey, "HidP KDR", 8) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct rd_buffer rpt_desc;
|
||||
rpt_desc.buf = buf;
|
||||
rpt_desc.buf_size = buf_size;
|
||||
rpt_desc.byte_idx = 0;
|
||||
|
||||
// Set pointer to the first node of link_collection_nodes
|
||||
phid_pp_link_collection_node link_collection_nodes = (phid_pp_link_collection_node)(((unsigned char*)&pp_data->caps[0]) + pp_data->FirstByteOfLinkCollectionArray);
|
||||
|
||||
// ****************************************************************************************************************************
|
||||
// Create lookup tables for the bit range of each report per collection (position of first bit and last bit in each collection)
|
||||
// coll_bit_range[COLLECTION_INDEX][REPORT_ID][INPUT/OUTPUT/FEATURE]
|
||||
// ****************************************************************************************************************************
|
||||
|
||||
// Allocate memory and initialize lookup table
|
||||
rd_bit_range ****coll_bit_range;
|
||||
coll_bit_range = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_bit_range));
|
||||
for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
|
||||
coll_bit_range[collection_node_idx] = malloc(256 * sizeof(*coll_bit_range[0])); // 256 possible report IDs (incl. 0x00)
|
||||
for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
|
||||
coll_bit_range[collection_node_idx][reportid_idx] = malloc(NUM_OF_HIDP_REPORT_TYPES * sizeof(*coll_bit_range[0][0]));
|
||||
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
|
||||
coll_bit_range[collection_node_idx][reportid_idx][rt_idx] = malloc(sizeof(rd_bit_range));
|
||||
coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit = -1;
|
||||
coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill the lookup table where caps exist
|
||||
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
|
||||
for (USHORT caps_idx = pp_data->caps_info[rt_idx].FirstCap; caps_idx < pp_data->caps_info[rt_idx].LastCap; caps_idx++) {
|
||||
int first_bit, last_bit;
|
||||
first_bit = (pp_data->caps[caps_idx].BytePosition - 1) * 8
|
||||
+ pp_data->caps[caps_idx].BitPosition;
|
||||
last_bit = first_bit + pp_data->caps[caps_idx].ReportSize
|
||||
* pp_data->caps[caps_idx].ReportCount - 1;
|
||||
if (coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit == -1 ||
|
||||
coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit > first_bit) {
|
||||
coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit = first_bit;
|
||||
}
|
||||
if (coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->LastBit < last_bit) {
|
||||
coll_bit_range[pp_data->caps[caps_idx].LinkCollection][pp_data->caps[caps_idx].ReportID][rt_idx]->LastBit = last_bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// *************************************************************************
|
||||
// -Determine hierarchy levels of each collections and store it in:
|
||||
// coll_levels[COLLECTION_INDEX]
|
||||
// -Determine number of direct childs of each collections and store it in:
|
||||
// coll_number_of_direct_childs[COLLECTION_INDEX]
|
||||
// *************************************************************************
|
||||
int max_coll_level = 0;
|
||||
int *coll_levels = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_levels[0]));
|
||||
int *coll_number_of_direct_childs = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_number_of_direct_childs[0]));
|
||||
for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
|
||||
coll_levels[collection_node_idx] = -1;
|
||||
coll_number_of_direct_childs[collection_node_idx] = 0;
|
||||
}
|
||||
|
||||
{
|
||||
int actual_coll_level = 0;
|
||||
USHORT collection_node_idx = 0;
|
||||
while (actual_coll_level >= 0) {
|
||||
coll_levels[collection_node_idx] = actual_coll_level;
|
||||
if ((link_collection_nodes[collection_node_idx].NumberOfChildren > 0) &&
|
||||
(coll_levels[link_collection_nodes[collection_node_idx].FirstChild] == -1)) {
|
||||
actual_coll_level++;
|
||||
coll_levels[collection_node_idx] = actual_coll_level;
|
||||
if (max_coll_level < actual_coll_level) {
|
||||
max_coll_level = actual_coll_level;
|
||||
}
|
||||
coll_number_of_direct_childs[collection_node_idx]++;
|
||||
collection_node_idx = link_collection_nodes[collection_node_idx].FirstChild;
|
||||
}
|
||||
else if (link_collection_nodes[collection_node_idx].NextSibling != 0) {
|
||||
coll_number_of_direct_childs[link_collection_nodes[collection_node_idx].Parent]++;
|
||||
collection_node_idx = link_collection_nodes[collection_node_idx].NextSibling;
|
||||
}
|
||||
else {
|
||||
actual_coll_level--;
|
||||
if (actual_coll_level >= 0) {
|
||||
collection_node_idx = link_collection_nodes[collection_node_idx].Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// *********************************************************************************
|
||||
// Propagate the bit range of each report from the child collections to their parent
|
||||
// and store the merged result for the parent
|
||||
// *********************************************************************************
|
||||
for (int actual_coll_level = max_coll_level - 1; actual_coll_level >= 0; actual_coll_level--) {
|
||||
for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
|
||||
if (coll_levels[collection_node_idx] == actual_coll_level) {
|
||||
USHORT child_idx = link_collection_nodes[collection_node_idx].FirstChild;
|
||||
while (child_idx) {
|
||||
for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
|
||||
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
|
||||
// Merge bit range from childs
|
||||
if ((coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit != -1) &&
|
||||
(coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit > coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit)) {
|
||||
coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->FirstBit = coll_bit_range[child_idx][reportid_idx][rt_idx]->FirstBit;
|
||||
}
|
||||
if (coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit < coll_bit_range[child_idx][reportid_idx][rt_idx]->LastBit) {
|
||||
coll_bit_range[collection_node_idx][reportid_idx][rt_idx]->LastBit = coll_bit_range[child_idx][reportid_idx][rt_idx]->LastBit;
|
||||
}
|
||||
child_idx = link_collection_nodes[child_idx].NextSibling;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// **************************************************************************************************
|
||||
// Determine child collection order of the whole hierarchy, based on previously determined bit ranges
|
||||
// and store it this index coll_child_order[COLLECTION_INDEX][DIRECT_CHILD_INDEX]
|
||||
// **************************************************************************************************
|
||||
USHORT **coll_child_order;
|
||||
coll_child_order = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_child_order));
|
||||
{
|
||||
BOOLEAN *coll_parsed_flag;
|
||||
coll_parsed_flag = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_parsed_flag[0]));
|
||||
for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
|
||||
coll_parsed_flag[collection_node_idx] = FALSE;
|
||||
}
|
||||
int actual_coll_level = 0;
|
||||
USHORT collection_node_idx = 0;
|
||||
while (actual_coll_level >= 0) {
|
||||
if ((coll_number_of_direct_childs[collection_node_idx] != 0) &&
|
||||
(coll_parsed_flag[link_collection_nodes[collection_node_idx].FirstChild] == FALSE)) {
|
||||
coll_parsed_flag[link_collection_nodes[collection_node_idx].FirstChild] = TRUE;
|
||||
coll_child_order[collection_node_idx] = malloc((coll_number_of_direct_childs[collection_node_idx]) * sizeof(*coll_child_order[0]));
|
||||
|
||||
{
|
||||
// Create list of child collection indices
|
||||
// sorted reverse to the order returned to HidP_GetLinkCollectionNodeschild
|
||||
// which seems to match the original order, as long as no bit position needs to be considered
|
||||
USHORT child_idx = link_collection_nodes[collection_node_idx].FirstChild;
|
||||
int child_count = coll_number_of_direct_childs[collection_node_idx] - 1;
|
||||
coll_child_order[collection_node_idx][child_count] = child_idx;
|
||||
while (link_collection_nodes[child_idx].NextSibling) {
|
||||
child_count--;
|
||||
child_idx = link_collection_nodes[child_idx].NextSibling;
|
||||
coll_child_order[collection_node_idx][child_count] = child_idx;
|
||||
}
|
||||
}
|
||||
|
||||
if (coll_number_of_direct_childs[collection_node_idx] > 1) {
|
||||
// Sort child collections indices by bit positions
|
||||
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
|
||||
for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
|
||||
for (int child_idx = 1; child_idx < coll_number_of_direct_childs[collection_node_idx]; child_idx++) {
|
||||
// since the coll_bit_range array is not sorted, we need to reference the collection index in
|
||||
// our sorted coll_child_order array, and look up the corresponding bit ranges for comparing values to sort
|
||||
int prev_coll_idx = coll_child_order[collection_node_idx][child_idx - 1];
|
||||
int cur_coll_idx = coll_child_order[collection_node_idx][child_idx];
|
||||
if ((coll_bit_range[prev_coll_idx][reportid_idx][rt_idx]->FirstBit != -1) &&
|
||||
(coll_bit_range[cur_coll_idx][reportid_idx][rt_idx]->FirstBit != -1) &&
|
||||
(coll_bit_range[prev_coll_idx][reportid_idx][rt_idx]->FirstBit > coll_bit_range[cur_coll_idx][reportid_idx][rt_idx]->FirstBit)) {
|
||||
// Swap position indices of the two compared child collections
|
||||
USHORT idx_latch = coll_child_order[collection_node_idx][child_idx - 1];
|
||||
coll_child_order[collection_node_idx][child_idx - 1] = coll_child_order[collection_node_idx][child_idx];
|
||||
coll_child_order[collection_node_idx][child_idx] = idx_latch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
actual_coll_level++;
|
||||
collection_node_idx = link_collection_nodes[collection_node_idx].FirstChild;
|
||||
}
|
||||
else if (link_collection_nodes[collection_node_idx].NextSibling != 0) {
|
||||
collection_node_idx = link_collection_nodes[collection_node_idx].NextSibling;
|
||||
}
|
||||
else {
|
||||
actual_coll_level--;
|
||||
if (actual_coll_level >= 0) {
|
||||
collection_node_idx = link_collection_nodes[collection_node_idx].Parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(coll_parsed_flag);
|
||||
}
|
||||
|
||||
|
||||
// ***************************************************************************************
|
||||
// Create sorted main_item_list containing all the Collection and CollectionEnd main items
|
||||
// ***************************************************************************************
|
||||
struct rd_main_item_node *main_item_list = NULL; // List root
|
||||
// Lookup table to find the Collection items in the list by index
|
||||
struct rd_main_item_node **coll_begin_lookup = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_begin_lookup));
|
||||
struct rd_main_item_node **coll_end_lookup = malloc(pp_data->NumberLinkCollectionNodes * sizeof(*coll_end_lookup));
|
||||
{
|
||||
int *coll_last_written_child = malloc(pp_data->NumberLinkCollectionNodes * sizeof(coll_last_written_child[0]));
|
||||
for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
|
||||
coll_last_written_child[collection_node_idx] = -1;
|
||||
}
|
||||
|
||||
int actual_coll_level = 0;
|
||||
USHORT collection_node_idx = 0;
|
||||
struct rd_main_item_node *firstDelimiterNode = NULL;
|
||||
struct rd_main_item_node *delimiterCloseNode = NULL;
|
||||
coll_begin_lookup[0] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list);
|
||||
while (actual_coll_level >= 0) {
|
||||
if ((coll_number_of_direct_childs[collection_node_idx] != 0) &&
|
||||
(coll_last_written_child[collection_node_idx] == -1)) {
|
||||
// Collection has child collections, but none is written to the list yet
|
||||
|
||||
coll_last_written_child[collection_node_idx] = coll_child_order[collection_node_idx][0];
|
||||
collection_node_idx = coll_child_order[collection_node_idx][0];
|
||||
|
||||
// In a HID Report Descriptor, the first usage declared is the most preferred usage for the control.
|
||||
// While the order in the WIN32 capabiliy strutures is the opposite:
|
||||
// Here the preferred usage is the last aliased usage in the sequence.
|
||||
|
||||
if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode == NULL)) {
|
||||
// Alliased Collection (First node in link_collection_nodes -> Last entry in report descriptor output)
|
||||
firstDelimiterNode = main_item_list;
|
||||
coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &main_item_list);
|
||||
coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_close, 0, &main_item_list);
|
||||
delimiterCloseNode = main_item_list;
|
||||
}
|
||||
else {
|
||||
// Normal not aliased collection
|
||||
coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list);
|
||||
actual_coll_level++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if ((coll_number_of_direct_childs[collection_node_idx] > 1) &&
|
||||
(coll_last_written_child[collection_node_idx] != coll_child_order[collection_node_idx][coll_number_of_direct_childs[collection_node_idx] - 1])) {
|
||||
// Collection has child collections, and this is not the first child
|
||||
|
||||
int nextChild = 1;
|
||||
while (coll_last_written_child[collection_node_idx] != coll_child_order[collection_node_idx][nextChild - 1]) {
|
||||
nextChild++;
|
||||
}
|
||||
coll_last_written_child[collection_node_idx] = coll_child_order[collection_node_idx][nextChild];
|
||||
collection_node_idx = coll_child_order[collection_node_idx][nextChild];
|
||||
|
||||
if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode == NULL)) {
|
||||
// Alliased Collection (First node in link_collection_nodes -> Last entry in report descriptor output)
|
||||
firstDelimiterNode = main_item_list;
|
||||
coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &main_item_list);
|
||||
coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_close, 0, &main_item_list);
|
||||
delimiterCloseNode = main_item_list;
|
||||
}
|
||||
else if (link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode != NULL)) {
|
||||
coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &firstDelimiterNode);
|
||||
}
|
||||
else if (!link_collection_nodes[collection_node_idx].IsAlias && (firstDelimiterNode != NULL)) {
|
||||
coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_usage, 0, &firstDelimiterNode);
|
||||
coll_begin_lookup[collection_node_idx] = rd_insert_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_delimiter_open, 0, &firstDelimiterNode);
|
||||
firstDelimiterNode = NULL;
|
||||
main_item_list = delimiterCloseNode;
|
||||
delimiterCloseNode = NULL; // Last entry of alias has .IsAlias == FALSE
|
||||
}
|
||||
if (!link_collection_nodes[collection_node_idx].IsAlias) {
|
||||
coll_begin_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection, 0, &main_item_list);
|
||||
actual_coll_level++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
actual_coll_level--;
|
||||
coll_end_lookup[collection_node_idx] = rd_append_main_item_node(0, 0, rd_item_node_collection, 0, collection_node_idx, rd_collection_end, 0, &main_item_list);
|
||||
collection_node_idx = link_collection_nodes[collection_node_idx].Parent;
|
||||
}
|
||||
}
|
||||
free(coll_last_written_child);
|
||||
}
|
||||
|
||||
|
||||
// ****************************************************************
|
||||
// Inserted Input/Output/Feature main items into the main_item_list
|
||||
// in order of reconstructed bit positions
|
||||
// ****************************************************************
|
||||
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
|
||||
// Add all value caps to node list
|
||||
struct rd_main_item_node *firstDelimiterNode = NULL;
|
||||
struct rd_main_item_node *delimiterCloseNode = NULL;
|
||||
for (USHORT caps_idx = pp_data->caps_info[rt_idx].FirstCap; caps_idx < pp_data->caps_info[rt_idx].LastCap; caps_idx++) {
|
||||
struct rd_main_item_node *coll_begin = coll_begin_lookup[pp_data->caps[caps_idx].LinkCollection];
|
||||
int first_bit, last_bit;
|
||||
first_bit = (pp_data->caps[caps_idx].BytePosition - 1) * 8 +
|
||||
pp_data->caps[caps_idx].BitPosition;
|
||||
last_bit = first_bit + pp_data->caps[caps_idx].ReportSize *
|
||||
pp_data->caps[caps_idx].ReportCount - 1;
|
||||
|
||||
for (int child_idx = 0; child_idx < coll_number_of_direct_childs[pp_data->caps[caps_idx].LinkCollection]; child_idx++) {
|
||||
// Determine in which section before/between/after child collection the item should be inserted
|
||||
if (first_bit < coll_bit_range[coll_child_order[pp_data->caps[caps_idx].LinkCollection][child_idx]][pp_data->caps[caps_idx].ReportID][rt_idx]->FirstBit)
|
||||
{
|
||||
// Note, that the default value for undefined coll_bit_range is -1, which can't be greater than the bit position
|
||||
break;
|
||||
}
|
||||
coll_begin = coll_end_lookup[coll_child_order[pp_data->caps[caps_idx].LinkCollection][child_idx]];
|
||||
}
|
||||
struct rd_main_item_node *list_node;
|
||||
list_node = rd_search_main_item_list_for_bit_position(first_bit, (rd_main_items) rt_idx, pp_data->caps[caps_idx].ReportID, &coll_begin);
|
||||
|
||||
// In a HID Report Descriptor, the first usage declared is the most preferred usage for the control.
|
||||
// While the order in the WIN32 capabiliy strutures is the opposite:
|
||||
// Here the preferred usage is the last aliased usage in the sequence.
|
||||
|
||||
if (pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode == NULL)) {
|
||||
// Alliased Usage (First node in pp_data->caps -> Last entry in report descriptor output)
|
||||
firstDelimiterNode = list_node;
|
||||
rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node);
|
||||
rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_close, pp_data->caps[caps_idx].ReportID, &list_node);
|
||||
delimiterCloseNode = list_node;
|
||||
} else if (pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode != NULL)) {
|
||||
rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node);
|
||||
}
|
||||
else if (!pp_data->caps[caps_idx].IsAlias && (firstDelimiterNode != NULL)) {
|
||||
// Alliased Collection (Last node in pp_data->caps -> First entry in report descriptor output)
|
||||
rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_usage, pp_data->caps[caps_idx].ReportID, &list_node);
|
||||
rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, rd_delimiter_open, pp_data->caps[caps_idx].ReportID, &list_node);
|
||||
firstDelimiterNode = NULL;
|
||||
list_node = delimiterCloseNode;
|
||||
delimiterCloseNode = NULL; // Last entry of alias has .IsAlias == FALSE
|
||||
}
|
||||
if (!pp_data->caps[caps_idx].IsAlias) {
|
||||
rd_insert_main_item_node(first_bit, last_bit, rd_item_node_cap, caps_idx, pp_data->caps[caps_idx].LinkCollection, (rd_main_items) rt_idx, pp_data->caps[caps_idx].ReportID, &list_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ***********************************************************
|
||||
// Add const main items for padding to main_item_list
|
||||
// -To fill all bit gaps
|
||||
// -At each report end for 8bit padding
|
||||
// Note that information about the padding at the report end,
|
||||
// is not stored in the preparsed data, but in practice all
|
||||
// report descriptors seem to have it, as assumed here.
|
||||
// ***********************************************************
|
||||
{
|
||||
int *last_bit_position[NUM_OF_HIDP_REPORT_TYPES];
|
||||
struct rd_main_item_node **last_report_item_lookup[NUM_OF_HIDP_REPORT_TYPES];
|
||||
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
|
||||
last_bit_position[rt_idx] = malloc(256 * sizeof(*last_bit_position[rt_idx]));
|
||||
last_report_item_lookup[rt_idx] = malloc(256 * sizeof(*last_report_item_lookup[rt_idx]));
|
||||
for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
|
||||
last_bit_position[rt_idx][reportid_idx] = -1;
|
||||
last_report_item_lookup[rt_idx][reportid_idx] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct rd_main_item_node *list = main_item_list; // List root;
|
||||
|
||||
while (list->next != NULL)
|
||||
{
|
||||
if ((list->MainItemType >= rd_input) &&
|
||||
(list->MainItemType <= rd_feature)) {
|
||||
// INPUT, OUTPUT or FEATURE
|
||||
if (list->FirstBit != -1) {
|
||||
if ((last_bit_position[list->MainItemType][list->ReportID] + 1 != list->FirstBit) &&
|
||||
(last_report_item_lookup[list->MainItemType][list->ReportID] != NULL) &&
|
||||
(last_report_item_lookup[list->MainItemType][list->ReportID]->FirstBit != list->FirstBit) // Happens in case of IsMultipleItemsForArray for multiple dedicated usages for a multi-button array
|
||||
) {
|
||||
struct rd_main_item_node *list_node = rd_search_main_item_list_for_bit_position(last_bit_position[list->MainItemType][list->ReportID], list->MainItemType, list->ReportID, &last_report_item_lookup[list->MainItemType][list->ReportID]);
|
||||
rd_insert_main_item_node(last_bit_position[list->MainItemType][list->ReportID] + 1, list->FirstBit - 1, rd_item_node_padding, -1, 0, list->MainItemType, list->ReportID, &list_node);
|
||||
}
|
||||
last_bit_position[list->MainItemType][list->ReportID] = list->LastBit;
|
||||
last_report_item_lookup[list->MainItemType][list->ReportID] = list;
|
||||
}
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
// Add 8 bit padding at each report end
|
||||
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
|
||||
for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
|
||||
if (last_bit_position[rt_idx][reportid_idx] != -1) {
|
||||
int padding = 8 - ((last_bit_position[rt_idx][reportid_idx] + 1) % 8);
|
||||
if (padding < 8) {
|
||||
// Insert padding item after item referenced in last_report_item_lookup
|
||||
rd_insert_main_item_node(last_bit_position[rt_idx][reportid_idx] + 1, last_bit_position[rt_idx][reportid_idx] + padding, rd_item_node_padding, -1, 0, (rd_main_items) rt_idx, (unsigned char) reportid_idx, &last_report_item_lookup[rt_idx][reportid_idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(last_bit_position[rt_idx]);
|
||||
free(last_report_item_lookup[rt_idx]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ***********************************
|
||||
// Encode the report descriptor output
|
||||
// ***********************************
|
||||
UCHAR last_report_id = 0;
|
||||
USAGE last_usage_page = 0;
|
||||
LONG last_physical_min = 0;// If both, Physical Minimum and Physical Maximum are 0, the logical limits should be taken as physical limits according USB HID spec 1.11 chapter 6.2.2.7
|
||||
LONG last_physical_max = 0;
|
||||
ULONG last_unit_exponent = 0; // If Unit Exponent is Undefined it should be considered as 0 according USB HID spec 1.11 chapter 6.2.2.7
|
||||
ULONG last_unit = 0; // If the first nibble is 7, or second nibble of Unit is 0, the unit is None according USB HID spec 1.11 chapter 6.2.2.7
|
||||
BOOLEAN inhibit_write_of_usage = FALSE; // Needed in case of delimited usage print, before the normal collection or cap
|
||||
int report_count = 0;
|
||||
while (main_item_list != NULL)
|
||||
{
|
||||
int rt_idx = main_item_list->MainItemType;
|
||||
int caps_idx = main_item_list->CapsIndex;
|
||||
if (main_item_list->MainItemType == rd_collection) {
|
||||
if (last_usage_page != link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage) {
|
||||
// Write "Usage Page" at the begin of a collection - except it refers the same table as wrote last
|
||||
rd_write_short_item(rd_global_usage_page, link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage, &rpt_desc);
|
||||
last_usage_page = link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage;
|
||||
}
|
||||
if (inhibit_write_of_usage) {
|
||||
// Inhibit only once after DELIMITER statement
|
||||
inhibit_write_of_usage = FALSE;
|
||||
}
|
||||
else {
|
||||
// Write "Usage" of collection
|
||||
rd_write_short_item(rd_local_usage, link_collection_nodes[main_item_list->CollectionIndex].LinkUsage, &rpt_desc);
|
||||
}
|
||||
// Write begin of "Collection"
|
||||
rd_write_short_item(rd_main_collection, link_collection_nodes[main_item_list->CollectionIndex].CollectionType, &rpt_desc);
|
||||
}
|
||||
else if (main_item_list->MainItemType == rd_collection_end) {
|
||||
// Write "End Collection"
|
||||
rd_write_short_item(rd_main_collection_end, 0, &rpt_desc);
|
||||
}
|
||||
else if (main_item_list->MainItemType == rd_delimiter_open) {
|
||||
if (main_item_list->CollectionIndex != -1) {
|
||||
// Write "Usage Page" inside of a collection delmiter section
|
||||
if (last_usage_page != link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage) {
|
||||
rd_write_short_item(rd_global_usage_page, link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage, &rpt_desc);
|
||||
last_usage_page = link_collection_nodes[main_item_list->CollectionIndex].LinkUsagePage;
|
||||
}
|
||||
}
|
||||
else if (main_item_list->CapsIndex != 0) {
|
||||
// Write "Usage Page" inside of a main item delmiter section
|
||||
if (pp_data->caps[caps_idx].UsagePage != last_usage_page) {
|
||||
rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc);
|
||||
last_usage_page = pp_data->caps[caps_idx].UsagePage;
|
||||
}
|
||||
}
|
||||
// Write "Delimiter Open"
|
||||
rd_write_short_item(rd_local_delimiter, 1, &rpt_desc); // 1 = open set of aliased usages
|
||||
}
|
||||
else if (main_item_list->MainItemType == rd_delimiter_usage) {
|
||||
if (main_item_list->CollectionIndex != -1) {
|
||||
// Write aliased collection "Usage"
|
||||
rd_write_short_item(rd_local_usage, link_collection_nodes[main_item_list->CollectionIndex].LinkUsage, &rpt_desc);
|
||||
} if (main_item_list->CapsIndex != 0) {
|
||||
// Write aliased main item range from "Usage Minimum" to "Usage Maximum"
|
||||
if (pp_data->caps[caps_idx].IsRange) {
|
||||
rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc);
|
||||
rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc);
|
||||
}
|
||||
else {
|
||||
// Write single aliased main item "Usage"
|
||||
rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (main_item_list->MainItemType == rd_delimiter_close) {
|
||||
// Write "Delimiter Close"
|
||||
rd_write_short_item(rd_local_delimiter, 0, &rpt_desc); // 0 = close set of aliased usages
|
||||
// Inhibit next usage write
|
||||
inhibit_write_of_usage = TRUE;
|
||||
}
|
||||
else if (main_item_list->TypeOfNode == rd_item_node_padding) {
|
||||
// Padding
|
||||
// The preparsed data doesn't contain any information about padding. Therefore all undefined gaps
|
||||
// in the reports are filled with the same style of constant padding.
|
||||
|
||||
// Write "Report Size" with number of padding bits
|
||||
rd_write_short_item(rd_global_report_size, (main_item_list->LastBit - main_item_list->FirstBit + 1), &rpt_desc);
|
||||
|
||||
// Write "Report Count" for padding always as 1
|
||||
rd_write_short_item(rd_global_report_count, 1, &rpt_desc);
|
||||
|
||||
if (rt_idx == HidP_Input) {
|
||||
// Write "Input" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const
|
||||
rd_write_short_item(rd_main_input, 0x03, &rpt_desc); // Const / Abs
|
||||
}
|
||||
else if (rt_idx == HidP_Output) {
|
||||
// Write "Output" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const
|
||||
rd_write_short_item(rd_main_output, 0x03, &rpt_desc); // Const / Abs
|
||||
}
|
||||
else if (rt_idx == HidP_Feature) {
|
||||
// Write "Feature" main item - We know it's Constant - We can only guess the other bits, but they don't matter in case of const
|
||||
rd_write_short_item(rd_main_feature, 0x03, &rpt_desc); // Const / Abs
|
||||
}
|
||||
report_count = 0;
|
||||
}
|
||||
else if (pp_data->caps[caps_idx].IsButtonCap) {
|
||||
// Button
|
||||
// (The preparsed data contain different data for 1 bit Button caps, than for parametric Value caps)
|
||||
|
||||
if (last_report_id != pp_data->caps[caps_idx].ReportID) {
|
||||
// Write "Report ID" if changed
|
||||
rd_write_short_item(rd_global_report_id, pp_data->caps[caps_idx].ReportID, &rpt_desc);
|
||||
last_report_id = pp_data->caps[caps_idx].ReportID;
|
||||
}
|
||||
|
||||
// Write "Usage Page" when changed
|
||||
if (pp_data->caps[caps_idx].UsagePage != last_usage_page) {
|
||||
rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc);
|
||||
last_usage_page = pp_data->caps[caps_idx].UsagePage;
|
||||
}
|
||||
|
||||
// Write only local report items for each cap, if ReportCount > 1
|
||||
if (pp_data->caps[caps_idx].IsRange) {
|
||||
report_count += (pp_data->caps[caps_idx].Range.DataIndexMax - pp_data->caps[caps_idx].Range.DataIndexMin);
|
||||
}
|
||||
|
||||
if (inhibit_write_of_usage) {
|
||||
// Inhibit only once after Delimiter - Reset flag
|
||||
inhibit_write_of_usage = FALSE;
|
||||
}
|
||||
else {
|
||||
if (pp_data->caps[caps_idx].IsRange) {
|
||||
// Write range from "Usage Minimum" to "Usage Maximum"
|
||||
rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc);
|
||||
rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc);
|
||||
}
|
||||
else {
|
||||
// Write single "Usage"
|
||||
rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc);
|
||||
}
|
||||
}
|
||||
|
||||
if (pp_data->caps[caps_idx].IsDesignatorRange) {
|
||||
// Write physical descriptor indices range from "Designator Minimum" to "Designator Maximum"
|
||||
rd_write_short_item(rd_local_designator_minimum, pp_data->caps[caps_idx].Range.DesignatorMin, &rpt_desc);
|
||||
rd_write_short_item(rd_local_designator_maximum, pp_data->caps[caps_idx].Range.DesignatorMax, &rpt_desc);
|
||||
}
|
||||
else if (pp_data->caps[caps_idx].NotRange.DesignatorIndex != 0) {
|
||||
// Designator set 0 is a special descriptor set (of the HID Physical Descriptor),
|
||||
// that specifies the number of additional descriptor sets.
|
||||
// Therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
|
||||
// Write single "Designator Index"
|
||||
rd_write_short_item(rd_local_designator_index, pp_data->caps[caps_idx].NotRange.DesignatorIndex, &rpt_desc);
|
||||
}
|
||||
|
||||
if (pp_data->caps[caps_idx].IsStringRange) {
|
||||
// Write range of indices of the USB string descriptor, from "String Minimum" to "String Maximum"
|
||||
rd_write_short_item(rd_local_string_minimum, pp_data->caps[caps_idx].Range.StringMin, &rpt_desc);
|
||||
rd_write_short_item(rd_local_string_maximum, pp_data->caps[caps_idx].Range.StringMax, &rpt_desc);
|
||||
}
|
||||
else if (pp_data->caps[caps_idx].NotRange.StringIndex != 0) {
|
||||
// String Index 0 is a special entry of the USB string descriptor, that contains a list of supported languages,
|
||||
// therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
|
||||
// Write single "String Index"
|
||||
rd_write_short_item(rd_local_string, pp_data->caps[caps_idx].NotRange.StringIndex, &rpt_desc);
|
||||
}
|
||||
|
||||
if ((main_item_list->next != NULL) &&
|
||||
((int)main_item_list->next->MainItemType == rt_idx) &&
|
||||
(main_item_list->next->TypeOfNode == rd_item_node_cap) &&
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].IsButtonCap) &&
|
||||
(!pp_data->caps[caps_idx].IsRange) && // This node in list is no array
|
||||
(!pp_data->caps[main_item_list->next->CapsIndex].IsRange) && // Next node in list is no array
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].UsagePage == pp_data->caps[caps_idx].UsagePage) &&
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].ReportID == pp_data->caps[caps_idx].ReportID) &&
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].BitField == pp_data->caps[caps_idx].BitField)
|
||||
) {
|
||||
if (main_item_list->next->FirstBit != main_item_list->FirstBit) {
|
||||
// In case of IsMultipleItemsForArray for multiple dedicated usages for a multi-button array, the report count should be incremented
|
||||
|
||||
// Skip global items until any of them changes, than use ReportCount item to write the count of identical report fields
|
||||
report_count++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
if ((pp_data->caps[caps_idx].Button.LogicalMin == 0) &&
|
||||
(pp_data->caps[caps_idx].Button.LogicalMax == 0)) {
|
||||
// While a HID report descriptor must always contain LogicalMinimum and LogicalMaximum,
|
||||
// the preparsed data contain both fields set to zero, for the case of simple buttons
|
||||
// Write "Logical Minimum" set to 0 and "Logical Maximum" set to 1
|
||||
rd_write_short_item(rd_global_logical_minimum, 0, &rpt_desc);
|
||||
rd_write_short_item(rd_global_logical_maximum, 1, &rpt_desc);
|
||||
}
|
||||
else {
|
||||
// Write logical range from "Logical Minimum" to "Logical Maximum"
|
||||
rd_write_short_item(rd_global_logical_minimum, pp_data->caps[caps_idx].Button.LogicalMin, &rpt_desc);
|
||||
rd_write_short_item(rd_global_logical_maximum, pp_data->caps[caps_idx].Button.LogicalMax, &rpt_desc);
|
||||
}
|
||||
|
||||
// Write "Report Size"
|
||||
rd_write_short_item(rd_global_report_size, pp_data->caps[caps_idx].ReportSize, &rpt_desc);
|
||||
|
||||
// Write "Report Count"
|
||||
if (!pp_data->caps[caps_idx].IsRange) {
|
||||
// Variable bit field with one bit per button
|
||||
// In case of multiple usages with the same items, only "Usage" is written per cap, and "Report Count" is incremented
|
||||
rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount + report_count, &rpt_desc);
|
||||
}
|
||||
else {
|
||||
// Button array of "Report Size" x "Report Count
|
||||
rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount, &rpt_desc);
|
||||
}
|
||||
|
||||
|
||||
// Buttons have only 1 bit and therefore no physical limits/units -> Set to undefined state
|
||||
if (last_physical_min != 0) {
|
||||
// Write "Physical Minimum", but only if changed
|
||||
last_physical_min = 0;
|
||||
rd_write_short_item(rd_global_physical_minimum, last_physical_min, &rpt_desc);
|
||||
}
|
||||
if (last_physical_max != 0) {
|
||||
// Write "Physical Maximum", but only if changed
|
||||
last_physical_max = 0;
|
||||
rd_write_short_item(rd_global_physical_maximum, last_physical_max, &rpt_desc);
|
||||
}
|
||||
if (last_unit_exponent != 0) {
|
||||
// Write "Unit Exponent", but only if changed
|
||||
last_unit_exponent = 0;
|
||||
rd_write_short_item(rd_global_unit_exponent, last_unit_exponent, &rpt_desc);
|
||||
}
|
||||
if (last_unit != 0) {
|
||||
// Write "Unit",but only if changed
|
||||
last_unit = 0;
|
||||
rd_write_short_item(rd_global_unit, last_unit, &rpt_desc);
|
||||
}
|
||||
|
||||
// Write "Input" main item
|
||||
if (rt_idx == HidP_Input) {
|
||||
rd_write_short_item(rd_main_input, pp_data->caps[caps_idx].BitField, &rpt_desc);
|
||||
}
|
||||
// Write "Output" main item
|
||||
else if (rt_idx == HidP_Output) {
|
||||
rd_write_short_item(rd_main_output, pp_data->caps[caps_idx].BitField, &rpt_desc);
|
||||
}
|
||||
// Write "Feature" main item
|
||||
else if (rt_idx == HidP_Feature) {
|
||||
rd_write_short_item(rd_main_feature, pp_data->caps[caps_idx].BitField, &rpt_desc);
|
||||
}
|
||||
report_count = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
if (last_report_id != pp_data->caps[caps_idx].ReportID) {
|
||||
// Write "Report ID" if changed
|
||||
rd_write_short_item(rd_global_report_id, pp_data->caps[caps_idx].ReportID, &rpt_desc);
|
||||
last_report_id = pp_data->caps[caps_idx].ReportID;
|
||||
}
|
||||
|
||||
// Write "Usage Page" if changed
|
||||
if (pp_data->caps[caps_idx].UsagePage != last_usage_page) {
|
||||
rd_write_short_item(rd_global_usage_page, pp_data->caps[caps_idx].UsagePage, &rpt_desc);
|
||||
last_usage_page = pp_data->caps[caps_idx].UsagePage;
|
||||
}
|
||||
|
||||
if (inhibit_write_of_usage) {
|
||||
// Inhibit only once after Delimiter - Reset flag
|
||||
inhibit_write_of_usage = FALSE;
|
||||
}
|
||||
else {
|
||||
if (pp_data->caps[caps_idx].IsRange) {
|
||||
// Write usage range from "Usage Minimum" to "Usage Maximum"
|
||||
rd_write_short_item(rd_local_usage_minimum, pp_data->caps[caps_idx].Range.UsageMin, &rpt_desc);
|
||||
rd_write_short_item(rd_local_usage_maximum, pp_data->caps[caps_idx].Range.UsageMax, &rpt_desc);
|
||||
}
|
||||
else {
|
||||
// Write single "Usage"
|
||||
rd_write_short_item(rd_local_usage, pp_data->caps[caps_idx].NotRange.Usage, &rpt_desc);
|
||||
}
|
||||
}
|
||||
|
||||
if (pp_data->caps[caps_idx].IsDesignatorRange) {
|
||||
// Write physical descriptor indices range from "Designator Minimum" to "Designator Maximum"
|
||||
rd_write_short_item(rd_local_designator_minimum, pp_data->caps[caps_idx].Range.DesignatorMin, &rpt_desc);
|
||||
rd_write_short_item(rd_local_designator_maximum, pp_data->caps[caps_idx].Range.DesignatorMax, &rpt_desc);
|
||||
}
|
||||
else if (pp_data->caps[caps_idx].NotRange.DesignatorIndex != 0) {
|
||||
// Designator set 0 is a special descriptor set (of the HID Physical Descriptor),
|
||||
// that specifies the number of additional descriptor sets.
|
||||
// Therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
|
||||
// Write single "Designator Index"
|
||||
rd_write_short_item(rd_local_designator_index, pp_data->caps[caps_idx].NotRange.DesignatorIndex, &rpt_desc);
|
||||
}
|
||||
|
||||
if (pp_data->caps[caps_idx].IsStringRange) {
|
||||
// Write range of indices of the USB string descriptor, from "String Minimum" to "String Maximum"
|
||||
rd_write_short_item(rd_local_string_minimum, pp_data->caps[caps_idx].Range.StringMin, &rpt_desc);
|
||||
rd_write_short_item(rd_local_string_maximum, pp_data->caps[caps_idx].Range.StringMax, &rpt_desc);
|
||||
}
|
||||
else if (pp_data->caps[caps_idx].NotRange.StringIndex != 0) {
|
||||
// String Index 0 is a special entry of the USB string descriptor, that contains a list of supported languages,
|
||||
// therefore Designator Index 0 can never be a useful reference for a control and we can inhibit it.
|
||||
// Write single "String Index"
|
||||
rd_write_short_item(rd_local_string, pp_data->caps[caps_idx].NotRange.StringIndex, &rpt_desc);
|
||||
}
|
||||
|
||||
if ((pp_data->caps[caps_idx].BitField & 0x02) != 0x02) {
|
||||
// In case of an value array overwrite "Report Count"
|
||||
pp_data->caps[caps_idx].ReportCount = pp_data->caps[caps_idx].Range.DataIndexMax - pp_data->caps[caps_idx].Range.DataIndexMin + 1;
|
||||
}
|
||||
|
||||
|
||||
// Print only local report items for each cap, if ReportCount > 1
|
||||
if ((main_item_list->next != NULL) &&
|
||||
((int) main_item_list->next->MainItemType == rt_idx) &&
|
||||
(main_item_list->next->TypeOfNode == rd_item_node_cap) &&
|
||||
(!pp_data->caps[main_item_list->next->CapsIndex].IsButtonCap) &&
|
||||
(!pp_data->caps[caps_idx].IsRange) && // This node in list is no array
|
||||
(!pp_data->caps[main_item_list->next->CapsIndex].IsRange) && // Next node in list is no array
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].UsagePage == pp_data->caps[caps_idx].UsagePage) &&
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].NotButton.LogicalMin == pp_data->caps[caps_idx].NotButton.LogicalMin) &&
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].NotButton.LogicalMax == pp_data->caps[caps_idx].NotButton.LogicalMax) &&
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].NotButton.PhysicalMin == pp_data->caps[caps_idx].NotButton.PhysicalMin) &&
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].NotButton.PhysicalMax == pp_data->caps[caps_idx].NotButton.PhysicalMax) &&
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].UnitsExp == pp_data->caps[caps_idx].UnitsExp) &&
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].Units == pp_data->caps[caps_idx].Units) &&
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].ReportSize == pp_data->caps[caps_idx].ReportSize) &&
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].ReportID == pp_data->caps[caps_idx].ReportID) &&
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].BitField == pp_data->caps[caps_idx].BitField) &&
|
||||
(pp_data->caps[main_item_list->next->CapsIndex].ReportCount == 1) &&
|
||||
(pp_data->caps[caps_idx].ReportCount == 1)
|
||||
) {
|
||||
// Skip global items until any of them changes, than use ReportCount item to write the count of identical report fields
|
||||
report_count++;
|
||||
}
|
||||
else {
|
||||
// Value
|
||||
|
||||
// Write logical range from "Logical Minimum" to "Logical Maximum"
|
||||
rd_write_short_item(rd_global_logical_minimum, pp_data->caps[caps_idx].NotButton.LogicalMin, &rpt_desc);
|
||||
rd_write_short_item(rd_global_logical_maximum, pp_data->caps[caps_idx].NotButton.LogicalMax, &rpt_desc);
|
||||
|
||||
if ((last_physical_min != pp_data->caps[caps_idx].NotButton.PhysicalMin) ||
|
||||
(last_physical_max != pp_data->caps[caps_idx].NotButton.PhysicalMax)) {
|
||||
// Write range from "Physical Minimum" to " Physical Maximum", but only if one of them changed
|
||||
rd_write_short_item(rd_global_physical_minimum, pp_data->caps[caps_idx].NotButton.PhysicalMin, &rpt_desc);
|
||||
last_physical_min = pp_data->caps[caps_idx].NotButton.PhysicalMin;
|
||||
rd_write_short_item(rd_global_physical_maximum, pp_data->caps[caps_idx].NotButton.PhysicalMax, &rpt_desc);
|
||||
last_physical_max = pp_data->caps[caps_idx].NotButton.PhysicalMax;
|
||||
}
|
||||
|
||||
|
||||
if (last_unit_exponent != pp_data->caps[caps_idx].UnitsExp) {
|
||||
// Write "Unit Exponent", but only if changed
|
||||
rd_write_short_item(rd_global_unit_exponent, pp_data->caps[caps_idx].UnitsExp, &rpt_desc);
|
||||
last_unit_exponent = pp_data->caps[caps_idx].UnitsExp;
|
||||
}
|
||||
|
||||
if (last_unit != pp_data->caps[caps_idx].Units) {
|
||||
// Write physical "Unit", but only if changed
|
||||
rd_write_short_item(rd_global_unit, pp_data->caps[caps_idx].Units, &rpt_desc);
|
||||
last_unit = pp_data->caps[caps_idx].Units;
|
||||
}
|
||||
|
||||
// Write "Report Size"
|
||||
rd_write_short_item(rd_global_report_size, pp_data->caps[caps_idx].ReportSize, &rpt_desc);
|
||||
|
||||
// Write "Report Count"
|
||||
rd_write_short_item(rd_global_report_count, pp_data->caps[caps_idx].ReportCount + report_count, &rpt_desc);
|
||||
|
||||
if (rt_idx == HidP_Input) {
|
||||
// Write "Input" main item
|
||||
rd_write_short_item(rd_main_input, pp_data->caps[caps_idx].BitField, &rpt_desc);
|
||||
}
|
||||
else if (rt_idx == HidP_Output) {
|
||||
// Write "Output" main item
|
||||
rd_write_short_item(rd_main_output, pp_data->caps[caps_idx].BitField, &rpt_desc);
|
||||
}
|
||||
else if (rt_idx == HidP_Feature) {
|
||||
// Write "Feature" main item
|
||||
rd_write_short_item(rd_main_feature, pp_data->caps[caps_idx].BitField, &rpt_desc);
|
||||
}
|
||||
report_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Go to next item in main_item_list and free the memory of the actual item
|
||||
struct rd_main_item_node *main_item_list_prev = main_item_list;
|
||||
main_item_list = main_item_list->next;
|
||||
free(main_item_list_prev);
|
||||
}
|
||||
|
||||
// Free multidimensionable array: coll_bit_range[COLLECTION_INDEX][REPORT_ID][INPUT/OUTPUT/FEATURE]
|
||||
// Free multidimensionable array: coll_child_order[COLLECTION_INDEX][DIRECT_CHILD_INDEX]
|
||||
for (USHORT collection_node_idx = 0; collection_node_idx < pp_data->NumberLinkCollectionNodes; collection_node_idx++) {
|
||||
for (int reportid_idx = 0; reportid_idx < 256; reportid_idx++) {
|
||||
for (HIDP_REPORT_TYPE rt_idx = 0; rt_idx < NUM_OF_HIDP_REPORT_TYPES; rt_idx++) {
|
||||
free(coll_bit_range[collection_node_idx][reportid_idx][rt_idx]);
|
||||
}
|
||||
free(coll_bit_range[collection_node_idx][reportid_idx]);
|
||||
}
|
||||
free(coll_bit_range[collection_node_idx]);
|
||||
if (coll_number_of_direct_childs[collection_node_idx] != 0) free(coll_child_order[collection_node_idx]);
|
||||
}
|
||||
free(coll_bit_range);
|
||||
free(coll_child_order);
|
||||
|
||||
// Free one dimensional arrays
|
||||
free(coll_begin_lookup);
|
||||
free(coll_end_lookup);
|
||||
free(coll_levels);
|
||||
free(coll_number_of_direct_childs);
|
||||
|
||||
return (int) rpt_desc.byte_idx;
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
/*******************************************************
|
||||
HIDAPI - Multi-Platform library for
|
||||
communication with HID devices.
|
||||
|
||||
libusb/hidapi Team
|
||||
|
||||
Copyright 2022, All Rights Reserved.
|
||||
|
||||
At the discretion of the user of this library,
|
||||
this software may be licensed under the terms of the
|
||||
GNU General Public License v3, a BSD-Style license, or the
|
||||
original HIDAPI license as outlined in the LICENSE.txt,
|
||||
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
|
||||
files located at the root of the source distribution.
|
||||
These files may also be found in the public source
|
||||
code repository located at:
|
||||
https://github.com/libusb/hidapi .
|
||||
********************************************************/
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifndef HIDAPI_DESCRIPTOR_RECONSTRUCT_H__
|
||||
#define HIDAPI_DESCRIPTOR_RECONSTRUCT_H__
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
/* Do not warn about wcsncpy usage.
|
||||
https://docs.microsoft.com/cpp/c-runtime-library/security-features-in-the-crt */
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "hidapi_winapi.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4200)
|
||||
#pragma warning(disable: 4201)
|
||||
#pragma warning(disable: 4214)
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "hidapi_hidsdi.h"
|
||||
/*#include <assert.h>*/
|
||||
|
||||
#define NUM_OF_HIDP_REPORT_TYPES 3
|
||||
|
||||
typedef enum rd_items_ {
|
||||
rd_main_input = 0x80, /* 1000 00 nn */
|
||||
rd_main_output = 0x90, /* 1001 00 nn */
|
||||
rd_main_feature = 0xB0, /* 1011 00 nn */
|
||||
rd_main_collection = 0xA0, /* 1010 00 nn */
|
||||
rd_main_collection_end = 0xC0, /* 1100 00 nn */
|
||||
rd_global_usage_page = 0x04, /* 0000 01 nn */
|
||||
rd_global_logical_minimum = 0x14, /* 0001 01 nn */
|
||||
rd_global_logical_maximum = 0x24, /* 0010 01 nn */
|
||||
rd_global_physical_minimum = 0x34, /* 0011 01 nn */
|
||||
rd_global_physical_maximum = 0x44, /* 0100 01 nn */
|
||||
rd_global_unit_exponent = 0x54, /* 0101 01 nn */
|
||||
rd_global_unit = 0x64, /* 0110 01 nn */
|
||||
rd_global_report_size = 0x74, /* 0111 01 nn */
|
||||
rd_global_report_id = 0x84, /* 1000 01 nn */
|
||||
rd_global_report_count = 0x94, /* 1001 01 nn */
|
||||
rd_global_push = 0xA4, /* 1010 01 nn */
|
||||
rd_global_pop = 0xB4, /* 1011 01 nn */
|
||||
rd_local_usage = 0x08, /* 0000 10 nn */
|
||||
rd_local_usage_minimum = 0x18, /* 0001 10 nn */
|
||||
rd_local_usage_maximum = 0x28, /* 0010 10 nn */
|
||||
rd_local_designator_index = 0x38, /* 0011 10 nn */
|
||||
rd_local_designator_minimum = 0x48, /* 0100 10 nn */
|
||||
rd_local_designator_maximum = 0x58, /* 0101 10 nn */
|
||||
rd_local_string = 0x78, /* 0111 10 nn */
|
||||
rd_local_string_minimum = 0x88, /* 1000 10 nn */
|
||||
rd_local_string_maximum = 0x98, /* 1001 10 nn */
|
||||
rd_local_delimiter = 0xA8 /* 1010 10 nn */
|
||||
} rd_items;
|
||||
|
||||
typedef enum rd_main_items_ {
|
||||
rd_input = HidP_Input,
|
||||
rd_output = HidP_Output,
|
||||
rd_feature = HidP_Feature,
|
||||
rd_collection,
|
||||
rd_collection_end,
|
||||
rd_delimiter_open,
|
||||
rd_delimiter_usage,
|
||||
rd_delimiter_close,
|
||||
} rd_main_items;
|
||||
|
||||
typedef struct rd_bit_range_ {
|
||||
int FirstBit;
|
||||
int LastBit;
|
||||
} rd_bit_range;
|
||||
|
||||
typedef enum rd_item_node_type_ {
|
||||
rd_item_node_cap,
|
||||
rd_item_node_padding,
|
||||
rd_item_node_collection,
|
||||
} rd_node_type;
|
||||
|
||||
struct rd_main_item_node {
|
||||
int FirstBit; /* Position of first bit in report (counting from 0) */
|
||||
int LastBit; /* Position of last bit in report (counting from 0) */
|
||||
rd_node_type TypeOfNode; /* Information if caps index refers to the array of button caps, value caps,
|
||||
or if the node is just a padding element to fill unused bit positions.
|
||||
The node can also be a collection node without any bits in the report. */
|
||||
int CapsIndex; /* Index in the array of caps */
|
||||
int CollectionIndex; /* Index in the array of link collections */
|
||||
rd_main_items MainItemType; /* Input, Output, Feature, Collection or Collection End */
|
||||
unsigned char ReportID;
|
||||
struct rd_main_item_node* next;
|
||||
};
|
||||
|
||||
typedef struct hid_pp_caps_info_ {
|
||||
USHORT FirstCap;
|
||||
USHORT NumberOfCaps; // Includes empty caps after LastCap
|
||||
USHORT LastCap;
|
||||
USHORT ReportByteLength;
|
||||
} hid_pp_caps_info, *phid_pp_caps_info;
|
||||
|
||||
typedef struct hid_pp_link_collection_node_ {
|
||||
USAGE LinkUsage;
|
||||
USAGE LinkUsagePage;
|
||||
USHORT Parent;
|
||||
USHORT NumberOfChildren;
|
||||
USHORT NextSibling;
|
||||
USHORT FirstChild;
|
||||
ULONG CollectionType : 8;
|
||||
ULONG IsAlias : 1;
|
||||
ULONG Reserved : 23;
|
||||
// Same as the public API structure HIDP_LINK_COLLECTION_NODE, but without PVOID UserContext at the end
|
||||
} hid_pp_link_collection_node, *phid_pp_link_collection_node;
|
||||
|
||||
// Note: This is risk-reduction-measure for this specific struct, as it has ULONG bit-field.
|
||||
// Although very unlikely, it might still be possible that the compiler creates a memory layout that is
|
||||
// not binary compatile.
|
||||
// Other structs are not checked at the time of writing.
|
||||
//static_assert(sizeof(struct hid_pp_link_collection_node_) == 16,
|
||||
// "Size of struct hid_pp_link_collection_node_ not as expected. This might break binary compatibility");
|
||||
SDL_COMPILE_TIME_ASSERT(hid_pp_link_collection_node_, sizeof(struct hid_pp_link_collection_node_) == 16);
|
||||
|
||||
typedef struct hidp_unknown_token_ {
|
||||
UCHAR Token; /* Specifies the one-byte prefix of a global item. */
|
||||
UCHAR Reserved[3];
|
||||
ULONG BitField; /* Specifies the data part of the global item. */
|
||||
} hidp_unknown_token, * phidp_unknown_token;
|
||||
|
||||
typedef struct hid_pp_cap_ {
|
||||
USAGE UsagePage;
|
||||
UCHAR ReportID;
|
||||
UCHAR BitPosition;
|
||||
USHORT ReportSize; // WIN32 term for this is BitSize
|
||||
USHORT ReportCount;
|
||||
USHORT BytePosition;
|
||||
USHORT BitCount;
|
||||
ULONG BitField;
|
||||
USHORT NextBytePosition;
|
||||
USHORT LinkCollection;
|
||||
USAGE LinkUsagePage;
|
||||
USAGE LinkUsage;
|
||||
|
||||
// Start of 8 Flags in one byte
|
||||
BOOLEAN IsMultipleItemsForArray:1;
|
||||
|
||||
BOOLEAN IsPadding:1;
|
||||
BOOLEAN IsButtonCap:1;
|
||||
BOOLEAN IsAbsolute:1;
|
||||
BOOLEAN IsRange:1;
|
||||
BOOLEAN IsAlias:1; // IsAlias is set to TRUE in the first n-1 capability structures added to the capability array. IsAlias set to FALSE in the nth capability structure.
|
||||
BOOLEAN IsStringRange:1;
|
||||
BOOLEAN IsDesignatorRange:1;
|
||||
// End of 8 Flags in one byte
|
||||
BOOLEAN Reserved1[3];
|
||||
|
||||
hidp_unknown_token UnknownTokens[4]; // 4 x 8 Byte
|
||||
|
||||
union {
|
||||
struct {
|
||||
USAGE UsageMin;
|
||||
USAGE UsageMax;
|
||||
USHORT StringMin;
|
||||
USHORT StringMax;
|
||||
USHORT DesignatorMin;
|
||||
USHORT DesignatorMax;
|
||||
USHORT DataIndexMin;
|
||||
USHORT DataIndexMax;
|
||||
} Range;
|
||||
struct {
|
||||
USAGE Usage;
|
||||
USAGE Reserved1;
|
||||
USHORT StringIndex;
|
||||
USHORT Reserved2;
|
||||
USHORT DesignatorIndex;
|
||||
USHORT Reserved3;
|
||||
USHORT DataIndex;
|
||||
USHORT Reserved4;
|
||||
} NotRange;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
LONG LogicalMin;
|
||||
LONG LogicalMax;
|
||||
} Button;
|
||||
struct {
|
||||
BOOLEAN HasNull;
|
||||
UCHAR Reserved4[3];
|
||||
LONG LogicalMin;
|
||||
LONG LogicalMax;
|
||||
LONG PhysicalMin;
|
||||
LONG PhysicalMax;
|
||||
} NotButton;
|
||||
};
|
||||
ULONG Units;
|
||||
ULONG UnitsExp;
|
||||
|
||||
} hid_pp_cap, *phid_pp_cap;
|
||||
|
||||
typedef struct hidp_preparsed_data_ {
|
||||
UCHAR MagicKey[8];
|
||||
USAGE Usage;
|
||||
USAGE UsagePage;
|
||||
USHORT Reserved[2];
|
||||
|
||||
// CAPS structure for Input, Output and Feature
|
||||
hid_pp_caps_info caps_info[3];
|
||||
|
||||
USHORT FirstByteOfLinkCollectionArray;
|
||||
USHORT NumberLinkCollectionNodes;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
// MINGW fails with: Flexible array member in union not supported
|
||||
// Solution: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
|
||||
union {
|
||||
#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
#endif
|
||||
hid_pp_cap caps[0];
|
||||
hid_pp_link_collection_node LinkCollectionArray[0];
|
||||
#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
};
|
||||
#else
|
||||
union {
|
||||
hid_pp_cap caps[];
|
||||
hid_pp_link_collection_node LinkCollectionArray[];
|
||||
};
|
||||
#endif
|
||||
|
||||
} hidp_preparsed_data;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
/*******************************************************
|
||||
HIDAPI - Multi-Platform library for
|
||||
communication with HID devices.
|
||||
|
||||
libusb/hidapi Team
|
||||
|
||||
Copyright 2022, All Rights Reserved.
|
||||
|
||||
At the discretion of the user of this library,
|
||||
this software may be licensed under the terms of the
|
||||
GNU General Public License v3, a BSD-Style license, or the
|
||||
original HIDAPI license as outlined in the LICENSE.txt,
|
||||
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
|
||||
files located at the root of the source distribution.
|
||||
These files may also be found in the public source
|
||||
code repository located at:
|
||||
https://github.com/libusb/hidapi .
|
||||
********************************************************/
|
||||
|
||||
#ifndef HIDAPI_HIDCLASS_H
|
||||
#define HIDAPI_HIDCLASS_H
|
||||
|
||||
#ifdef HIDAPI_USE_DDK
|
||||
|
||||
#include <hidclass.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <winioctl.h>
|
||||
|
||||
/* This part of the header mimics hidclass.h,
|
||||
but only what is used by HIDAPI */
|
||||
|
||||
#define HID_OUT_CTL_CODE(id) CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
|
||||
#define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100)
|
||||
#define IOCTL_HID_GET_INPUT_REPORT HID_OUT_CTL_CODE(104)
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HIDAPI_HIDCLASS_H */
|
||||
@@ -0,0 +1,72 @@
|
||||
/*******************************************************
|
||||
HIDAPI - Multi-Platform library for
|
||||
communication with HID devices.
|
||||
|
||||
libusb/hidapi Team
|
||||
|
||||
Copyright 2022, All Rights Reserved.
|
||||
|
||||
At the discretion of the user of this library,
|
||||
this software may be licensed under the terms of the
|
||||
GNU General Public License v3, a BSD-Style license, or the
|
||||
original HIDAPI license as outlined in the LICENSE.txt,
|
||||
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
|
||||
files located at the root of the source distribution.
|
||||
These files may also be found in the public source
|
||||
code repository located at:
|
||||
https://github.com/libusb/hidapi .
|
||||
********************************************************/
|
||||
|
||||
#ifndef HIDAPI_HIDPI_H
|
||||
#define HIDAPI_HIDPI_H
|
||||
|
||||
#ifdef HIDAPI_USE_DDK
|
||||
|
||||
#include <hidpi.h>
|
||||
|
||||
#else
|
||||
|
||||
/* This part of the header mimics hidpi.h,
|
||||
but only what is used by HIDAPI */
|
||||
|
||||
typedef enum _HIDP_REPORT_TYPE
|
||||
{
|
||||
HidP_Input,
|
||||
HidP_Output,
|
||||
HidP_Feature
|
||||
} HIDP_REPORT_TYPE;
|
||||
|
||||
typedef struct _HIDP_PREPARSED_DATA * PHIDP_PREPARSED_DATA;
|
||||
|
||||
typedef struct _HIDP_CAPS
|
||||
{
|
||||
USAGE Usage;
|
||||
USAGE UsagePage;
|
||||
USHORT InputReportByteLength;
|
||||
USHORT OutputReportByteLength;
|
||||
USHORT FeatureReportByteLength;
|
||||
USHORT Reserved[17];
|
||||
|
||||
USHORT NumberLinkCollectionNodes;
|
||||
|
||||
USHORT NumberInputButtonCaps;
|
||||
USHORT NumberInputValueCaps;
|
||||
USHORT NumberInputDataIndices;
|
||||
|
||||
USHORT NumberOutputButtonCaps;
|
||||
USHORT NumberOutputValueCaps;
|
||||
USHORT NumberOutputDataIndices;
|
||||
|
||||
USHORT NumberFeatureButtonCaps;
|
||||
USHORT NumberFeatureValueCaps;
|
||||
USHORT NumberFeatureDataIndices;
|
||||
} HIDP_CAPS, *PHIDP_CAPS;
|
||||
|
||||
#define HIDP_STATUS_SUCCESS 0x00110000
|
||||
#define HIDP_STATUS_INVALID_PREPARSED_DATA 0xc0110001
|
||||
|
||||
typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, PHIDP_CAPS caps);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HIDAPI_HIDPI_H */
|
||||
@@ -0,0 +1,59 @@
|
||||
/*******************************************************
|
||||
HIDAPI - Multi-Platform library for
|
||||
communication with HID devices.
|
||||
|
||||
libusb/hidapi Team
|
||||
|
||||
Copyright 2022, All Rights Reserved.
|
||||
|
||||
At the discretion of the user of this library,
|
||||
this software may be licensed under the terms of the
|
||||
GNU General Public License v3, a BSD-Style license, or the
|
||||
original HIDAPI license as outlined in the LICENSE.txt,
|
||||
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
|
||||
files located at the root of the source distribution.
|
||||
These files may also be found in the public source
|
||||
code repository located at:
|
||||
https://github.com/libusb/hidapi .
|
||||
********************************************************/
|
||||
|
||||
#ifndef HIDAPI_HIDSDI_H
|
||||
#define HIDAPI_HIDSDI_H
|
||||
|
||||
#ifdef HIDAPI_USE_DDK
|
||||
|
||||
#include <hidsdi.h>
|
||||
|
||||
#else
|
||||
|
||||
/* This part of the header mimics hidsdi.h,
|
||||
but only what is used by HIDAPI */
|
||||
|
||||
typedef USHORT USAGE;
|
||||
|
||||
#include "hidapi_hidpi.h"
|
||||
|
||||
typedef struct _HIDD_ATTRIBUTES{
|
||||
ULONG Size;
|
||||
USHORT VendorID;
|
||||
USHORT ProductID;
|
||||
USHORT VersionNumber;
|
||||
} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
|
||||
|
||||
typedef void (__stdcall *HidD_GetHidGuid_)(LPGUID hid_guid);
|
||||
typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);
|
||||
typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);
|
||||
typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
|
||||
typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
|
||||
typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length);
|
||||
typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length);
|
||||
typedef BOOLEAN (__stdcall *HidD_GetInputReport_)(HANDLE handle, PVOID data, ULONG length);
|
||||
typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len);
|
||||
typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);
|
||||
typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);
|
||||
typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
|
||||
typedef BOOLEAN (__stdcall *HidD_SetOutputReport_)(HANDLE HidDeviceObject, PVOID ReportBuffer, ULONG ReportBufferLength);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HIDAPI_HIDSDI_H */
|
||||
@@ -0,0 +1,74 @@
|
||||
/*******************************************************
|
||||
HIDAPI - Multi-Platform library for
|
||||
communication with HID devices.
|
||||
|
||||
libusb/hidapi Team
|
||||
|
||||
Copyright 2022, All Rights Reserved.
|
||||
|
||||
At the discretion of the user of this library,
|
||||
this software may be licensed under the terms of the
|
||||
GNU General Public License v3, a BSD-Style license, or the
|
||||
original HIDAPI license as outlined in the LICENSE.txt,
|
||||
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
|
||||
files located at the root of the source distribution.
|
||||
These files may also be found in the public source
|
||||
code repository located at:
|
||||
https://github.com/libusb/hidapi .
|
||||
********************************************************/
|
||||
|
||||
/** @file
|
||||
* @defgroup API hidapi API
|
||||
*
|
||||
* Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
|
||||
*/
|
||||
|
||||
#ifndef HIDAPI_WINAPI_H__
|
||||
#define HIDAPI_WINAPI_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <guiddef.h>
|
||||
|
||||
#include "../hidapi/hidapi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Get the container ID for a HID device.
|
||||
|
||||
Since version 0.12.0, @ref HID_API_VERSION >= HID_API_MAKE_VERSION(0, 12, 0)
|
||||
|
||||
This function returns the `DEVPKEY_Device_ContainerId` property of
|
||||
the given device. This can be used to correlate different
|
||||
interfaces/ports on the same hardware device.
|
||||
|
||||
@ingroup API
|
||||
@param dev A device handle returned from hid_open().
|
||||
@param container_id The device's container ID on return.
|
||||
|
||||
@returns
|
||||
This function returns 0 on success and -1 on error.
|
||||
*/
|
||||
int HID_API_EXPORT_CALL hid_winapi_get_container_id(hid_device *dev, GUID *container_id);
|
||||
|
||||
/**
|
||||
* @brief Reconstructs a HID Report Descriptor from a Win32 HIDP_PREPARSED_DATA structure.
|
||||
* This reconstructed report descriptor is logical identical to the real report descriptor,
|
||||
* but not byte wise identical.
|
||||
*
|
||||
* @param[in] hidp_preparsed_data Pointer to the HIDP_PREPARSED_DATA to read, i.e.: the value of PHIDP_PREPARSED_DATA,
|
||||
* as returned by HidD_GetPreparsedData WinAPI function.
|
||||
* @param buf Pointer to the buffer where the report descriptor should be stored.
|
||||
* @param[in] buf_size Size of the buffer. The recommended size for the buffer is @ref HID_API_MAX_REPORT_DESCRIPTOR_SIZE bytes.
|
||||
*
|
||||
* @return Returns size of reconstructed report descriptor if successful, -1 for error.
|
||||
*/
|
||||
int HID_API_EXPORT_CALL hid_winapi_descriptor_reconstruct_pp_data(void *hidp_preparsed_data, unsigned char *buf, size_t buf_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,176 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{23E9FF6A-49D1-4993-B2B5-BBB992C6C712}</ProjectGuid>
|
||||
<RootNamespace>hidtest</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='11'">v110</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='12'">v120</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='14'">v140</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='15'">v141</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='16'">v142</PlatformToolset>
|
||||
<PlatformToolset Condition="'$(VisualStudioVersion)'=='17'">v143</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>14.0.25431.1</_ProjectFileVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\hidapi;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<MinimalRebuild>true</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>hidapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\hidapi;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>hidapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\hidapi;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>hidapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\hidapi;.;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>hidapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(Configuration);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\hidtest\test.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="hidapi.vcxproj">
|
||||
<Project>{a107c21c-418a-4697-bb10-20c3aa60e2e4}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,15 @@
|
||||
project(pp_data_dump C)
|
||||
|
||||
add_executable(pp_data_dump pp_data_dump.c)
|
||||
set_target_properties(pp_data_dump
|
||||
PROPERTIES
|
||||
C_STANDARD 11
|
||||
C_STANDARD_REQUIRED TRUE
|
||||
)
|
||||
target_link_libraries(pp_data_dump
|
||||
PRIVATE hidapi_winapi
|
||||
)
|
||||
|
||||
install(TARGETS pp_data_dump
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
)
|
||||
@@ -0,0 +1,238 @@
|
||||
#if defined(__MINGW32__)
|
||||
// Needed for %hh
|
||||
#define __USE_MINGW_ANSI_STDIO 1
|
||||
#endif
|
||||
|
||||
#include <hid.c>
|
||||
#include <../windows/hidapi_descriptor_reconstruct.h>
|
||||
|
||||
#include <hidapi.h>
|
||||
|
||||
void dump_hid_pp_cap(FILE* file, phid_pp_cap pp_cap, unsigned int cap_idx) {
|
||||
fprintf(file, "pp_data->cap[%u]->UsagePage = 0x%04hX\n", cap_idx, pp_cap->UsagePage);
|
||||
fprintf(file, "pp_data->cap[%u]->ReportID = 0x%02hhX\n", cap_idx, pp_cap->ReportID);
|
||||
fprintf(file, "pp_data->cap[%u]->BitPosition = %hhu\n", cap_idx, pp_cap->BitPosition);
|
||||
fprintf(file, "pp_data->cap[%u]->BitSize = %hu\n", cap_idx, pp_cap->ReportSize);
|
||||
fprintf(file, "pp_data->cap[%u]->ReportCount = %hu\n", cap_idx, pp_cap->ReportCount);
|
||||
fprintf(file, "pp_data->cap[%u]->BytePosition = 0x%04hX\n", cap_idx, pp_cap->BytePosition);
|
||||
fprintf(file, "pp_data->cap[%u]->BitCount = %hu\n", cap_idx, pp_cap->BitCount);
|
||||
fprintf(file, "pp_data->cap[%u]->BitField = 0x%02lX\n", cap_idx, pp_cap->BitField);
|
||||
fprintf(file, "pp_data->cap[%u]->NextBytePosition = 0x%04hX\n", cap_idx, pp_cap->NextBytePosition);
|
||||
fprintf(file, "pp_data->cap[%u]->LinkCollection = 0x%04hX\n", cap_idx, pp_cap->LinkCollection);
|
||||
fprintf(file, "pp_data->cap[%u]->LinkUsagePage = 0x%04hX\n", cap_idx, pp_cap->LinkUsagePage);
|
||||
fprintf(file, "pp_data->cap[%u]->LinkUsage = 0x%04hX\n", cap_idx, pp_cap->LinkUsage);
|
||||
|
||||
// 8 Flags in one byte
|
||||
fprintf(file, "pp_data->cap[%u]->IsMultipleItemsForArray = %hhu\n", cap_idx, pp_cap->IsMultipleItemsForArray);
|
||||
fprintf(file, "pp_data->cap[%u]->IsButtonCap = %hhu\n", cap_idx, pp_cap->IsButtonCap);
|
||||
fprintf(file, "pp_data->cap[%u]->IsPadding = %hhu\n", cap_idx, pp_cap->IsPadding);
|
||||
fprintf(file, "pp_data->cap[%u]->IsAbsolute = %hhu\n", cap_idx, pp_cap->IsAbsolute);
|
||||
fprintf(file, "pp_data->cap[%u]->IsRange = %hhu\n", cap_idx, pp_cap->IsRange);
|
||||
fprintf(file, "pp_data->cap[%u]->IsAlias = %hhu\n", cap_idx, pp_cap->IsAlias);
|
||||
fprintf(file, "pp_data->cap[%u]->IsStringRange = %hhu\n", cap_idx, pp_cap->IsStringRange);
|
||||
fprintf(file, "pp_data->cap[%u]->IsDesignatorRange = %hhu\n", cap_idx, pp_cap->IsDesignatorRange);
|
||||
|
||||
fprintf(file, "pp_data->cap[%u]->Reserved1 = 0x%02hhX%02hhX%02hhX\n", cap_idx, pp_cap->Reserved1[0], pp_cap->Reserved1[1], pp_cap->Reserved1[2]);
|
||||
|
||||
for (int token_idx = 0; token_idx < 4; token_idx++) {
|
||||
fprintf(file, "pp_data->cap[%u]->pp_cap->UnknownTokens[%d].Token = 0x%02hhX\n", cap_idx, token_idx, pp_cap->UnknownTokens[token_idx].Token);
|
||||
fprintf(file, "pp_data->cap[%u]->pp_cap->UnknownTokens[%d].Reserved = 0x%02hhX%02hhX%02hhX\n", cap_idx, token_idx, pp_cap->UnknownTokens[token_idx].Reserved[0], pp_cap->UnknownTokens[token_idx].Reserved[1], pp_cap->UnknownTokens[token_idx].Reserved[2]);
|
||||
fprintf(file, "pp_data->cap[%u]->pp_cap->UnknownTokens[%d].BitField = 0x%08lX\n", cap_idx, token_idx, pp_cap->UnknownTokens[token_idx].BitField);
|
||||
}
|
||||
|
||||
if (pp_cap->IsRange) {
|
||||
fprintf(file, "pp_data->cap[%u]->Range.UsageMin = 0x%04hX\n", cap_idx, pp_cap->Range.UsageMin);
|
||||
fprintf(file, "pp_data->cap[%u]->Range.UsageMax = 0x%04hX\n", cap_idx, pp_cap->Range.UsageMax);
|
||||
fprintf(file, "pp_data->cap[%u]->Range.StringMin = %hu\n", cap_idx, pp_cap->Range.StringMin);
|
||||
fprintf(file, "pp_data->cap[%u]->Range.StringMax = %hu\n", cap_idx, pp_cap->Range.StringMax);
|
||||
fprintf(file, "pp_data->cap[%u]->Range.DesignatorMin = %hu\n", cap_idx, pp_cap->Range.DesignatorMin);
|
||||
fprintf(file, "pp_data->cap[%u]->Range.DesignatorMax = %hu\n", cap_idx, pp_cap->Range.DesignatorMax);
|
||||
fprintf(file, "pp_data->cap[%u]->Range.DataIndexMin = %hu\n", cap_idx, pp_cap->Range.DataIndexMin);
|
||||
fprintf(file, "pp_data->cap[%u]->Range.DataIndexMax = %hu\n", cap_idx, pp_cap->Range.DataIndexMax);
|
||||
}
|
||||
else {
|
||||
fprintf(file, "pp_data->cap[%u]->NotRange.Usage = 0x%04hX\n", cap_idx, pp_cap->NotRange.Usage);
|
||||
fprintf(file, "pp_data->cap[%u]->NotRange.Reserved1 = 0x%04hX\n", cap_idx, pp_cap->NotRange.Reserved1);
|
||||
fprintf(file, "pp_data->cap[%u]->NotRange.StringIndex = %hu\n", cap_idx, pp_cap->NotRange.StringIndex);
|
||||
fprintf(file, "pp_data->cap[%u]->NotRange.Reserved2 = %hu\n", cap_idx, pp_cap->NotRange.Reserved2);
|
||||
fprintf(file, "pp_data->cap[%u]->NotRange.DesignatorIndex = %hu\n", cap_idx, pp_cap->NotRange.DesignatorIndex);
|
||||
fprintf(file, "pp_data->cap[%u]->NotRange.Reserved3 = %hu\n", cap_idx, pp_cap->NotRange.Reserved3);
|
||||
fprintf(file, "pp_data->cap[%u]->NotRange.DataIndex = %hu\n", cap_idx, pp_cap->NotRange.DataIndex);
|
||||
fprintf(file, "pp_data->cap[%u]->NotRange.Reserved4 = %hu\n", cap_idx, pp_cap->NotRange.Reserved4);
|
||||
}
|
||||
|
||||
if (pp_cap->IsButtonCap) {
|
||||
fprintf(file, "pp_data->cap[%u]->Button.LogicalMin = %ld\n", cap_idx, pp_cap->Button.LogicalMin);
|
||||
fprintf(file, "pp_data->cap[%u]->Button.LogicalMax = %ld\n", cap_idx, pp_cap->Button.LogicalMax);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(file, "pp_data->cap[%u]->NotButton.HasNull = %hhu\n", cap_idx, pp_cap->NotButton.HasNull);
|
||||
fprintf(file, "pp_data->cap[%u]->NotButton.Reserved4 = 0x%02hhX%02hhX%02hhX\n", cap_idx, pp_cap->NotButton.Reserved4[0], pp_cap->NotButton.Reserved4[1], pp_cap->NotButton.Reserved4[2]);
|
||||
fprintf(file, "pp_data->cap[%u]->NotButton.LogicalMin = %ld\n", cap_idx, pp_cap->NotButton.LogicalMin);
|
||||
fprintf(file, "pp_data->cap[%u]->NotButton.LogicalMax = %ld\n", cap_idx, pp_cap->NotButton.LogicalMax);
|
||||
fprintf(file, "pp_data->cap[%u]->NotButton.PhysicalMin = %ld\n", cap_idx, pp_cap->NotButton.PhysicalMin);
|
||||
fprintf(file, "pp_data->cap[%u]->NotButton.PhysicalMax = %ld\n", cap_idx, pp_cap->NotButton.PhysicalMax);
|
||||
};
|
||||
fprintf(file, "pp_data->cap[%u]->Units = %lu\n", cap_idx, pp_cap->Units);
|
||||
fprintf(file, "pp_data->cap[%u]->UnitsExp = %lu\n", cap_idx, pp_cap->UnitsExp);
|
||||
}
|
||||
|
||||
void dump_hidp_link_collection_node(FILE* file, phid_pp_link_collection_node pcoll, unsigned int coll_idx) {
|
||||
fprintf(file, "pp_data->LinkCollectionArray[%u]->LinkUsage = 0x%04hX\n", coll_idx, pcoll->LinkUsage);
|
||||
fprintf(file, "pp_data->LinkCollectionArray[%u]->LinkUsagePage = 0x%04hX\n", coll_idx, pcoll->LinkUsagePage);
|
||||
fprintf(file, "pp_data->LinkCollectionArray[%u]->Parent = %hu\n", coll_idx, pcoll->Parent);
|
||||
fprintf(file, "pp_data->LinkCollectionArray[%u]->NumberOfChildren = %hu\n", coll_idx, pcoll->NumberOfChildren);
|
||||
fprintf(file, "pp_data->LinkCollectionArray[%u]->NextSibling = %hu\n", coll_idx, pcoll->NextSibling);
|
||||
fprintf(file, "pp_data->LinkCollectionArray[%u]->FirstChild = %hu\n", coll_idx, pcoll->FirstChild);
|
||||
// The compilers are not consistent on ULONG-bit-fields: They lose the unsinged or define them as int.
|
||||
// Thus just always cast them to unsinged int, which should be fine, as the biggest bit-field is 28 bit
|
||||
fprintf(file, "pp_data->LinkCollectionArray[%u]->CollectionType = %u\n", coll_idx, (unsigned int)(pcoll->CollectionType));
|
||||
fprintf(file, "pp_data->LinkCollectionArray[%u]->IsAlias = %u\n", coll_idx, (unsigned int)(pcoll->IsAlias));
|
||||
fprintf(file, "pp_data->LinkCollectionArray[%u]->Reserved = 0x%08X\n", coll_idx, (unsigned int)(pcoll->Reserved));
|
||||
}
|
||||
|
||||
int dump_pp_data(FILE* file, hid_device* dev)
|
||||
{
|
||||
BOOL res;
|
||||
hidp_preparsed_data* pp_data = NULL;
|
||||
|
||||
res = HidD_GetPreparsedData(dev->device_handle, (PHIDP_PREPARSED_DATA*) &pp_data);
|
||||
if (!res) {
|
||||
printf("ERROR: HidD_GetPreparsedData failed!");
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
fprintf(file, "pp_data->MagicKey = 0x%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX\n", pp_data->MagicKey[0], pp_data->MagicKey[1], pp_data->MagicKey[2], pp_data->MagicKey[3], pp_data->MagicKey[4], pp_data->MagicKey[5], pp_data->MagicKey[6], pp_data->MagicKey[7]);
|
||||
fprintf(file, "pp_data->Usage = 0x%04hX\n", pp_data->Usage);
|
||||
fprintf(file, "pp_data->UsagePage = 0x%04hX\n", pp_data->UsagePage);
|
||||
fprintf(file, "pp_data->Reserved = 0x%04hX%04hX\n", pp_data->Reserved[0], pp_data->Reserved[1]);
|
||||
fprintf(file, "# Input caps_info struct:\n");
|
||||
fprintf(file, "pp_data->caps_info[0]->FirstCap = %hu\n", pp_data->caps_info[0].FirstCap);
|
||||
fprintf(file, "pp_data->caps_info[0]->LastCap = %hu\n", pp_data->caps_info[0].LastCap);
|
||||
fprintf(file, "pp_data->caps_info[0]->NumberOfCaps = %hu\n", pp_data->caps_info[0].NumberOfCaps);
|
||||
fprintf(file, "pp_data->caps_info[0]->ReportByteLength = %hu\n", pp_data->caps_info[0].ReportByteLength);
|
||||
fprintf(file, "# Output caps_info struct:\n");
|
||||
fprintf(file, "pp_data->caps_info[1]->FirstCap = %hu\n", pp_data->caps_info[1].FirstCap);
|
||||
fprintf(file, "pp_data->caps_info[1]->LastCap = %hu\n", pp_data->caps_info[1].LastCap);
|
||||
fprintf(file, "pp_data->caps_info[1]->NumberOfCaps = %hu\n", pp_data->caps_info[1].NumberOfCaps);
|
||||
fprintf(file, "pp_data->caps_info[1]->ReportByteLength = %hu\n", pp_data->caps_info[1].ReportByteLength);
|
||||
fprintf(file, "# Feature caps_info struct:\n");
|
||||
fprintf(file, "pp_data->caps_info[2]->FirstCap = %hu\n", pp_data->caps_info[2].FirstCap);
|
||||
fprintf(file, "pp_data->caps_info[2]->LastCap = %hu\n", pp_data->caps_info[2].LastCap);
|
||||
fprintf(file, "pp_data->caps_info[2]->NumberOfCaps = %hu\n", pp_data->caps_info[2].NumberOfCaps);
|
||||
fprintf(file, "pp_data->caps_info[2]->ReportByteLength = %hu\n", pp_data->caps_info[2].ReportByteLength);
|
||||
fprintf(file, "# LinkCollectionArray Offset & Size:\n");
|
||||
fprintf(file, "pp_data->FirstByteOfLinkCollectionArray = 0x%04hX\n", pp_data->FirstByteOfLinkCollectionArray);
|
||||
fprintf(file, "pp_data->NumberLinkCollectionNodes = %hu\n", pp_data->NumberLinkCollectionNodes);
|
||||
|
||||
|
||||
phid_pp_cap pcap = (phid_pp_cap)(((unsigned char*)pp_data) + offsetof(hidp_preparsed_data, caps));
|
||||
fprintf(file, "# Input hid_pp_cap struct:\n");
|
||||
for (int caps_idx = pp_data->caps_info[0].FirstCap; caps_idx < pp_data->caps_info[0].LastCap; caps_idx++) {
|
||||
dump_hid_pp_cap(file, pcap + caps_idx, caps_idx);
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
fprintf(file, "# Output hid_pp_cap struct:\n");
|
||||
for (int caps_idx = pp_data->caps_info[1].FirstCap; caps_idx < pp_data->caps_info[1].LastCap; caps_idx++) {
|
||||
dump_hid_pp_cap(file, pcap + caps_idx, caps_idx);
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
fprintf(file, "# Feature hid_pp_cap struct:\n");
|
||||
for (int caps_idx = pp_data->caps_info[2].FirstCap; caps_idx < pp_data->caps_info[2].LastCap; caps_idx++) {
|
||||
dump_hid_pp_cap(file, pcap + caps_idx, caps_idx);
|
||||
fprintf(file, "\n");
|
||||
}
|
||||
|
||||
phid_pp_link_collection_node pcoll = (phid_pp_link_collection_node)(((unsigned char*)pcap) + pp_data->FirstByteOfLinkCollectionArray);
|
||||
fprintf(file, "# Link Collections:\n");
|
||||
for (int coll_idx = 0; coll_idx < pp_data->NumberLinkCollectionNodes; coll_idx++) {
|
||||
dump_hidp_link_collection_node(file, pcoll + coll_idx, coll_idx);
|
||||
}
|
||||
|
||||
HidD_FreePreparsedData((PHIDP_PREPARSED_DATA) pp_data);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
#define MAX_STR 255
|
||||
|
||||
struct hid_device_info *devs, *cur_dev;
|
||||
|
||||
printf("pp_data_dump tool. Compiled with hidapi version %s, runtime version %s.\n", HID_API_VERSION_STR, hid_version_str());
|
||||
if (hid_version()->major == HID_API_VERSION_MAJOR && hid_version()->minor == HID_API_VERSION_MINOR && hid_version()->patch == HID_API_VERSION_PATCH) {
|
||||
printf("Compile-time version matches runtime version of hidapi.\n\n");
|
||||
}
|
||||
else {
|
||||
printf("Compile-time version is different than runtime version of hidapi.\n]n");
|
||||
}
|
||||
|
||||
if (hid_init())
|
||||
return -1;
|
||||
|
||||
devs = hid_enumerate(0x0, 0x0);
|
||||
cur_dev = devs;
|
||||
while (cur_dev) {
|
||||
printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
|
||||
printf("\n");
|
||||
printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string);
|
||||
printf(" Product: %ls\n", cur_dev->product_string);
|
||||
printf(" Release: %hX\n", cur_dev->release_number);
|
||||
printf(" Interface: %d\n", cur_dev->interface_number);
|
||||
printf(" Usage (page): %02X (%02X)\n", cur_dev->usage, cur_dev->usage_page);
|
||||
|
||||
hid_device *device = hid_open_path(cur_dev->path);
|
||||
if (device) {
|
||||
char filename[MAX_STR];
|
||||
FILE* file;
|
||||
|
||||
sprintf_s(filename, MAX_STR, "%04X_%04X_%04X_%04X.pp_data", cur_dev->vendor_id, cur_dev->product_id, cur_dev->usage, cur_dev->usage_page);
|
||||
errno_t err = fopen_s(&file, filename, "w");
|
||||
if (err == 0) {
|
||||
fprintf(file, "# HIDAPI device info struct:\n");
|
||||
fprintf(file, "dev->vendor_id = 0x%04hX\n", cur_dev->vendor_id);
|
||||
fprintf(file, "dev->product_id = 0x%04hX\n", cur_dev->product_id);
|
||||
fprintf(file, "dev->manufacturer_string = \"%ls\"\n", cur_dev->manufacturer_string);
|
||||
fprintf(file, "dev->product_string = \"%ls\"\n", cur_dev->product_string);
|
||||
fprintf(file, "dev->release_number = 0x%04hX\n", cur_dev->release_number);
|
||||
fprintf(file, "dev->interface_number = %d\n", cur_dev->interface_number);
|
||||
fprintf(file, "dev->usage = 0x%04hX\n", cur_dev->usage);
|
||||
fprintf(file, "dev->usage_page = 0x%04hX\n", cur_dev->usage_page);
|
||||
fprintf(file, "dev->path = \"%s\"\n", cur_dev->path);
|
||||
fprintf(file, "\n# Preparsed Data struct:\n");
|
||||
int res = dump_pp_data(file, device);
|
||||
|
||||
if (res == 0) {
|
||||
printf("Dumped Preparsed Data to %s\n", filename);
|
||||
}
|
||||
else {
|
||||
printf("ERROR: Dump Preparsed Data to %s failed!\n", filename);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
hid_close(device);
|
||||
}
|
||||
else {
|
||||
printf(" Device: not available.\n");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
cur_dev = cur_dev->next;
|
||||
}
|
||||
hid_free_enumeration(devs);
|
||||
|
||||
|
||||
/* Free static HIDAPI objects. */
|
||||
hid_exit();
|
||||
|
||||
//system("pause");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
add_executable(hid_report_reconstructor_test hid_report_reconstructor_test.c)
|
||||
set_target_properties(hid_report_reconstructor_test
|
||||
PROPERTIES
|
||||
C_STANDARD 11
|
||||
C_STANDARD_REQUIRED TRUE
|
||||
)
|
||||
|
||||
target_link_libraries(hid_report_reconstructor_test
|
||||
PRIVATE hidapi_include hidapi_winapi
|
||||
)
|
||||
|
||||
# Each test case requires 2 files:
|
||||
# <name>.pp_data - textual representation of HIDP_PREPARSED_DATA;
|
||||
# <name>_expected.rpt_desc - reconstructed HID Report Descriptor out of .pp_data file;
|
||||
#
|
||||
# (Non-required by test):
|
||||
# <name>_real.dpt_desc - the original report rescriptor used to create a test case;
|
||||
set(HID_DESCRIPTOR_RECONSTRUCT_TEST_CASES
|
||||
046D_C52F_0001_000C
|
||||
046D_C52F_0001_FF00
|
||||
046D_C52F_0002_0001
|
||||
046D_C52F_0002_FF00
|
||||
17CC_1130_0000_FF01
|
||||
046D_0A37_0001_000C
|
||||
046A_0011_0006_0001
|
||||
046D_C077_0002_0001
|
||||
046D_C283_0004_0001
|
||||
046D_B010_0006_0001
|
||||
046D_B010_0002_FF00
|
||||
046D_B010_0002_0001
|
||||
046D_B010_0001_FF00
|
||||
046D_B010_0001_000C
|
||||
046D_C534_0001_000C
|
||||
046D_C534_0001_FF00
|
||||
046D_C534_0002_0001
|
||||
046D_C534_0002_FF00
|
||||
046D_C534_0006_0001
|
||||
046D_C534_0080_0001
|
||||
047F_C056_0001_000C
|
||||
047F_C056_0003_FFA0
|
||||
047F_C056_0005_000B
|
||||
045E_02FF_0005_0001
|
||||
)
|
||||
|
||||
set(CMAKE_VERSION_SUPPORTS_ENVIRONMENT_MODIFICATION "3.22")
|
||||
|
||||
if(HIDAPI_ENABLE_ASAN AND MSVC)
|
||||
if(CMAKE_VERSION VERSION_LESS CMAKE_VERSION_SUPPORTS_ENVIRONMENT_MODIFICATION)
|
||||
message("CTest/ASAN: Make sure to run ctest from MSVC Command Prompt")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
foreach(TEST_CASE ${HID_DESCRIPTOR_RECONSTRUCT_TEST_CASES})
|
||||
set(TEST_PP_DATA "${CMAKE_CURRENT_LIST_DIR}/data/${TEST_CASE}.pp_data")
|
||||
if(NOT EXISTS "${TEST_PP_DATA}")
|
||||
message(FATAL_ERROR "Missing '${TEST_PP_DATA}' file for '${TEST_CASE}' test case")
|
||||
endif()
|
||||
set(TEST_EXPECTED_DESCRIPTOR "${CMAKE_CURRENT_LIST_DIR}/data/${TEST_CASE}_expected.rpt_desc")
|
||||
if(NOT EXISTS "${TEST_EXPECTED_DESCRIPTOR}")
|
||||
message(FATAL_ERROR "Missing '${TEST_EXPECTED_DESCRIPTOR}' file for '${TEST_CASE}' test case")
|
||||
endif()
|
||||
|
||||
add_test(NAME "WinHidReportReconstructTest_${TEST_CASE}"
|
||||
COMMAND hid_report_reconstructor_test "${TEST_PP_DATA}" "${TEST_EXPECTED_DESCRIPTOR}"
|
||||
WORKING_DIRECTORY "$<TARGET_FILE_DIR:hidapi_winapi>"
|
||||
)
|
||||
if(HIDAPI_ENABLE_ASAN)
|
||||
if(MSVC)
|
||||
if(NOT CMAKE_VERSION VERSION_LESS CMAKE_VERSION_SUPPORTS_ENVIRONMENT_MODIFICATION)
|
||||
get_filename_component(MSVC_BUILD_TOOLS_DIR "${CMAKE_LINKER}" DIRECTORY)
|
||||
set_property(TEST "WinHidReportReconstructTest_${TEST_CASE}" PROPERTY ENVIRONMENT_MODIFICATION "PATH=path_list_append:${MSVC_BUILD_TOOLS_DIR}")
|
||||
endif()
|
||||
endif()
|
||||
set_property(TEST "WinHidReportReconstructTest_${TEST_CASE}" PROPERTY ENVIRONMENT "ASAN_SAVE_DUMPS=AsanDump_${TEST_CASE}.dmp")
|
||||
endif()
|
||||
endforeach()
|
||||
@@ -0,0 +1,563 @@
|
||||
#if defined(__MINGW32__)
|
||||
// Needed for %zu
|
||||
#define __USE_MINGW_ANSI_STDIO 1
|
||||
#endif
|
||||
|
||||
#include "../hidapi_descriptor_reconstruct.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static hidp_preparsed_data * alloc_preparsed_data_from_file(char* filename)
|
||||
{
|
||||
FILE* file;
|
||||
errno_t err = fopen_s(&file, filename, "r");
|
||||
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ERROR: Couldn't open file '%s' for reading: %s\n", filename, strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char line[256];
|
||||
|
||||
{
|
||||
unsigned short vendor_id = 0;
|
||||
unsigned short product_id = 0;
|
||||
unsigned short usage = 0;
|
||||
unsigned short usage_page = 0;
|
||||
unsigned short release_number = 0;
|
||||
int interface_number = -1;
|
||||
BOOLEAN header_read_success = FALSE;
|
||||
char manufacturer_string[128];
|
||||
manufacturer_string[0] = '\0';
|
||||
char product_string[128];
|
||||
product_string[0] = '\0';
|
||||
// char path[128];
|
||||
// path[0] = '\0';
|
||||
|
||||
while (fgets(line, sizeof(line), file) != NULL) {
|
||||
if (line[0] == '\r' || line[0] == '\n') {
|
||||
line[0] = '\0';
|
||||
}
|
||||
if (line[0] == '\0') {
|
||||
// read the 'metadata' only until the first empty line
|
||||
header_read_success = TRUE;
|
||||
break;
|
||||
}
|
||||
if (sscanf(line, "dev->vendor_id = 0x%04hX\n", &vendor_id)) continue;
|
||||
if (sscanf(line, "dev->product_id = 0x%04hX\n", &product_id)) continue;
|
||||
if (sscanf(line, "dev->usage_page = 0x%04hX\n", &usage_page)) continue;
|
||||
if (sscanf(line, "dev->usage = 0x%04hX\n", &usage)) continue;
|
||||
if (sscanf(line, "dev->manufacturer_string = \"%127[^\"\n]", manufacturer_string)) continue;
|
||||
if (sscanf(line, "dev->product_string = \"%127[^\"\n]", product_string)) continue;
|
||||
if (sscanf(line, "dev->release_number = 0x%04hX\n", &release_number)) continue;
|
||||
if (sscanf(line, "dev->interface_number = %d\n", &interface_number)) continue;
|
||||
// if (sscanf(line, "dev->path = \"%127[^\"]\n", path)) continue;
|
||||
}
|
||||
if (!header_read_success) {
|
||||
fprintf(stderr, "ERROR: Couldn't read PP Data header (missing newline)\n");
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
printf("'Virtual' Device Read: %04hx %04hx\n", vendor_id, product_id);
|
||||
if (manufacturer_string[0] != '\0') {
|
||||
printf(" Manufacturer: %s\n", manufacturer_string);
|
||||
}
|
||||
if (product_string[0] != '\0') {
|
||||
printf(" Product: %s\n", product_string);
|
||||
}
|
||||
printf(" Release: %hx\n", release_number);
|
||||
printf(" Interface: %d\n", interface_number);
|
||||
printf(" Usage (page): 0x%hx (0x%hx)\n", usage, usage_page);
|
||||
}
|
||||
|
||||
hidp_preparsed_data static_pp_data;
|
||||
memset(&static_pp_data, 0, sizeof(static_pp_data));
|
||||
hidp_preparsed_data *pp_data = &static_pp_data;
|
||||
|
||||
unsigned int rt_idx;
|
||||
unsigned int caps_idx;
|
||||
unsigned int token_idx;
|
||||
unsigned int coll_idx;
|
||||
USAGE temp_usage;
|
||||
BOOLEAN temp_boolean[3];
|
||||
UCHAR temp_uchar[3];
|
||||
USHORT temp_ushort;
|
||||
ULONG temp_ulong;
|
||||
LONG temp_long;
|
||||
|
||||
USHORT FirstByteOfLinkCollectionArray = 0;
|
||||
USHORT NumberLinkCollectionNodes = 0;
|
||||
|
||||
while (fgets(line, sizeof(line), file) != NULL) {
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
|
||||
if (FirstByteOfLinkCollectionArray != 0 && NumberLinkCollectionNodes != 0) {
|
||||
size_t size_of_preparsed_data = offsetof(hidp_preparsed_data, caps) + FirstByteOfLinkCollectionArray + (NumberLinkCollectionNodes * sizeof(hid_pp_link_collection_node));
|
||||
pp_data->FirstByteOfLinkCollectionArray = FirstByteOfLinkCollectionArray;
|
||||
pp_data->NumberLinkCollectionNodes = NumberLinkCollectionNodes;
|
||||
FirstByteOfLinkCollectionArray = 0;
|
||||
NumberLinkCollectionNodes = 0;
|
||||
pp_data = malloc(size_of_preparsed_data);
|
||||
memcpy(pp_data, &static_pp_data, sizeof(static_pp_data));
|
||||
}
|
||||
|
||||
if (sscanf(line, "pp_data->MagicKey = 0x%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX\n", &pp_data->MagicKey[0], &pp_data->MagicKey[1], &pp_data->MagicKey[2], &pp_data->MagicKey[3], &pp_data->MagicKey[4], &pp_data->MagicKey[5], &pp_data->MagicKey[6], &pp_data->MagicKey[7])) continue;
|
||||
if (sscanf(line, "pp_data->Usage = 0x%04hX\n", &pp_data->Usage)) continue;
|
||||
if (sscanf(line, "pp_data->UsagePage = 0x%04hX\n", &pp_data->UsagePage)) continue;
|
||||
if (sscanf(line, "pp_data->Reserved = 0x%04hX%04hX\n", &pp_data->Reserved[0], &pp_data->Reserved[1])) continue;
|
||||
|
||||
if (sscanf(line, "pp_data->caps_info[%u]", &rt_idx) == 1) {
|
||||
const size_t caps_info_count = sizeof(pp_data->caps_info) / sizeof(pp_data->caps_info[0]);
|
||||
if (rt_idx >= caps_info_count) {
|
||||
fprintf(stderr, "Broken pp_data file, pp_data->caps_info[<idx>] can have at most %zu elements, accessing %ud, (%s)", caps_info_count, rt_idx, line);
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->caps_info[%u]->FirstCap = %hu\n", &rt_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps_info[rt_idx].FirstCap = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->caps_info[%u]->LastCap = %hu\n", &rt_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps_info[rt_idx].LastCap = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->caps_info[%u]->NumberOfCaps = %hu\n", &rt_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps_info[rt_idx].NumberOfCaps = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->caps_info[%u]->ReportByteLength = %hu\n", &rt_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps_info[rt_idx].ReportByteLength = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "Ignoring unimplemented caps_info field: %s", line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sscanf(line, "pp_data->FirstByteOfLinkCollectionArray = 0x%04hX\n", &FirstByteOfLinkCollectionArray)) {
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->NumberLinkCollectionNodes = %hu\n", &NumberLinkCollectionNodes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sscanf(line, "pp_data->cap[%u]", &caps_idx) == 1) {
|
||||
if (pp_data->FirstByteOfLinkCollectionArray == 0) {
|
||||
fprintf(stderr, "Error reading pp_data file (%s): FirstByteOfLinkCollectionArray is 0 or not reported yet\n", line);
|
||||
continue;
|
||||
}
|
||||
if ((caps_idx + 1) * sizeof(hid_pp_cap) > pp_data->FirstByteOfLinkCollectionArray) {
|
||||
fprintf(stderr, "Error reading pp_data file (%s): the caps index (%u) is out of pp_data bytes boundary (%hu vs %hu)\n", line, caps_idx, (unsigned short) ((caps_idx + 1) * sizeof(hid_pp_cap)), pp_data->FirstByteOfLinkCollectionArray);
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->UsagePage = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
|
||||
pp_data->caps[caps_idx].UsagePage = temp_usage;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->ReportID = 0x%02hhX\n", &caps_idx, &temp_uchar[0]) == 2) {
|
||||
pp_data->caps[caps_idx].ReportID = temp_uchar[0];
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->BitPosition = %hhu\n", &caps_idx, &temp_uchar[0]) == 2) {
|
||||
pp_data->caps[caps_idx].BitPosition = temp_uchar[0];
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->BitSize = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].ReportSize = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->ReportCount = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].ReportCount = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->BytePosition = 0x%04hX\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].BytePosition = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->BitCount = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].BitCount = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->BitField = 0x%02lX\n", &caps_idx, &temp_ulong) == 2) {
|
||||
pp_data->caps[caps_idx].BitField = temp_ulong;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->NextBytePosition = 0x%04hX\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].NextBytePosition = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->LinkCollection = 0x%04hX\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].LinkCollection = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->LinkUsagePage = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
|
||||
pp_data->caps[caps_idx].LinkUsagePage = temp_usage;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->LinkUsage = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
|
||||
pp_data->caps[caps_idx].LinkUsage = temp_usage;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 8 Flags in one byte
|
||||
if (sscanf(line, "pp_data->cap[%u]->IsMultipleItemsForArray = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
|
||||
pp_data->caps[caps_idx].IsMultipleItemsForArray = temp_boolean[0];
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->IsButtonCap = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
|
||||
pp_data->caps[caps_idx].IsButtonCap = temp_boolean[0];
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->IsPadding = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
|
||||
pp_data->caps[caps_idx].IsPadding = temp_boolean[0];
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->IsAbsolute = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
|
||||
pp_data->caps[caps_idx].IsAbsolute = temp_boolean[0];
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->IsRange = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
|
||||
pp_data->caps[caps_idx].IsRange = temp_boolean[0];
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->IsAlias = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
|
||||
pp_data->caps[caps_idx].IsAlias = temp_boolean[0];
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->IsStringRange = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
|
||||
pp_data->caps[caps_idx].IsStringRange = temp_boolean[0];
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->IsDesignatorRange = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
|
||||
pp_data->caps[caps_idx].IsDesignatorRange = temp_boolean[0];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sscanf(line, "pp_data->cap[%u]->Reserved1 = 0x%hhu%hhu%hhu\n", &caps_idx, &temp_uchar[0], &temp_uchar[1], &temp_uchar[2]) == 4) {
|
||||
pp_data->caps[caps_idx].Reserved1[0] = temp_uchar[0];
|
||||
pp_data->caps[caps_idx].Reserved1[1] = temp_uchar[1];
|
||||
pp_data->caps[caps_idx].Reserved1[2] = temp_uchar[2];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sscanf(line, "pp_data->cap[%u]->pp_cap->UnknownTokens[%u]", &caps_idx, &token_idx) == 2) {
|
||||
const size_t unknown_tokens_count = sizeof(pp_data->caps[0].UnknownTokens) / sizeof(pp_data->caps[0].UnknownTokens[0]);
|
||||
if (token_idx >= unknown_tokens_count) {
|
||||
fprintf(stderr, "Broken pp_data file, pp_data->caps[<idx>].UnknownTokens[<idx>] can have at most %zu elements, accessing %ud, (%s)", unknown_tokens_count, token_idx, line);
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->pp_cap->UnknownTokens[%u].Token = 0x%02hhX\n", &caps_idx, &token_idx, &temp_uchar[0]) == 3) {
|
||||
pp_data->caps[caps_idx].UnknownTokens[token_idx].Token = temp_uchar[0];
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->pp_cap->UnknownTokens[%u].Reserved = 0x%02hhX%02hhX%02hhX\n", &caps_idx, &token_idx, &temp_uchar[0], &temp_uchar[1], &temp_uchar[2]) == 5) {
|
||||
pp_data->caps[caps_idx].UnknownTokens[token_idx].Reserved[0] = temp_uchar[0];
|
||||
pp_data->caps[caps_idx].UnknownTokens[token_idx].Reserved[1] = temp_uchar[1];
|
||||
pp_data->caps[caps_idx].UnknownTokens[token_idx].Reserved[2] = temp_uchar[2];
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->pp_cap->UnknownTokens[%u].BitField = 0x%08lX\n", &caps_idx, &token_idx, &temp_ulong) == 3) {
|
||||
pp_data->caps[caps_idx].UnknownTokens[token_idx].BitField = temp_ulong;
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "Ignoring unimplemented pp_data->cap[]->pp_cap->UnknownTokens field: %s", line);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Range
|
||||
if (sscanf(line, "pp_data->cap[%u]->Range.UsageMin = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
|
||||
pp_data->caps[caps_idx].Range.UsageMin = temp_usage;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->Range.UsageMax = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
|
||||
pp_data->caps[caps_idx].Range.UsageMax = temp_usage;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->Range.StringMin = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].Range.StringMin = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->Range.StringMax = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].Range.StringMax = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->Range.DesignatorMin = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].Range.DesignatorMin = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->Range.DesignatorMax = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].Range.DesignatorMax = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->Range.DataIndexMin = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].Range.DataIndexMin = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->Range.DataIndexMax = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].Range.DataIndexMax = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
|
||||
// NotRange
|
||||
if (sscanf(line, "pp_data->cap[%u]->NotRange.Usage = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
|
||||
pp_data->caps[caps_idx].NotRange.Usage = temp_usage;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->NotRange.Reserved1 = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
|
||||
pp_data->caps[caps_idx].NotRange.Reserved1 = temp_usage;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->NotRange.StringIndex = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].NotRange.StringIndex = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->NotRange.Reserved2 = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].NotRange.Reserved2 = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->NotRange.DesignatorIndex = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].NotRange.DesignatorIndex = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->NotRange.Reserved3 = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].NotRange.Reserved3 = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->NotRange.DataIndex = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].NotRange.DataIndex = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->NotRange.Reserved4 = %hu\n", &caps_idx, &temp_ushort) == 2) {
|
||||
pp_data->caps[caps_idx].NotRange.Reserved4 = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Button
|
||||
if (sscanf(line, "pp_data->cap[%u]->Button.LogicalMin = %ld\n", &caps_idx, &temp_long) == 2) {
|
||||
pp_data->caps[caps_idx].Button.LogicalMin = temp_long;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->Button.LogicalMax = %ld\n", &caps_idx, &temp_long) == 2) {
|
||||
pp_data->caps[caps_idx].Button.LogicalMax = temp_long;
|
||||
continue;
|
||||
}
|
||||
|
||||
// NotButton
|
||||
if (sscanf(line, "pp_data->cap[%u]->NotButton.HasNull = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
|
||||
pp_data->caps[caps_idx].NotButton.HasNull = temp_boolean[0];
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->NotButton.Reserved4 = 0x%02hhX%02hhX%02hhX\n", &caps_idx, &temp_uchar[0], &temp_uchar[1], &temp_uchar[2]) == 4) {
|
||||
pp_data->caps[caps_idx].NotButton.Reserved4[0] = temp_uchar[0];
|
||||
pp_data->caps[caps_idx].NotButton.Reserved4[1] = temp_uchar[1];
|
||||
pp_data->caps[caps_idx].NotButton.Reserved4[2] = temp_uchar[2];
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->NotButton.LogicalMin = %ld\n", &caps_idx, &temp_long) == 2) {
|
||||
pp_data->caps[caps_idx].NotButton.LogicalMin = temp_long;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->NotButton.LogicalMax = %ld\n", &caps_idx, &temp_long) == 2) {
|
||||
pp_data->caps[caps_idx].NotButton.LogicalMax = temp_long;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->NotButton.PhysicalMin = %ld\n", &caps_idx, &temp_long) == 2) {
|
||||
pp_data->caps[caps_idx].NotButton.PhysicalMin = temp_long;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->NotButton.PhysicalMax = %ld\n", &caps_idx, &temp_long) == 2) {
|
||||
pp_data->caps[caps_idx].NotButton.PhysicalMax = temp_long;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sscanf(line, "pp_data->cap[%u]->Units = %lu\n", &caps_idx, &temp_ulong) == 2) {
|
||||
pp_data->caps[caps_idx].Units = temp_ulong;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->UnitsExp = %lu\n", &caps_idx, &temp_ulong) == 2) {
|
||||
pp_data->caps[caps_idx].UnitsExp = temp_ulong;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->cap[%u]->Reserved1 = 0x%02hhu%02hhu%02hhu\n", &coll_idx, &temp_uchar[0], &temp_uchar[1], &temp_uchar[2]) == 4) {
|
||||
pp_data->caps[caps_idx].Reserved1[0] = temp_uchar[0];
|
||||
pp_data->caps[caps_idx].Reserved1[1] = temp_uchar[1];
|
||||
pp_data->caps[caps_idx].Reserved1[2] = temp_uchar[2];
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "Ignoring unimplemented cap field: %s", line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sscanf(line, "pp_data->LinkCollectionArray[%u]", &coll_idx) == 1) {
|
||||
if (pp_data->FirstByteOfLinkCollectionArray == 0 || pp_data->NumberLinkCollectionNodes == 0) {
|
||||
fprintf(stderr, "Error reading pp_data file (%s): FirstByteOfLinkCollectionArray or NumberLinkCollectionNodes is 0 or not reported yet\n", line);
|
||||
continue;
|
||||
}
|
||||
if (coll_idx >= pp_data->NumberLinkCollectionNodes) {
|
||||
fprintf(stderr, "Error reading pp_data file (%s): the LinkCollection index (%u) is out of boundary (%hu)\n", line, coll_idx, pp_data->NumberLinkCollectionNodes);
|
||||
continue;
|
||||
}
|
||||
phid_pp_link_collection_node pcoll = (phid_pp_link_collection_node)(((unsigned char*)&pp_data->caps[0]) + pp_data->FirstByteOfLinkCollectionArray);
|
||||
if (sscanf(line, "pp_data->LinkCollectionArray[%u]->LinkUsage = 0x%04hX\n", &coll_idx, &temp_usage) == 2) {
|
||||
pcoll[coll_idx].LinkUsage = temp_usage;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->LinkCollectionArray[%u]->LinkUsagePage = 0x%04hX\n", &coll_idx, &temp_usage) == 2) {
|
||||
pcoll[coll_idx].LinkUsagePage = temp_usage;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->LinkCollectionArray[%u]->Parent = %hu\n", &coll_idx, &temp_ushort) == 2) {
|
||||
pcoll[coll_idx].Parent = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->LinkCollectionArray[%u]->NumberOfChildren = %hu\n", &coll_idx, &temp_ushort) == 2) {
|
||||
pcoll[coll_idx].NumberOfChildren = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->LinkCollectionArray[%u]->NextSibling = %hu\n", &coll_idx, &temp_ushort) == 2) {
|
||||
pcoll[coll_idx].NextSibling = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->LinkCollectionArray[%u]->FirstChild = %hu\n", &coll_idx, &temp_ushort) == 2) {
|
||||
pcoll[coll_idx].FirstChild = temp_ushort;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->LinkCollectionArray[%u]->CollectionType = %lu\n", &coll_idx, &temp_ulong) == 2) {
|
||||
pcoll[coll_idx].CollectionType = temp_ulong;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->LinkCollectionArray[%u]->IsAlias = %lu\n", &coll_idx, &temp_ulong) == 2) {
|
||||
pcoll[coll_idx].IsAlias = temp_ulong;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "pp_data->LinkCollectionArray[%u]->Reserved = %lu\n", &coll_idx, &temp_ulong) == 2) {
|
||||
pcoll[coll_idx].Reserved = temp_ulong;
|
||||
continue;
|
||||
}
|
||||
fprintf(stderr, "Ignoring unimplemented LinkCollectionArray field: %s", line);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//end:
|
||||
fclose(file);
|
||||
|
||||
if (pp_data == &static_pp_data) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pp_data;
|
||||
}
|
||||
|
||||
static BOOLEAN read_hex_data_from_text_file(const char *filename, unsigned char *data_out, size_t data_size, size_t *actual_read)
|
||||
{
|
||||
size_t read_index = 0;
|
||||
FILE* file = NULL;
|
||||
errno_t err = fopen_s(&file, filename, "r");
|
||||
if (err != 0) {
|
||||
fprintf(stderr, "ERROR: Couldn't open file '%s' for reading: %s\n", filename, strerror(err));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOLEAN result = TRUE;
|
||||
unsigned int val;
|
||||
char buf[16];
|
||||
while (fscanf(file, "%15s", buf) == 1) {
|
||||
if (sscanf(buf, "0x%X", &val) != 1) {
|
||||
fprintf(stderr, "Invalid HEX text ('%s') file, got %s\n", filename, buf);
|
||||
result = FALSE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (read_index >= data_size) {
|
||||
fprintf(stderr, "Buffer for file read is too small. Got only %zu bytes to read '%s'\n", data_size, filename);
|
||||
result = FALSE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (val > (unsigned char)-1) {
|
||||
fprintf(stderr, "Invalid HEX text ('%s') file, got a value of: %u\n", filename, val);
|
||||
result = FALSE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
data_out[read_index] = (unsigned char) val;
|
||||
|
||||
read_index++;
|
||||
}
|
||||
|
||||
if (!feof(file)) {
|
||||
fprintf(stderr, "Invalid HEX text ('%s') file - failed to read all values\n", filename);
|
||||
result = FALSE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
*actual_read = read_index;
|
||||
|
||||
end:
|
||||
fclose(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Expected 2 arguments for the test ('<>.pp_data' and '<>_expected.rpt_desc'), got: %d\n", argc - 1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("Checking: '%s' / '%s'\n", argv[1], argv[2]);
|
||||
|
||||
hidp_preparsed_data *pp_data = alloc_preparsed_data_from_file(argv[1]);
|
||||
if (pp_data == NULL) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
int result = EXIT_SUCCESS;
|
||||
|
||||
unsigned char report_descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE];
|
||||
|
||||
int res = hid_winapi_descriptor_reconstruct_pp_data(pp_data, report_descriptor, sizeof(report_descriptor));
|
||||
|
||||
if (res < 0) {
|
||||
result = EXIT_FAILURE;
|
||||
fprintf(stderr, "Failed to reconstruct descriptor");
|
||||
goto end;
|
||||
}
|
||||
size_t report_descriptor_size = (size_t) res;
|
||||
|
||||
unsigned char expected_report_descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE];
|
||||
size_t expected_report_descriptor_size = 0;
|
||||
if (!read_hex_data_from_text_file(argv[2], expected_report_descriptor, sizeof(expected_report_descriptor), &expected_report_descriptor_size)) {
|
||||
result = EXIT_FAILURE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (report_descriptor_size == expected_report_descriptor_size) {
|
||||
if (memcmp(report_descriptor, expected_report_descriptor, report_descriptor_size) == 0) {
|
||||
printf("Reconstructed Report Descriptor matches the expected descriptor\n");
|
||||
goto end;
|
||||
}
|
||||
else {
|
||||
result = EXIT_FAILURE;
|
||||
fprintf(stderr, "Reconstructed Report Descriptor has different content than expected\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = EXIT_FAILURE;
|
||||
fprintf(stderr, "Reconstructed Report Descriptor has different size: %zu when expected %zu\n", report_descriptor_size, expected_report_descriptor_size);
|
||||
}
|
||||
|
||||
printf(" Reconstructed Report Descriptor:\n");
|
||||
for (int i = 0; i < res; i++) {
|
||||
printf("0x%02X, ", report_descriptor[i]);
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
|
||||
end:
|
||||
free(pp_data);
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user