aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING340
-rw-r--r--Makefile25
-rw-r--r--README13
-rw-r--r--TODO275
-rw-r--r--hidio-help.pd589
-rw-r--r--hidio.c485
-rw-r--r--hidio.h153
-rw-r--r--hidio_darwin.c1468
-rw-r--r--hidio_linux.c648
-rw-r--r--hidio_windows.c337
-rw-r--r--input_arrays.c463
-rw-r--r--input_arrays.h42
-rw-r--r--linux/input.h1016
-rwxr-xr-xmake-arrays-from-input.h.pl321
14 files changed, 6175 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..7f87ef8
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) 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
+this service 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 make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. 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.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR PDP.LICENSE, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE 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.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: 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
+convey 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) 19yy <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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision 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, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This 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 Library General
+Public License instead of this License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..341c55b
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,25 @@
+TARGET := $(shell pwd | sed 's|.*/\(.*\)$$|\1|')
+EXTERNALS_ROOT := $(shell pwd | sed 's|^\(/.*externals\).*|\1|')
+
+default:
+ make -C $(EXTERNALS_ROOT) $(TARGET)
+
+install:
+ make -C $(EXTERNALS_ROOT) $(TARGET)_install
+
+clean:
+ make -C $(EXTERNALS_ROOT) $(TARGET)_clean
+
+test_locations:
+ make -C $(EXTERNALS_ROOT) test_locations
+
+# for emacs
+etags:
+ make etags_`uname -s`
+
+etags_Darwin:
+ etags *.[ch] linux/input.h HID\ Utilities\ Source/*.[ch] \
+ /System/Library/Frameworks/IOKit.framework/Headers/hid*/*.[ch]
+
+etags_Linux:
+ etags *.[ch] /usr/include/*.h linux/input.h /usr/include/sys/*.h
diff --git a/README b/README
new file mode 100644
index 0000000..d1e5e22
--- /dev/null
+++ b/README
@@ -0,0 +1,13 @@
+
+[hidio]
+
+This is the next generation of HID API for Pd and Max/MSP. The aim is to have
+this object perform the same on Pd on GNU/Linux, Mac OS X, and Windows, and
+Max/MSP on Mac OS X and Windows.
+
+David Merrill <dmerrill@media.mit.edu>
+Hans-Christoph Steiner <hans@eds.org>
+Olaf Matthes <olaf@nullmedium.de>
+
+
+
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..f3e32e2
--- /dev/null
+++ b/TODO
@@ -0,0 +1,275 @@
+
+______________________________________________________________________________
+- switch to snprintf
+
+in hid_darwin.c, replace all sprintf()s with snprintf()s.
+
+______________________________________________________________________________
+- deal with hatswitches!!
+
+Because of the currnently implementation of the conversion of the MacOS X
+style event to the Linux style event, an event with a value of zero is output
+on the unchanged axis when the hatswitch is moved in along the X or Y axis (as
+opposed to diagonally). but this might be fixed...
+
+- fix up hatswitch logic... hmmm
+ on Mac OS X, just make the next element in the array always be the Y axis of
+ the hatswitch, then when receiving a hatswitch event, output, increment,
+ then output again (yes, its a hack).
+
+- what do standard hatswitches output on the various platforms? they should
+ probably always output like axes, but then the CUI will be screwed
+
+
+______________________________________________________________________________
+= fix key names on Mac OS X
+
+I think they are unimplemented... :-(
+
+______________________________________________________________________________
+= array lookups for symbols
+
+implementation idea #2:
+
+this array should be built by hid_build_elements_list(). Then each time it
+fetches an event using the element_pointer array, it would also get the stored
+usage_page and usage symbols, and instance t_float. So I need to make an
+element struct like:
+
+struct _hid_element
+{
+ void *element;
+ t_symbol *type; // HID "usage page"
+ t_symbol *usage; // Linux "code"
+ t_float instance;
+ t_float previous_value; //only output on change on abs and buttons
+} t_hid_element;
+
+For Linux input.h, instead void *element, store the type and code numbers to
+compare against
+
+
+______________________________________________________________________________
+= make only the first executed instance fetch the data
+
+ the function is ugen_getsortno() -- returns
+an integer which increases eachtime DSP is restarted. You can add the
+function call (to the ugen chain for instance) each time you see
+ugen_getsortno() return an integer greater than the previous one you've
+
+______________________________________________________________________________
+= output one value per poll
+
+- for relative axes, sum up all events and output one
+http://lists.apple.com/archives/mac-games-dev/2005/Oct/msg00060.html
+
+- current method only works for instances in the same patch...
+
+______________________________________________________________________________
+= [poll 1( message set to exact delay based on block size
+
+to eliminate the jitter of the messages being processed every block, have
+[poll 1( set the time to the poll size (~1.5ms for 44,100)
+
+______________________________________________________________________________
+= iterate through elements and do a proper queue of the ones we want:
+
+- also, label multiple instances of the same usage
+
+http://mud.5341.com/msg/8455.html
+
+
+______________________________________________________________________________
+= make second inlet for specific status requests [human->pd])
+
+- [vendor(, [product(
+- [range(
+- [poll(
+- [name(
+- [type(
+
+______________________________________________________________________________
+= output device data on open
+
+- Logical Min/Max i.e. [range -127 127(
+- device string [name Trackpad(
+
+______________________________________________________________________________
+= get tablets working on Mac OS X
+
+http://www.versiontracker.com/php/feedback/article.php?story=20051221163326829
+
+http://www.wacom-europe.com/forum/topic.asp?TOPIC_ID=2719&ARCHIVE=
+
+______________________________________________________________________________
+= block devices like mice/keyboards etc from outputting
+
+at least document the procedure needed
+
+Mac OS X:
+http://lists.apple.com/archives/usb/2005/Aug/msg00068.html
+
+
+
+______________________________________________________________________________
+= open devices by name
+
+i.e "Trackpad" a la Max's [hi]
+
+
+______________________________________________________________________________
+=
+= autoscaling based on Logical min/max
+
+- this is probably essential for input, the question is how to find out what
+ the data range is easily.
+
+- output would be handy, rather than autoscale, to save on CPU
+
+- this should probably be done in Pd space
+
+______________________________________________________________________________
+= test verbose names
+
+- matju says symbols are compared by pointer, so they are fast
+
+- try verbose names like:
+ syn = sync
+ snd = sound
+ msc = misc
+ rep = repeat
+ pwr = power
+
+- maybe these too
+ abs = absolute
+ rel = relative
+ btn = button
+
+- maybe make the type the full name, with the code using the abbreviation
+
+- change generic ev_9 to type_9
+
+- change word "code" to "element"
+
+
+______________________________________________________________________________
+= event name changes
+
+- make key/button Type "button" rather than "key" (undecided on this one)
+
+
+______________________________________________________________________________
+= hid/serial
+
+- open/close status outlet
+
+- [send ( to send data
+
+- [tgl] 1/0 for open/close
+
+
+______________________________________________________________________________
+= linux input synch events (EV_SYN)
+
+- these seem to be generated by the Linux kernel, so they probably don't fit
+ in with the [hid] scheme. Probably the best thing is to ditch them, or
+ figure out whether they should be used in controlling the flow of event
+ data, as they are intended.
+
+
+______________________________________________________________________________
+= writing support!
+
+- Linux example: http://www.linuxjournal.com/article/6429
+
+
+______________________________________________________________________________
+= profile [hid] object and usage
+
+- find out if [autoscale] takes a lot of CPU power, or where in [hid] is using
+ CPU where it doesn't have to be
+
+
+______________________________________________________________________________
+= Report available FF effects
+
+- check against HID Utilities Source/PID.h
+
+
+______________________________________________________________________________
+= pollfn for mouse-like devices
+
+- determine whether using a pollfn is actually better than using a t_clock
+
+- any device that acts like a system mouse can be used with a pollfn, since
+ the mouse data will go thru Pd's network port, triggering the pollfn.
+
+- this is probably unnecessary since the t_clock seems to run well at 1ms delay
+
+- at standard block size (64 samples), one block = ~1.5ms
+
+
+______________________________________________________________________________
+= check out using USB timestamp
+
+- use the USB timestamp to correctly space the output data
+
+(meh, probably not useful)
+
+
+
+ /----------------------------------------------------------------------------\
+------------------------------------------------------------------------------
+ BUGS BUGS BUGS BUGS BUGS BUGS BUGS BUGS BUGS BUGS BUGS BUGS BUGS BUGS BUGS
+------------------------------------------------------------------------------
+ \----------------------------------------------------------------------------/
+
+______________________________________________________________________________
+- BUG: crashes when you try yo open "mouse" with no args
+
+
+______________________________________________________________________________
+- BUG: on Mac OS X, polling starts without hid_build_device_list() or hid_open()
+
+- when polling starts, hid_build_device_list() should be called before starting
+
+
+______________________________________________________________________________
+- BUG: figure out how to prevent segfaults on mismapped devices/elements
+
+- it should gracefully ignore things where it currently segfaults
+
+- looks like its in build_device_list
+
+______________________________________________________________________________
+- BUG: multiple instances pointing to the same device don't have seperate close/free
+
+- closing the device on one instance closing that same device on all other
+ instances of [hid]
+
+- deleting that instance also closes the device for all other instances
+ pointing to that same device
+
+
+______________________________________________________________________________
+- BUG: getting events from the queue doesn't output a 0 value event when the
+ motion stops, so when the mouse stops, the sound keeps playing.
+
+This is probably only a problem on relative axes.
+
+ This will probably have to be implemented on a platform-specific level:
+
+ - On Darwin/MacOSX, I think that the HIDGetEvent() loop will have to be
+ followed by one call to HIDGetElementValue()
+
+
+
+______________________________________________________________________________
+- BUG: on MacOS X, two keyboard key codes are reported as hatswitches
+
+ abs abs_hat0x Button Input, Keyboard Usage 0x39
+ abs abs_hat0y Button Input, Keyboard Usage 0x39
+
+I am pretty sure this is just a hid_print_element_list() display problem.
+
+
diff --git a/hidio-help.pd b/hidio-help.pd
new file mode 100644
index 0000000..1c5bfe3
--- /dev/null
+++ b/hidio-help.pd
@@ -0,0 +1,589 @@
+#N canvas 157 38 921 595 10;
+#X floatatom 27 439 5 0 0 0 - - -;
+#X floatatom 83 439 5 0 0 0 - - -;
+#X floatatom 63 395 6 0 0 0 - - -;
+#X obj 191 164 tgl 35 0 empty empty empty 0 -6 0 8 -24198 -1 -1 0 25
+;
+#X floatatom 571 340 12 0 0 1 value - -;
+#X symbolatom 531 356 15 0 0 1 event_code - -;
+#X symbolatom 492 372 15 0 0 1 event_type - -;
+#X obj 2 2 cnv 15 900 20 empty empty [hid] 2 11 1 18 -233017 -66577
+0;
+#X text 274 332 outlet message format:;
+#X obj 772 99 ev-list;
+#X obj 772 150 ev_syn-list;
+#X obj 772 172 ev_key-list;
+#X obj 772 194 ev_rel-list;
+#X obj 772 216 ev_abs-list;
+#X obj 772 238 ev_msc-list;
+#X obj 772 260 ev_led-list;
+#X obj 772 282 ev_snd-list;
+#X obj 772 304 ev_rep-list;
+#X obj 772 326 ev_ff-list;
+#X obj 772 348 ev_ff_status-list;
+#X text 740 80 Event Types:;
+#X text 740 131 Event Codes:;
+#X floatatom 138 343 5 0 0 1 ev_syn - -;
+#X obj 111 342 +;
+#X msg 111 322 1;
+#X msg 374 140 close;
+#X msg 374 119 refresh;
+#X text 435 117 refresh device list;
+#X text 537 487 For more info:;
+#X text 266 557 released under the GNU GPL;
+#X text 472 544 $Revision: 1.1 $$Date: 2006-11-30 05:53:40 $;
+#X text 473 557 $Author: eighthave $;
+#X msg 436 201 poll 20;
+#X msg 374 201 poll 2;
+#X text 370 186 start polling and set the poll delay in ms;
+#X text 462 33 !!! This software is very much alpha \, so any aspect
+of it could change without notice !!!;
+#X obj 16 291 route key rel abs syn;
+#X obj 9 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0 1
+;
+#N canvas 278 328 631 544 Event_Codes 0;
+#X text 28 48 (For a complete listing of Linux Input Events \, see
+/usr/include/linux/input.h.);
+#X obj 11 9 cnv 15 580 30 empty empty Event_Codes 20 12 1 14 -225271
+-66577 0;
+#X text 32 118 EVENT CODE;
+#X text 162 118 #define;
+#X text 232 118 number;
+#X text 32 133 -----------------------------------;
+#X text 32 148 X Axis;
+#X text 32 163 Y Axis;
+#X text 32 178 Z Axis;
+#X text 32 193 Horizontal Wheel;
+#X text 32 208 Dial;
+#X text 32 223 Wheel;
+#X text 32 238 Misc;
+#X text 162 148 REL_X;
+#X text 162 163 REL_Y;
+#X text 162 178 REL_Z;
+#X text 162 193 REL_HWHEEL;
+#X text 162 208 REL_DIAL;
+#X text 162 223 REL_WHEEL;
+#X text 162 238 REL_MISC;
+#X text 247 148 0;
+#X text 247 163 1;
+#X text 247 178 2;
+#X text 247 193 6;
+#X text 247 208 7;
+#X text 247 223 8;
+#X text 247 238 9;
+#X text 307 118 EVENT CODE;
+#X text 457 118 #define;
+#X text 547 118 number;
+#X text 307 148 Absolute X;
+#X text 307 163 Absolute Y;
+#X text 307 178 Absolute Z;
+#X text 307 193 RX;
+#X text 307 208 RY;
+#X text 307 223 RZ;
+#X text 307 238 Throttle;
+#X text 307 253 Rudder;
+#X text 307 268 Wheel;
+#X text 307 283 Gas Pedal;
+#X text 307 298 Brake Pedal;
+#X text 307 313 Hat Switch 0 X-axis;
+#X text 307 328 Hat Switch 0 Y-axis;
+#X text 307 343 Hat Switch 1 X-axis;
+#X text 307 358 Hat Switch 1 Y-axis;
+#X text 307 373 Hat Switch 2 X-axis;
+#X text 307 388 Hat Switch 2 Y-axis;
+#X text 307 403 Hat Switch 3 X-axis;
+#X text 307 418 Hat Switch 3 Y-axis;
+#X text 307 433 Pressure;
+#X text 307 448 Distance;
+#X text 307 463 Tilt X-Axis;
+#X text 307 478 Tilt Y-Axis;
+#X text 307 493 Misc;
+#X text 457 148 ABS_X;
+#X text 457 163 ABS_Y;
+#X text 457 178 ABS_Z;
+#X text 457 193 ABS_RX;
+#X text 457 208 ABS_RY;
+#X text 457 223 ABS_RZ;
+#X text 457 238 ABS_THROTTLE;
+#X text 457 253 ABS_RUDDER;
+#X text 457 268 ABS_WHEEL;
+#X text 457 283 ABS_GAS;
+#X text 457 298 ABS_BRAKE;
+#X text 457 313 ABS_HAT0X;
+#X text 457 328 ABS_HAT0Y;
+#X text 457 343 ABS_HAT1X;
+#X text 457 358 ABS_HAT1Y;
+#X text 457 373 ABS_HAT2X;
+#X text 457 388 ABS_HAT2Y;
+#X text 457 403 ABS_HAT3X;
+#X text 457 418 ABS_HAT3Y;
+#X text 457 433 ABS_PRESSURE;
+#X text 457 448 ABS_DISTANCE;
+#X text 457 463 ABS_TILT_X;
+#X text 457 478 ABS_TILT_Y;
+#X text 457 493 ABS_MISC;
+#X text 563 148 0;
+#X text 563 163 1;
+#X text 563 178 2;
+#X text 563 193 3;
+#X text 563 208 4;
+#X text 563 223 5;
+#X text 563 238 6;
+#X text 563 253 7;
+#X text 563 268 8;
+#X text 563 283 9;
+#X text 563 298 10;
+#X text 563 313 16;
+#X text 563 328 17;
+#X text 563 343 18;
+#X text 563 358 19;
+#X text 563 373 20;
+#X text 563 388 21;
+#X text 563 403 22;
+#X text 563 418 23;
+#X text 563 433 24;
+#X text 563 448 25;
+#X text 563 463 26;
+#X text 563 478 27;
+#X text 563 493 28;
+#X obj 30 89 cnv 15 250 25 empty empty Relative_Axes 20 12 1 12 -241660
+-66577 0;
+#X obj 308 89 cnv 15 280 25 empty empty Absolute_Axes 20 12 1 12 -241660
+-66577 0;
+#X text 307 133 ----------------------------------------;
+#X text 32 285 EVENT CODE;
+#X text 138 285 #define;
+#X text 232 285 number;
+#X text 32 300 -----------------------------------;
+#X obj 30 256 cnv 15 250 25 empty empty Joystick_Buttons 20 12 1 12
+-241660 -66577 0;
+#X text 138 315 BTN_TRIGGER;
+#X text 32 315 Trigger;
+#X text 32 330 Thumb;
+#X text 32 345 Thumb 2;
+#X text 32 360 Top;
+#X text 32 375 Top 2;
+#X text 32 390 Pinkie;
+#X text 32 405 Base 1;
+#X text 138 404 BTN_BASE;
+#X text 138 330 BTN_THUMB;
+#X text 138 345 BTN_THUMB2;
+#X text 138 360 BTN_TOP;
+#X text 138 375 BTN_TOP2;
+#X text 138 390 BTN_PINKIE;
+#X text 245 315 288;
+#X text 245 330 289;
+#X text 245 345 290;
+#X text 245 360 291;
+#X text 245 375 292;
+#X text 245 390 293;
+#X text 245 405 294;
+#X text 245 419 295;
+#X text 245 434 296;
+#X text 245 448 297;
+#X text 138 418 BTN_BASE2;
+#X text 138 433 BTN_BASE3;
+#X text 138 447 BTN_BASE4;
+#X text 32 419 Base 2;
+#X text 32 434 Base 3;
+#X text 32 448 Base 4;
+#X text 32 463 Base 5;
+#X text 32 477 Base 6;
+#X text 138 462 BTN_BASE5;
+#X text 138 476 BTN_BASE6;
+#X text 245 463 298;
+#X text 245 477 299;
+#X restore 774 414 pd Event_Codes;
+#N canvas 50 289 469 317 Event_Types 0;
+#X text 28 48 (For a complete listing of Linux Input Events \, see
+/usr/include/linux/input.h.);
+#X text 61 90 EVENT TYPE;
+#X text 61 135 Keys and Buttons;
+#X text 61 150 Relative Axes;
+#X text 61 165 Absolute Axes;
+#X text 61 180 Misc Events;
+#X text 61 195 LED Event;
+#X text 61 210 Sounds;
+#X text 61 225 Autorepeat Values;
+#X text 61 240 Force Feedback;
+#X text 230 90 #define;
+#X text 230 135 EV_KEY;
+#X text 230 150 EV_REL;
+#X text 230 165 EV_ABS;
+#X text 230 180 EV_MSC;
+#X text 230 195 EV_LED;
+#X text 230 210 EV_SND;
+#X text 230 225 EV_REP;
+#X text 230 240 EV_FF;
+#X text 315 90 number;
+#X text 331 120 0;
+#X text 331 135 1;
+#X text 331 150 2;
+#X text 331 165 3;
+#X text 331 180 4;
+#X text 331 195 17;
+#X text 331 210 18;
+#X text 331 225 20;
+#X text 331 240 21;
+#X obj 11 9 cnv 15 400 30 empty empty Event_Types 20 12 1 14 -262131
+-66577 0;
+#X text 230 120 EV_SYN;
+#X text 61 270 Force Feedback Status;
+#X text 61 120 Syncronization Events;
+#X text 230 270 EV_FF_STATUS;
+#X text 331 270 23;
+#X text 61 105 -------------------------------------------;
+#X text 331 255 22;
+#X text 230 255 EV_PWR;
+#X text 61 255 Power Events (for UPS);
+#X restore 774 394 pd Event_Types;
+#N canvas 0 22 450 300 Event_Values 0;
+#X text 28 48 (For a complete listing of Linux Input Events \, see
+/usr/include/linux/input.h.);
+#X obj 11 9 cnv 15 400 30 empty empty Event_Values 20 12 1 14 -261681
+-66577 0;
+#X restore 774 434 pd Event_Values;
+#X floatatom 140 439 5 0 0 0 - - -;
+#X obj 421 394 route abs_hat0x abs_hat0y abs_hat1x abs_hat1y;
+#X floatatom 421 416 7 0 0 0 - - -;
+#X msg 374 161 print;
+#X text 437 141 close the device;
+#X text 437 162 print the device and element lists;
+#X text 9 212 Any non-zero value starts polling \,;
+#X text 8 225 0 stops the polling. If the number;
+#X text 9 238 is greater than 1 \, then the poll;
+#X text 9 251 delay is set to that number.;
+#X obj 27 419 route rel_x rel_y rel_z rel_wheel;
+#X floatatom 196 439 5 0 0 0 - - -;
+#X obj 492 321 unpack s s f;
+#X text 298 346 event_type event_code value;
+#X obj 63 374 route abs_x abs_y abs_z abs_rx abs_ry abs_rz abs_throttle
+;
+#X obj 421 432 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+-1;
+#X floatatom 498 416 7 0 0 0 - - -;
+#X obj 498 432 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X floatatom 576 416 7 0 0 0 - - -;
+#X obj 576 432 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X floatatom 653 416 7 0 0 0 - - -;
+#X obj 653 432 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X floatatom 113 395 6 0 0 0 - - -;
+#X floatatom 163 395 6 0 0 0 - - -;
+#X floatatom 213 395 6 0 0 0 - - -;
+#X floatatom 263 395 6 0 0 0 - - -;
+#X floatatom 313 395 6 0 0 0 - - -;
+#X floatatom 363 395 6 0 0 0 - - -;
+#X obj 39 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0 1
+;
+#X obj 69 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0 1
+;
+#X obj 99 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0 1
+;
+#X obj 129 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0
+1;
+#X obj 159 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0
+1;
+#X obj 189 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0
+1;
+#X obj 219 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0
+1;
+#X obj 249 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0
+1;
+#X obj 279 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0
+1;
+#X obj 309 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0
+1;
+#X obj 339 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0
+1;
+#X obj 369 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0
+1;
+#X obj 399 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0
+1;
+#X obj 9 460 route btn_0 btn_1 btn_2 btn_3 btn_4 btn_5 btn_6 btn_7
+btn_8 btn_9 btn_10 btn_11 btn_12 btn_13 btn_14 btn_15;
+#X obj 429 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0
+1;
+#X obj 459 502 tgl 25 0 empty empty empty 0 -6 0 8 -195568 -1 -1 0
+1;
+#X obj 262 298 cyclone/prepend set;
+#X msg 25 155 debug 0;
+#X msg 298 145 info;
+#N canvas 743 25 411 235 see 0;
+#N canvas 108 318 543 264 route 0;
+#X obj 27 14 inlet;
+#X obj 72 226 outlet;
+#X obj 19 226 outlet;
+#X obj 172 226 outlet;
+#X obj 222 204 symbol;
+#X obj 222 226 outlet;
+#X obj 272 204 symbol;
+#X obj 272 226 outlet;
+#X obj 322 204 symbol;
+#X obj 322 226 outlet;
+#X obj 372 204 symbol;
+#X obj 372 226 outlet;
+#X obj 122 225 outlet;
+#X obj 422 204 symbol;
+#X obj 422 226 outlet;
+#X obj 472 204 symbol;
+#X obj 472 226 outlet;
+#X obj 26 63 route open device poll total product manufacturer transport
+type vendorID productID;
+#X connect 0 0 17 0;
+#X connect 4 0 5 0;
+#X connect 6 0 7 0;
+#X connect 8 0 9 0;
+#X connect 10 0 11 0;
+#X connect 13 0 14 0;
+#X connect 15 0 16 0;
+#X connect 17 0 2 0;
+#X connect 17 1 1 0;
+#X connect 17 2 12 0;
+#X connect 17 3 3 0;
+#X connect 17 4 4 0;
+#X connect 17 5 6 0;
+#X connect 17 6 8 0;
+#X connect 17 7 10 0;
+#X connect 17 8 13 0;
+#X connect 17 9 15 0;
+#X restore 117 70 pd route info;
+#X obj 81 96 tgl 15 0 empty empty open 0 -6 0 8 -262144 -1 -1 0 1;
+#X obj 110 22 inlet;
+#X obj 123 43 print info;
+#X symbolatom 304 93 0 0 0 0 productID - -;
+#X symbolatom 304 112 0 0 0 0 vendorID - -;
+#X symbolatom 304 151 0 0 0 0 transport - -;
+#X symbolatom 304 171 0 0 0 0 manufacturer - -;
+#X symbolatom 186 192 0 0 0 0 product - -;
+#X floatatom 97 140 5 0 0 0 device - -;
+#X floatatom 97 162 5 0 0 0 poll - -;
+#X symbolatom 304 131 0 0 0 0 type - -;
+#X floatatom 97 182 5 0 0 0 total - -;
+#X connect 0 0 1 0;
+#X connect 0 1 9 0;
+#X connect 0 2 10 0;
+#X connect 0 3 12 0;
+#X connect 0 4 8 0;
+#X connect 0 5 7 0;
+#X connect 0 6 6 0;
+#X connect 0 7 11 0;
+#X connect 0 8 5 0;
+#X connect 0 9 4 0;
+#X connect 2 0 0 0;
+#X connect 2 0 3 0;
+#X restore 420 271 pd see device info;
+#N canvas 0 22 380 450 open 0;
+#X obj 77 61 hradio 15 1 0 8 empty empty empty 0 -6 0 8 -262144 -1
+-1 0;
+#X msg 78 81 open mouse \$1;
+#X obj 121 201 hradio 15 1 0 8 empty empty empty 0 -6 0 8 -262144 -1
+-1 0;
+#X msg 130 221 open keyboard \$1;
+#X obj 50 13 hradio 15 1 0 8 empty empty empty 0 -6 0 8 -262144 -1
+-1 0;
+#X obj 55 417 outlet;
+#X obj 85 108 hradio 15 1 0 8 empty empty empty 0 -6 0 8 -262144 -1
+-1 0;
+#X msg 94 128 open joystick \$1;
+#X msg 59 33 open pointer \$1;
+#X obj 101 155 hradio 15 1 0 8 empty empty empty 0 -6 0 8 -262144 -1
+-1 0;
+#X msg 110 175 open gamepad \$1;
+#X obj 137 244 hradio 15 1 0 8 empty empty empty 0 -6 0 8 -262144 -1
+-1 0;
+#X msg 146 264 open keypad \$1;
+#X obj 141 291 hradio 15 1 0 8 empty empty empty 0 -6 0 8 -262144 -1
+-1 0;
+#X msg 150 311 open multiaxiscontroller \$1;
+#X text 155 342 or just open the first one:;
+#X msg 138 363 open mouse;
+#X msg 159 381 open joystick;
+#X connect 0 0 1 0;
+#X connect 1 0 5 0;
+#X connect 2 0 3 0;
+#X connect 3 0 5 0;
+#X connect 4 0 8 0;
+#X connect 6 0 7 0;
+#X connect 7 0 5 0;
+#X connect 8 0 5 0;
+#X connect 9 0 10 0;
+#X connect 10 0 5 0;
+#X connect 11 0 12 0;
+#X connect 12 0 5 0;
+#X connect 13 0 14 0;
+#X connect 14 0 5 0;
+#X connect 16 0 5 0;
+#X connect 17 0 5 0;
+#X restore 203 59 pd open by device type;
+#N canvas 88 102 470 320 open 0;
+#X text 217 82 Gravis/Destroyer Tiltpad;
+#X msg 76 81 open 0x047D 0x4008;
+#X msg 73 53 open 0x046d 0xc01d;
+#X text 211 53 Logitech USB-PS/2 Optical Mouse;
+#X obj 10 277 outlet;
+#X text 9 12 You can use the hex values of the USB vendor and product
+IDs (it is not case sensitive):;
+#X text 221 111 Overtone CUI v1.0;
+#X msg 80 110 open 0x1043 0x0015;
+#X connect 1 0 4 0;
+#X connect 2 0 4 0;
+#X connect 7 0 4 0;
+#X restore 174 37 pd open by vendor/product ID;
+#N canvas 114 93 467 346 test 0;
+#X obj 144 45 inlet;
+#X obj 88 104 route DESKTOP;
+#X obj 87 158 route DESKTOP57;
+#X obj 70 207 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X floatatom 95 212 5 0 0 0 - - -;
+#X obj 148 215 spigot;
+#X obj 146 256 print test;
+#X obj 189 192 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 292 122 spigot;
+#X obj 290 163 print test;
+#X obj 333 99 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X connect 0 0 1 0;
+#X connect 0 0 8 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 2 0 4 0;
+#X connect 2 0 5 0;
+#X connect 5 0 6 0;
+#X connect 7 0 5 1;
+#X connect 8 0 9 0;
+#X connect 10 0 8 1;
+#X restore 197 303 pd test;
+#X msg 504 201 poll 200;
+#X msg 261 317 key key_leftctrl 1;
+#X text 49 543 (C) Copyright 2004 Hans-Christoph Steiner <hans@at.or.at>
+;
+#N canvas 162 133 570 420 serin 0;
+#X obj 209 61 cnv 15 15 15 empty \$0-debug-canvas 0 4 8 0 14 -233017
+-1 0;
+#X obj 60 61 hradio 15 1 1 10 empty empty empty 0 -6 0 8 -261689 -1
+-1 0;
+#X obj 60 13 inlet;
+#X msg 200 202 label \$1;
+#X obj 200 180 makefilename %d;
+#X obj 59 108 int;
+#X obj 59 337 outlet;
+#X msg 201 306 set \$1 \$2;
+#X obj 59 266 trigger bang anything;
+#X obj 201 286 list;
+#X msg 60 210 debug \$1;
+#X obj 200 225 send \$0-debug-canvas;
+#X connect 1 0 5 0;
+#X connect 2 0 1 0;
+#X connect 3 0 11 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 0;
+#X connect 5 0 10 0;
+#X connect 7 0 6 0;
+#X connect 8 0 6 0;
+#X connect 8 1 9 0;
+#X connect 9 0 7 0;
+#X connect 10 0 8 0;
+#X coords 0 -1 1 1 165 17 1 60 60;
+#X restore 25 134 pd serin;
+#X msg 262 114 open 1;
+#N canvas 162 133 570 420 serin 0;
+#X obj 209 61 cnv 15 15 15 empty \$0-open-canvas 1 4 8 0 14 -233017
+-1 0;
+#X obj 60 61 hradio 15 1 1 10 empty empty empty 0 -6 0 8 -225271 -1
+-1 1;
+#X obj 60 13 inlet;
+#X msg 200 202 label \$1;
+#X obj 200 180 makefilename %d;
+#X obj 59 108 int;
+#X obj 59 337 outlet;
+#X msg 201 306 set \$1 \$2;
+#X obj 59 266 trigger bang anything;
+#X obj 201 286 list;
+#X msg 60 210 open \$1;
+#X obj 200 225 send \$0-open-canvas;
+#X connect 1 0 5 0;
+#X connect 2 0 1 0;
+#X connect 3 0 11 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 0;
+#X connect 5 0 10 0;
+#X connect 7 0 6 0;
+#X connect 8 0 6 0;
+#X connect 8 1 9 0;
+#X connect 9 0 7 0;
+#X connect 10 0 8 0;
+#X coords 0 -1 1 1 165 17 1 60 60;
+#X restore 262 93 pd serin;
+#X obj 646 486 pddp/open all_about_hid;
+#X obj 304 250 hidio;
+#X connect 3 0 99 0;
+#X connect 22 0 23 1;
+#X connect 23 0 22 0;
+#X connect 24 0 23 0;
+#X connect 25 0 99 0;
+#X connect 26 0 99 0;
+#X connect 32 0 99 0;
+#X connect 33 0 99 0;
+#X connect 36 0 82 0;
+#X connect 36 1 51 0;
+#X connect 36 2 55 0;
+#X connect 36 3 24 0;
+#X connect 42 0 43 0;
+#X connect 42 1 57 0;
+#X connect 42 2 59 0;
+#X connect 42 3 61 0;
+#X connect 43 0 56 0;
+#X connect 44 0 99 0;
+#X connect 51 0 0 0;
+#X connect 51 1 1 0;
+#X connect 51 2 41 0;
+#X connect 51 3 52 0;
+#X connect 53 0 6 0;
+#X connect 53 1 5 0;
+#X connect 53 2 4 0;
+#X connect 55 0 2 0;
+#X connect 55 1 63 0;
+#X connect 55 2 64 0;
+#X connect 55 3 65 0;
+#X connect 55 4 66 0;
+#X connect 55 5 67 0;
+#X connect 55 6 68 0;
+#X connect 55 7 42 0;
+#X connect 57 0 58 0;
+#X connect 59 0 60 0;
+#X connect 61 0 62 0;
+#X connect 82 0 37 0;
+#X connect 82 1 69 0;
+#X connect 82 2 70 0;
+#X connect 82 3 71 0;
+#X connect 82 4 72 0;
+#X connect 82 5 73 0;
+#X connect 82 6 74 0;
+#X connect 82 7 75 0;
+#X connect 82 8 76 0;
+#X connect 82 9 77 0;
+#X connect 82 10 78 0;
+#X connect 82 11 79 0;
+#X connect 82 12 80 0;
+#X connect 82 13 81 0;
+#X connect 82 14 83 0;
+#X connect 82 15 84 0;
+#X connect 85 0 93 0;
+#X connect 86 0 99 0;
+#X connect 87 0 99 0;
+#X connect 89 0 99 0;
+#X connect 90 0 99 0;
+#X connect 92 0 99 0;
+#X connect 95 0 86 0;
+#X connect 96 0 99 0;
+#X connect 97 0 96 0;
+#X connect 99 0 36 0;
+#X connect 99 0 53 0;
+#X connect 99 0 85 0;
+#X connect 99 0 91 0;
+#X connect 99 1 88 0;
diff --git a/hidio.c b/hidio.c
new file mode 100644
index 0000000..d43e0df
--- /dev/null
+++ b/hidio.c
@@ -0,0 +1,485 @@
+/* --------------------------------------------------------------------------*/
+/* */
+/* interface to native HID (Human Interface Devices) API */
+/* Written by Hans-Christoph Steiner <hans@at.or.at> */
+/* */
+/* Copyright (c) 2004-2006 Hans-Christoph Steiner */
+/* */
+/* 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 2 */
+/* of the License, or (at your option) any later version. */
+/* */
+/* See file LICENSE for further informations on licensing terms. */
+/* */
+/* 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, write to the Free Software Foundation, */
+/* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+/* */
+/* --------------------------------------------------------------------------*/
+
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "hidio.h"
+
+/*------------------------------------------------------------------------------
+ * LOCAL DEFINES
+ */
+
+//#define DEBUG(x)
+#define DEBUG(x) x
+
+unsigned short global_debug_level = 0;
+
+static t_class *hidio_class;
+
+/*------------------------------------------------------------------------------
+ * FUNCTION PROTOTYPES
+ */
+
+//static void hidio_poll(t_hidio *x, t_float f);
+static void hidio_open(t_hidio *x, t_symbol *s, int argc, t_atom *argv);
+//static t_int hidio_close(t_hidio *x);
+//static t_int hidio_read(t_hidio *x,int fd);
+//static void hidio_float(t_hidio* x, t_floatarg f);
+
+
+/*------------------------------------------------------------------------------
+ * SUPPORT FUNCTIONS
+ */
+
+void debug_print(t_int message_debug_level, const char *fmt, ...)
+{
+ if(message_debug_level <= global_debug_level)
+ {
+ char buf[MAXPDSTRING];
+ va_list ap;
+ //t_int arg[8];
+ va_start(ap, fmt);
+ vsnprintf(buf, MAXPDSTRING-1, fmt, ap);
+ post(buf);
+ va_end(ap);
+ }
+}
+
+void debug_error(t_hidio *x, t_int message_debug_level, const char *fmt, ...)
+{
+ if(message_debug_level <= global_debug_level)
+ {
+ char buf[MAXPDSTRING];
+ va_list ap;
+ //t_int arg[8];
+ va_start(ap, fmt);
+ vsnprintf(buf, MAXPDSTRING-1, fmt, ap);
+ pd_error(x, buf);
+ va_end(ap);
+ }
+}
+
+
+static void output_status(t_hidio *x, t_symbol *selector, t_float output_value)
+{
+ t_atom *output_atom = getbytes(sizeof(t_atom));
+ SETFLOAT(output_atom, output_value);
+ outlet_anything( x->x_status_outlet, selector, 1, output_atom);
+ freebytes(output_atom,sizeof(t_atom));
+}
+
+static void output_open_status(t_hidio *x)
+{
+ output_status(x, gensym("open"), x->x_device_open);
+}
+
+static void output_device_number(t_hidio *x)
+{
+ output_status(x, gensym("device"), x->x_device_number);
+}
+
+static void output_poll_time(t_hidio *x)
+{
+ output_status(x, gensym("poll"), x->x_delay);
+}
+
+static void output_device_count(t_hidio *x)
+{
+ output_status(x, gensym("total"), device_count);
+}
+
+static void output_element_ranges(t_hidio *x)
+{
+ if( (x->x_device_number > -1) && (x->x_device_open) )
+ {
+ unsigned int i;
+ t_atom output_data[4];
+
+ for(i=0;i<element_count[x->x_device_number];++i)
+ {
+ SETSYMBOL(output_data, element[x->x_device_number][i]->type);
+ SETSYMBOL(output_data + 1, element[x->x_device_number][i]->name);
+ SETFLOAT(output_data + 2, element[x->x_device_number][i]->min);
+ SETFLOAT(output_data + 3, element[x->x_device_number][i]->max);
+ outlet_anything(x->x_status_outlet, gensym("range"), 4, output_data);
+ }
+ }
+}
+
+
+static unsigned int name_to_usage(char *usage_name)
+{ // output usagepage << 16 + usage
+ if(strcmp(usage_name,"pointer") == 0) return(0x00010001);
+ if(strcmp(usage_name,"mouse") == 0) return(0x00010002);
+ if(strcmp(usage_name,"joystick") == 0) return(0x00010004);
+ if(strcmp(usage_name,"gamepad") == 0) return(0x00010005);
+ if(strcmp(usage_name,"keyboard") == 0) return(0x00010006);
+ if(strcmp(usage_name,"keypad") == 0) return(0x00010007);
+ if(strcmp(usage_name,"multiaxiscontroller") == 0) return(0x00010008);
+ return(0);
+}
+
+
+static short get_device_number_from_arguments(int argc, t_atom *argv)
+{
+ short device_number = -1;
+ unsigned short device_type_instance;
+ unsigned int usage;
+ unsigned short vendor_id;
+ unsigned short product_id;
+ char device_type_string[MAXPDSTRING] = "";
+ t_symbol *first_argument;
+ t_symbol *second_argument;
+
+ if(argc == 1)
+ {
+ first_argument = atom_getsymbolarg(0,argc,argv);
+ if(first_argument == &s_)
+ { // single float arg means device #
+ post("first_argument == &s_");
+ device_number = (short) atom_getfloatarg(0,argc,argv);
+ if(device_number < 0) device_number = -1;
+ debug_print(LOG_DEBUG,"[hidio] setting device# to %d",device_number);
+ }
+ else
+ { // single symbol arg means first instance of a device type
+ atom_string(argv, device_type_string, MAXPDSTRING-1);
+ usage = name_to_usage(device_type_string);
+ device_number = get_device_number_from_usage(0, usage >> 16,
+ usage & 0xffff);
+ debug_print(LOG_INFO,"[hidio] using 0x%04x 0x%04x for %s",
+ usage >> 16, usage & 0xffff, device_type_string);
+ }
+ }
+ else if(argc == 2)
+ {
+ first_argument = atom_getsymbolarg(0,argc,argv);
+ second_argument = atom_getsymbolarg(1,argc,argv);
+ if( second_argument == &s_ )
+ { /* a symbol then a float means match on usage */
+ atom_string(argv, device_type_string, MAXPDSTRING-1);
+ usage = name_to_usage(device_type_string);
+ device_type_instance = atom_getfloatarg(1,argc,argv);
+ debug_print(LOG_DEBUG,"[hidio] looking for %s at #%d",
+ device_type_string, device_type_instance);
+ device_number = get_device_number_from_usage(device_type_instance,
+ usage >> 16,
+ usage & 0xffff);
+ }
+ else
+ { /* two symbols means idVendor and idProduct in hex */
+ vendor_id =
+ (unsigned short) strtol(first_argument->s_name, NULL, 16);
+ product_id =
+ (unsigned short) strtol(second_argument->s_name, NULL, 16);
+ device_number = get_device_number_by_id(vendor_id,product_id);
+ }
+ }
+ return(device_number);
+}
+
+
+void hidio_output_event(t_hidio *x, t_hid_element *output_data)
+{
+ if( (output_data->value != output_data->previous_value) ||
+ (output_data->relative) ) // relative data should always be output
+ {
+ t_atom event_data[3];
+ SETSYMBOL(event_data, output_data->name);
+ SETFLOAT(event_data + 1, output_data->instance);
+ SETFLOAT(event_data + 2, output_data->value);
+ outlet_anything(x->x_data_outlet,output_data->type,3,event_data);
+ }
+}
+
+
+/* stop polling the device */
+static void stop_poll(t_hidio* x)
+{
+ debug_print(LOG_DEBUG,"stop_poll");
+
+ if (x->x_started)
+ {
+ clock_unset(x->x_clock);
+ debug_print(LOG_INFO,"[hidio] polling stopped");
+ x->x_started = 0;
+ }
+}
+
+/*------------------------------------------------------------------------------
+ * METHODS FOR [hidio]'s MESSAGES
+ */
+
+
+void hidio_poll(t_hidio* x, t_float f)
+{
+ debug_print(LOG_DEBUG,"hidio_poll");
+
+/* if the user sets the delay less than 2, set to block size */
+ if( f > 2 )
+ x->x_delay = (t_int)f;
+ else if( f > 0 ) //TODO make this the actual time between message processing
+ x->x_delay = 1.54;
+ if(x->x_device_number > -1)
+ {
+ if(!x->x_device_open)
+ hidio_open(x,gensym("open"),0,NULL);
+ if(!x->x_started)
+ {
+ clock_delay(x->x_clock, x->x_delay);
+ debug_print(LOG_DEBUG,"[hidio] polling started");
+ x->x_started = 1;
+ }
+ }
+}
+
+static void hidio_set_from_float(t_hidio *x, t_floatarg f)
+{
+/* values greater than 1 set the polling delay time */
+/* 1 and 0 for start/stop so you can use a [tgl] */
+ if(f > 1)
+ {
+ x->x_delay = (t_int)f;
+ hidio_poll(x,f);
+ }
+ else if(f == 1)
+ {
+ if(! x->x_started)
+ hidio_poll(x,f);
+ }
+ else if(f == 0)
+ {
+ stop_poll(x);
+ }
+}
+
+/* close the device */
+t_int hidio_close(t_hidio *x)
+{
+ debug_print(LOG_DEBUG,"hidio_close");
+
+/* just to be safe, stop it first */
+ stop_poll(x);
+
+ if(! hidio_close_device(x))
+ {
+ debug_print(LOG_INFO,"[hidio] closed device %d",x->x_device_number);
+ x->x_device_open = 0;
+ return (0);
+ }
+
+ return (1);
+}
+
+
+/* hidio_open behavoir
+ * current state action
+ * ---------------------------------------
+ * closed / same device open
+ * open / same device no action
+ * closed / different device open
+ * open / different device close open
+ */
+static void hidio_open(t_hidio *x, t_symbol *s, int argc, t_atom *argv)
+{
+ debug_print(LOG_DEBUG,"hid_%s",s->s_name);
+/* store running state to be restored after the device has been opened */
+ t_int started = x->x_started;
+
+ short device_number = get_device_number_from_arguments(argc, argv);
+ if(device_number > -1)
+ {
+ if( (device_number != x->x_device_number) && (x->x_device_open) )
+ hidio_close(x);
+ if(! x->x_device_open)
+ {
+ if(hidio_open_device(x,device_number))
+ error("[hidio] can not open device %d",device_number);
+ else
+ x->x_device_open = 1;
+ }
+ }
+ else debug_print(LOG_WARNING,"[hidio] device does not exist");
+/* restore the polling state so that when I [tgl] is used to start/stop [hidio],
+ * the [tgl]'s state will continue to accurately reflect [hidio]'s state */
+ if(started)
+ hidio_set_from_float(x,x->x_delay);
+ debug_print(LOG_DEBUG,"[hidio] set device# to %d",device_number);
+ output_open_status(x);
+ output_device_number(x);
+}
+
+
+t_int hidio_read(t_hidio *x, int fd)
+{
+// debug_print(LOG_DEBUG,"hidio_read");
+ unsigned int i;
+ double right_now = clock_getlogicaltime();
+ t_hid_element *current_element;
+
+ if(right_now > last_execute_time[x->x_device_number])
+ {
+ hidio_get_events(x);
+ last_execute_time[x->x_device_number] = right_now;
+/* post("executing: instance %d/%d at %ld",
+ x->x_instance, hidio_instance_count, right_now);*/
+ }
+ for(i=0; i< element_count[x->x_device_number]; ++i)
+ {
+ current_element = element[x->x_device_number][i];
+ if(current_element->previous_value != current_element->value)
+ {
+ hidio_output_event(x, current_element);
+ if(!current_element->relative)
+ current_element->previous_value = current_element->value;
+ }
+ }
+ if (x->x_started)
+ {
+ clock_delay(x->x_clock, x->x_delay);
+ }
+
+ // TODO: why is this 1?
+ return 1;
+}
+
+static void hidio_info(t_hidio *x)
+{
+ output_open_status(x);
+ output_device_number(x);
+ output_device_count(x);
+ output_poll_time(x);
+ output_element_ranges(x);
+ hidio_platform_specific_info(x);
+}
+
+static void hidio_float(t_hidio* x, t_floatarg f)
+{
+ debug_print(LOG_DEBUG,"hid_float");
+
+ hidio_set_from_float(x,f);
+}
+
+static void hidio_debug(t_hidio *x, t_float f)
+{
+ global_debug_level = f;
+}
+
+
+/*------------------------------------------------------------------------------
+ * system functions
+ */
+static void hidio_free(t_hidio* x)
+{
+ debug_print(LOG_DEBUG,"hidio_free");
+
+ hidio_close(x);
+ clock_free(x->x_clock);
+ hidio_instance_count--;
+
+ hidio_platform_specific_free(x);
+}
+
+/* create a new instance of this class */
+static void *hidio_new(t_symbol *s, int argc, t_atom *argv)
+{
+ DEBUG(post("hidio_new"););
+ t_hidio *x = (t_hidio *)pd_new(hidio_class);
+ unsigned int i;
+
+#if !defined(__linux__) && !defined(__APPLE__)
+ error(" !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!");
+ error(" This is a dummy, since this object only works GNU/Linux and MacOS X!");
+ error(" !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!");
+#endif
+
+ /* init vars */
+ global_debug_level = 9; /* high numbers here means see more messages */
+ x->x_has_ff = 0;
+ x->x_device_open = 0;
+ x->x_started = 0;
+ x->x_delay = DEFAULT_DELAY;
+ for(i=0; i<MAX_DEVICES; ++i) last_execute_time[i] = 0;
+
+ x->x_clock = clock_new(x, (t_method)hidio_read);
+
+ /* create anything outlet used for HID data */
+ x->x_data_outlet = outlet_new(&x->x_obj, 0);
+ x->x_status_outlet = outlet_new(&x->x_obj, 0);
+
+ x->x_device_number = get_device_number_from_arguments(argc, argv);
+
+ x->x_instance = hidio_instance_count;
+ hidio_instance_count++;
+
+ return (x);
+}
+
+void hidio_setup(void)
+{
+ hidio_class = class_new(gensym("hidin"),
+ (t_newmethod)hidio_new,
+ (t_method)hidio_free,
+ sizeof(t_hidio),
+ CLASS_DEFAULT,
+ A_GIMME,0);
+
+ /* add inlet datatype methods */
+ class_addfloat(hidio_class,(t_method) hidio_float);
+ class_addbang(hidio_class,(t_method) hidio_read);
+/* class_addanything(hidio_class,(t_method) hidio_anything); */
+
+ /* add inlet message methods */
+/* class_addmethod(hidio_class,(t_method) hidio_debug,gensym("debug"),A_DEFFLOAT,0);
+ class_addmethod(hidio_class,(t_method) hidio_build_device_list,gensym("refresh"),0);
+ class_addmethod(hidio_class,(t_method) hidio_print,gensym("print"),0);
+ class_addmethod(hidio_class,(t_method) hidio_info,gensym("info"),0);
+ class_addmethod(hidio_class,(t_method) hidio_open,gensym("open"),A_GIMME,0);
+ class_addmethod(hidio_class,(t_method) hidio_close,gensym("close"),0);
+ class_addmethod(hidio_class,(t_method) hidio_poll,gensym("poll"),A_DEFFLOAT,0);
+ /* force feedback messages */
+/* class_addmethod(hidio_class,(t_method) hidio_ff_autocenter,
+ gensym("ff_autocenter"),A_DEFFLOAT,0);
+ class_addmethod(hidio_class,(t_method) hidio_ff_gain,gensym("ff_gain"),A_DEFFLOAT,0);
+ class_addmethod(hidio_class,(t_method) hidio_ff_motors,gensym("ff_motors"),A_DEFFLOAT,0);
+ class_addmethod(hidio_class,(t_method) hidio_ff_continue,gensym("ff_continue"),0);
+ class_addmethod(hidio_class,(t_method) hidio_ff_pause,gensym("ff_pause"),0);
+ class_addmethod(hidio_class,(t_method) hidio_ff_reset,gensym("ff_reset"),0);
+ class_addmethod(hidio_class,(t_method) hidio_ff_stopall,gensym("ff_stopall"),0);
+ /* ff tests */
+/* class_addmethod(hidio_class,(t_method) hidio_ff_fftest,gensym("fftest"),A_DEFFLOAT,0);
+ class_addmethod(hidio_class,(t_method) hidio_ff_print,gensym("ff_print"),0);
+*/
+
+ post("[hidio] %d.%d, written by Hans-Christoph Steiner <hans@eds.org>",
+ HIDIO_MAJOR_VERSION, HIDIO_MINOR_VERSION);
+ post("\tcompiled on "__DATE__" at "__TIME__ " ");
+ post("arg!!!!!!");
+}
+
diff --git a/hidio.h b/hidio.h
new file mode 100644
index 0000000..7b709ad
--- /dev/null
+++ b/hidio.h
@@ -0,0 +1,153 @@
+#ifndef _HIDIO_H
+#define _HIDIO_H
+
+#include <stdio.h>
+#include <sys/syslog.h>
+
+#ifdef __linux__
+#include <linux/types.h>
+#endif /* __linux__ */
+
+#include <m_pd.h>
+
+/*
+ * this is automatically generated from linux/input.h by
+ * make-arrays-from-input.h.pl to be the cross-platform event types and codes
+ */
+#include "input_arrays.h"
+
+#define HIDIO_MAJOR_VERSION 0
+#define HIDIO_MINOR_VERSION 0
+
+/* static char *version = "$Revision: 1.1 $"; */
+
+/*------------------------------------------------------------------------------
+ * GLOBAL DEFINES
+ */
+
+#define DEFAULT_DELAY 5
+
+/* this is set to simplify data structures (arrays instead of linked lists) */
+#define MAX_DEVICES 128
+
+/* I think 64 is the limit per device as defined in the OS <hans@at.or.at> */
+#define MAX_ELEMENTS 64
+
+/* this is limited so that the object doesn't cause a click getting too many
+ * events from the OS's event queue */
+#define MAX_EVENTS_PER_POLL 64
+
+/*------------------------------------------------------------------------------
+ * CLASS DEF
+ */
+typedef struct _hidio
+
+{
+ t_object x_obj;
+ t_int x_fd;
+ void *x_ff_device;
+ short x_device_number;
+ short x_instance;
+ t_int x_has_ff;
+ t_int x_started;
+ t_int x_device_open;
+ t_int x_delay;
+ t_clock *x_clock;
+ t_outlet *x_data_outlet;
+ t_outlet *x_status_outlet;
+} t_hidio;
+
+
+
+/*------------------------------------------------------------------------------
+ * GLOBAL VARIABLES
+ */
+
+/* count the number of instances of this object so that certain free()
+ * functions can be called only after the final instance is detroyed.
+ */
+t_int hidio_instance_count;
+
+/* this is used to test for the first instance to execute */
+double last_execute_time[MAX_DEVICES];
+
+extern unsigned short global_debug_level;
+
+/* built up when the elements of an open device are enumerated */
+typedef struct _hid_element
+{
+#ifdef __linux__
+ /* GNU/Linux store type and code to compare against */
+ __u16 linux_type;
+ __u16 linux_code;
+#endif /* __linux__ */
+#ifdef _WIN32
+ /* this should be pointers to the UsagePage and Usage */
+#endif /* _WIN32 */
+#ifdef __APPLE__
+ void *pHIDElement; // pRecElement on Mac OS X; ... on Windows
+#endif /* __APPLE__ */
+ t_symbol *type; // Linux "type"; HID "usagePage"
+ t_symbol *name; // Linux "code"; HID "usage"
+ unsigned char polled; // is it polled or queued? (maybe only on Mac OS X?)
+ unsigned char relative; // relative data gets output everytime
+ t_int min; // from device report
+ t_int max; // from device report
+ t_float instance; // usage page/usage instance # ([absolute throttle 2 163(
+ t_int value; // output the sum of events in a poll for relative axes
+ t_int previous_value; //only output on change on abs and buttons
+} t_hid_element;
+
+/* mostly for status querying */
+unsigned short device_count;
+
+/* store element structs to eliminate symbol table lookups, etc. */
+t_hid_element *element[MAX_DEVICES][MAX_ELEMENTS];
+/* number of active elements per device */
+unsigned short element_count[MAX_DEVICES];
+
+/*------------------------------------------------------------------------------
+ * FUNCTION PROTOTYPES FOR DIFFERENT PLATFORMS
+ */
+
+/* support functions */
+void debug_print(t_int debug_level, const char *fmt, ...);
+void debug_error(t_hidio *x, t_int debug_level, const char *fmt, ...);
+void hidio_output_event(t_hidio *x, t_hid_element *output_data);
+
+
+/* generic, cross-platform functions implemented in a separate file for each
+ * platform
+ */
+t_int hidio_open_device(t_hidio *x, short device_number);
+t_int hidio_close_device(t_hidio *x);
+void hidio_build_device_list(void);
+void hidio_get_events(t_hidio *x);
+void hidio_print(t_hidio* x); /* print info to the console */
+void hidio_platform_specific_info(t_hidio* x); /* device info on the status outlet */
+void hidio_platform_specific_free(t_hidio *x);
+short get_device_number_by_id(unsigned short vendor_id, unsigned short product_id);
+/* TODO: this function should probably accept the single unsigned for the combined usage_page and usage, instead of two separate variables */
+short get_device_number_from_usage(short device_number,
+ unsigned short usage_page,
+ unsigned short usage);
+
+
+/* cross-platform force feedback functions */
+t_int hidio_ff_autocenter(t_hidio *x, t_float value);
+t_int hidio_ff_gain(t_hidio *x, t_float value);
+t_int hidio_ff_motors(t_hidio *x, t_float value);
+t_int hidio_ff_continue(t_hidio *x);
+t_int hidio_ff_pause(t_hidio *x);
+t_int hidio_ff_reset(t_hidio *x);
+t_int hidio_ff_stopall(t_hidio *x);
+
+// these are just for testing...
+t_int hidio_ff_fftest (t_hidio *x, t_float value);
+void hidio_ff_print(t_hidio *x);
+
+
+
+
+
+#endif /* #ifndef _HIDIO_H */
diff --git a/hidio_darwin.c b/hidio_darwin.c
new file mode 100644
index 0000000..35e1970
--- /dev/null
+++ b/hidio_darwin.c
@@ -0,0 +1,1468 @@
+#ifdef __APPLE__
+/*
+ * Apple Darwin HID Manager support for Pd [hidio] object
+ *
+ * some code from SuperCollider3's SC_HID.cpp by Jan Truetzschler Falkenstein
+ *
+ * Copyright (c) 2004 Hans-Christoph All rights reserved.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ */
+
+/* struct IOHIDEventStruct */
+/* { */
+/* IOHIDElementType type; */
+/* IOHIDElementCookie elementCookie; */
+/* SInt32 value; */
+/* AbsoluteTime timestamp; */
+/* UInt32 longValueSize; */
+/* void * longValue; */
+/* }; */
+
+/* typedef struct { */
+/* natural_t hi; */
+/* natural_t lo; */
+/* } AbsoluteTime; */
+
+
+
+#include <Carbon/Carbon.h>
+
+#include "HID_Utilities_External.h"
+#include "ImmrHIDUtilAddOn.h"
+
+#include <IOKit/hid/IOHIDUsageTables.h>
+#include <ForceFeedback/ForceFeedback.h>
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include "hidio.h"
+
+#define DEBUG(x)
+//#define DEBUG(x) x
+
+/*==============================================================================
+ * GLOBAL VARS
+ *======================================================================== */
+
+extern t_int hidio_instance_count; // in hidio.h
+
+/* store device pointers so I don't have to query them all the time */
+pRecDevice device_pointer[MAX_DEVICES];
+
+
+// this stuff is moving to the t_hid_element struct
+
+/* store element pointers for elements that are not queued (absolute axes) */
+//pRecElement element[MAX_DEVICES][MAX_ELEMENTS];
+/* number of active elements per device */
+//unsigned short element_count[MAX_DEVICES];
+
+/*==============================================================================
+ * FUNCTION PROTOTYPES
+ *==============================================================================
+ */
+
+/* conversion functions */
+static char *convertEventsFromDarwinToLinux(pRecElement element);
+
+/*==============================================================================
+ * EVENT TYPE/CODE CONVERSION FUNCTIONS
+ *==============================================================================
+ */
+
+/*
+ * This function is needed to translate the USB HID relative flag into the
+ * [hidio]/linux style events
+ */
+static void convert_axis_to_symbols(pRecElement pCurrentHIDElement, t_hid_element *new_element, char *axis)
+{
+ char buffer[MAXPDSTRING];
+ if (pCurrentHIDElement->relative)
+ {
+ new_element->type = gensym("rel");
+ snprintf(buffer, sizeof(buffer), "rel_%s", axis);
+ new_element->name = gensym(buffer);
+ }
+ else
+ {
+ new_element->type = gensym("abs");
+ snprintf(buffer, sizeof(buffer), "abs_%s", axis);
+ new_element->name = gensym(buffer);
+ }
+}
+
+
+static void get_usage_symbols(pRecElement pCurrentHIDElement, t_hid_element *new_element)
+{
+// debug_print(LOG_DEBUG,"get_usage_symbols");
+ char buffer[MAXPDSTRING];
+
+ if(new_element == NULL)
+ {
+ debug_print(LOG_EMERG,"[hidio] new_element == NULL!! This is a bug, please report it.");
+ return;
+ }
+ if(pCurrentHIDElement == NULL)
+ {
+ debug_print(LOG_EMERG,"[hidio] pCurrentHIDElement == NULL!! This is a bug, please report it.");
+ return;
+ }
+
+ switch(pCurrentHIDElement->type)
+ {
+ case kIOHIDElementTypeInput_Button:
+ new_element->type = gensym("key");
+ break;
+ }
+ switch (pCurrentHIDElement->usagePage)
+ {
+ case kHIDPage_GenericDesktop:
+ switch (pCurrentHIDElement->usage)
+ {
+ case kHIDUsage_GD_X: convert_axis_to_symbols(pCurrentHIDElement, new_element, "x"); break;
+ case kHIDUsage_GD_Y: convert_axis_to_symbols(pCurrentHIDElement, new_element, "y"); break;
+ case kHIDUsage_GD_Z: convert_axis_to_symbols(pCurrentHIDElement, new_element, "z"); break;
+ case kHIDUsage_GD_Rx: convert_axis_to_symbols(pCurrentHIDElement, new_element, "rx"); break;
+ case kHIDUsage_GD_Ry: convert_axis_to_symbols(pCurrentHIDElement, new_element, "ry"); break;
+ case kHIDUsage_GD_Rz: convert_axis_to_symbols(pCurrentHIDElement, new_element, "rz"); break;
+ case kHIDUsage_GD_Slider:
+ new_element->type = gensym("abs");
+ new_element->name = gensym("abs_throttle");
+ break;
+ case kHIDUsage_GD_Dial:
+ new_element->type = gensym("abs");
+ new_element->name = gensym("abs_ry");
+ break;
+ case kHIDUsage_GD_Wheel:
+ new_element->type = gensym("rel");
+ new_element->name = gensym("rel_wheel");
+ break;
+ case kHIDUsage_GD_Hatswitch:
+ // this is still a mystery how to handle
+ new_element->type = gensym("abs");
+ new_element->name = gensym("hatswitch");
+ break;
+ default:
+ new_element->type = gensym("DESKTOP");
+ snprintf(buffer, sizeof(buffer), "DESKTOP%ld", pCurrentHIDElement->usage);
+ new_element->name = gensym(buffer);
+ }
+ break;
+ case kHIDPage_Simulation:
+ switch (pCurrentHIDElement->usage)
+ {
+ case kHIDUsage_Sim_Rudder:
+ new_element->type = gensym("abs");
+ new_element->name = gensym("abs_rz");
+ break;
+ case kHIDUsage_Sim_Throttle:
+ new_element->type = gensym("abs");
+ new_element->name = gensym("abs_throttle");
+ break;
+ default:
+ new_element->type = gensym("SIMULATION");
+ snprintf(buffer, sizeof(buffer), "SIMULATION%ld", pCurrentHIDElement->usage);
+ new_element->name = gensym(buffer);
+ }
+ break;
+ case kHIDPage_KeyboardOrKeypad:
+ new_element->type = gensym("key");
+ /* temporary kludge until I feel like writing the translation table */
+ snprintf(buffer, sizeof(buffer), "key_%ld", pCurrentHIDElement->usage);
+ new_element->name = gensym(buffer);
+ break;
+ case kHIDPage_Button:
+ new_element->type = gensym("key");
+ /* HID Manager button numbers start at 1, [hidio] start at 0 */
+ snprintf(buffer, sizeof(buffer), "btn_%ld", pCurrentHIDElement->usage - 1);
+ new_element->name = gensym(buffer);
+ break;
+ case kHIDPage_LEDs:
+ /* temporary kludge until I feel like writing the translation table */
+ new_element->type = gensym("led");
+ snprintf(buffer, sizeof(buffer), "led_%ld", pCurrentHIDElement->usage);
+ new_element->name = gensym(buffer);
+ break;
+ case kHIDPage_PID:
+ /* temporary kludge until I feel like writing the translation table */
+ new_element->type = gensym("ff");
+ snprintf(buffer, sizeof(buffer), "ff_%ld", pCurrentHIDElement->usage);
+ new_element->name = gensym(buffer);
+ break;
+ default:
+ /* the rest are "vendor defined" so no translation table is possible */
+ snprintf(buffer, sizeof(buffer), "0x%04x", (unsigned int) pCurrentHIDElement->usagePage);
+ new_element->type = gensym(buffer);
+ snprintf(buffer, sizeof(buffer), "0x%04x", (unsigned int) pCurrentHIDElement->usage);
+ new_element->name = gensym(buffer);
+ }
+}
+
+
+static t_float get_type_name_instance(t_symbol *type, t_symbol *name,
+ int argc, t_hid_element **argv)
+{
+ int i;
+ int instance_count = 0;
+ for(i=0; i<argc; ++i)
+ {
+ if( (argv[i]->name == name) && (argv[i]->type == type) )
+ {
+ ++instance_count;
+// post("found %d instances of %s %s", instance_count, type->s_name, name->s_name);
+ }
+ }
+ return((t_float) instance_count);
+}
+
+
+/*
+ * Linux input events report hatswitches as absolute axes with -1, 0, 1 as
+ * possible values. MacOS X HID Manager reports hatswitches as a specific
+ * hatswitch type with each direction represented by a unique number. This
+ * function converts the unique number to the Linux style axes.
+ */
+
+/*
+ * hmm, not sure how to implement this cleanly yet,
+ * MacOS X represents this as one event, while [hidio] represents it as two
+ * distinct axes. So the conversion requires an added hidio_output_event().
+ void hidio_convert_hatswitch_values(IOHIDEventStruct event, t_symbol *type, t_atom *usage)
+ {
+ case 0:
+ name = gensym("abs_hat0y");value = 1;
+ hidio_output_event(x, type, name, value);
+ name = gensym("abs_hat0x");value = 0;
+ break;
+ case 1:
+ name = gensym("abs_hat0y");value = 1;
+ hidio_output_event(x, type, name, value);
+ name = gensym("abs_hat0x");value = 1;
+ break;
+ case 2:
+ name = gensym("abs_hat0y");value = 0;
+ hidio_output_event(x, type, name, value);
+ name = gensym("abs_hat0x");value = 1;
+ break;
+ case 3:
+ name = gensym("abs_hat0y");value = -1;
+ hidio_output_event(x, type, name, value);
+ name = gensym("abs_hat0x");value = 1;
+ break;
+ case 4:
+ name = gensym("abs_hat0y");value = -1;
+ hidio_output_event(x, type, name, value);
+ name = gensym("abs_hat0x");value = 0;
+ break;
+ case 5:
+ name = gensym("abs_hat0y");value = -1;
+ hidio_output_event(x, type, name, value);
+ name = gensym("abs_hat0x");value = -1;
+ break;
+ case 6:
+ name = gensym("abs_hat0y");value = 0;
+ hidio_output_event(x, type, name, value);
+ name = gensym("abs_hat0x");value = -1;
+ break;
+ case 7:
+ name = gensym("abs_hat0y");value = 1;
+ hidio_output_event(x, type, name, value);
+ name = gensym("abs_hat0x");value = -1;
+ break;
+ case 8:
+ name = gensym("abs_hat0y");value = 0;
+ hidio_output_event(x, type, name, value);
+ name = gensym("abs_hat0x");value = 0;
+ break;
+ }
+
+ }
+*/
+
+/* ============================================================================== */
+/* DARWIN-SPECIFIC SUPPORT FUNCTIONS */
+/* ============================================================================== */
+
+short get_device_number_by_id(unsigned short vendor_id, unsigned short product_id)
+{
+ debug_print(LOG_DEBUG,"get_device_number_from_usage");
+
+ pRecDevice pCurrentHIDDevice;
+ t_int i;
+ short return_device_number = -1;
+
+ if( !HIDHaveDeviceList() ) hidio_build_device_list();
+
+ pCurrentHIDDevice = HIDGetFirstDevice();
+ i = HIDCountDevices();
+ while(pCurrentHIDDevice != NULL)
+ {
+ --i;
+ debug_print(LOG_INFO,"compare 0x%04x == 0x%04x 0x%04x == 0x%04x",
+ pCurrentHIDDevice->vendorID,
+ vendor_id,
+ pCurrentHIDDevice->productID,
+ product_id);
+ if( (pCurrentHIDDevice->vendorID == vendor_id) &&
+ (pCurrentHIDDevice->productID == product_id) )
+ {
+ return_device_number = i;
+ pCurrentHIDDevice = NULL;
+ }
+ else
+ pCurrentHIDDevice = HIDGetNextDevice(pCurrentHIDDevice);
+ }
+ return(return_device_number);
+}
+
+short get_device_number_from_usage(short device_number,
+ unsigned short usage_page,
+ unsigned short usage)
+{
+// debug_print(LOG_DEBUG,"get_device_number_from_usage");
+
+ pRecDevice pCurrentHIDDevice;
+ t_int i;
+ short return_device_number = -1;
+ t_int total_devices = 0;
+ char cstrDeviceName[MAXPDSTRING];
+
+ if( !HIDHaveDeviceList() ) hidio_build_device_list();
+
+ pCurrentHIDDevice = HIDGetFirstDevice();
+ while(pCurrentHIDDevice != NULL)
+ {
+ if( (pCurrentHIDDevice->usagePage == usage_page) &&
+ (pCurrentHIDDevice->usage == usage) )
+ {
+ ++total_devices;
+ }
+ pCurrentHIDDevice = HIDGetNextDevice(pCurrentHIDDevice);
+ }
+ i = total_devices;
+ return_device_number = HIDCountDevices();
+ pCurrentHIDDevice = HIDGetFirstDevice();
+ while( (pCurrentHIDDevice != NULL) && (i > device_number) )
+ {
+ return_device_number--;
+ if( (pCurrentHIDDevice->usagePage == usage_page) &&
+ (pCurrentHIDDevice->usage == usage) )
+ {
+ i--;
+ HIDGetUsageName(pCurrentHIDDevice->usagePage,
+ pCurrentHIDDevice->usage,
+ cstrDeviceName);
+ debug_print(LOG_DEBUG,"[hidio]: found a %s at %d/%d: %s %s"
+ ,cstrDeviceName,
+ i,
+ total_devices,
+ pCurrentHIDDevice->manufacturer,
+ pCurrentHIDDevice->product);
+ }
+ pCurrentHIDDevice = HIDGetNextDevice(pCurrentHIDDevice);
+ }
+ if(i < total_devices)
+ return(return_device_number);
+ else
+ return(-1);
+}
+
+
+static void hidio_build_element_list(t_hidio *x)
+{
+ char type_name[256];
+ char usage_name[256];
+ pRecElement pCurrentHIDElement;
+ pRecDevice pCurrentHIDDevice = device_pointer[x->x_device_number];
+ t_hid_element *new_element;
+
+ element_count[x->x_device_number] = 0;
+ if( HIDIsValidDevice(pCurrentHIDDevice) )
+ {
+ /* queuing one element at a time only works for the first element, so
+ * try queuing the whole device, then removing specific elements from
+ * the queue */
+ HIDQueueDevice(pCurrentHIDDevice);
+ pCurrentHIDElement = HIDGetFirstDeviceElement( pCurrentHIDDevice,
+ kHIDElementTypeInput );
+ while( pCurrentHIDElement != NULL)
+ {
+ /* these two functions just get the pretty names for display */
+ HIDGetTypeName((IOHIDElementType) pCurrentHIDElement->type, type_name);
+ HIDGetUsageName(pCurrentHIDElement->usagePage,
+ pCurrentHIDElement->usage, usage_name);
+
+ new_element = getbytes(sizeof(t_hid_element));
+ new_element->pHIDElement = (void *) pCurrentHIDElement;
+ get_usage_symbols(pCurrentHIDElement, new_element);
+ new_element->relative = pCurrentHIDElement->relative;
+ new_element->instance = get_type_name_instance(new_element->type,
+ new_element->name,
+ element_count[x->x_device_number],
+ element[x->x_device_number]);
+
+ if( (pCurrentHIDElement->usagePage == kHIDPage_GenericDesktop) &&
+ (!pCurrentHIDElement->relative) )
+ {
+ switch(pCurrentHIDElement->usage)
+ {
+ case kHIDUsage_GD_X:
+ case kHIDUsage_GD_Y:
+ case kHIDUsage_GD_Z:
+ case kHIDUsage_GD_Rx:
+ case kHIDUsage_GD_Ry:
+ case kHIDUsage_GD_Rz:
+ case kHIDUsage_GD_Slider:
+ case kHIDUsage_GD_Dial:
+ case kHIDUsage_GD_Wheel:
+ //case kHIDUsage_GD_Hatswitch: // hatswitches are more like buttons, so queue them
+ debug_print(LOG_INFO,"[hidio] storing absolute axis to poll %s, %s (0x%04x 0x%04x)",
+ type_name, usage_name,
+ pCurrentHIDElement->usagePage, pCurrentHIDElement->usage);
+ if(HIDDequeueElement(pCurrentHIDDevice,pCurrentHIDElement) != kIOReturnSuccess)
+ debug_print(LOG_ERR,"[hidio] could not dequeue element");
+ new_element->polled = 1;
+ break;
+ }
+ }
+ else
+ {
+ debug_print(LOG_INFO,"[hidio] queuing element %s, %s (0x%04x 0x%04x)",
+ type_name, usage_name,
+ pCurrentHIDElement->usagePage, pCurrentHIDElement->usage);
+ }
+ new_element->min = pCurrentHIDElement->min;
+ new_element->max = pCurrentHIDElement->max;
+ debug_print(LOG_DEBUG,"\tlogical min %d max %d",
+ pCurrentHIDElement->min,pCurrentHIDElement->max);
+ element[x->x_device_number][element_count[x->x_device_number]] = new_element;
+ ++element_count[x->x_device_number];
+ pCurrentHIDElement = HIDGetNextDeviceElement(pCurrentHIDElement, kHIDElementTypeInput);
+ }
+ }
+}
+
+static void hidio_print_element_list(t_hidio *x)
+{
+// debug_print(LOG_DEBUG,"hidio_print_element_list");
+ int i;
+ pRecElement pCurrentHIDElement;
+ pRecDevice pCurrentHIDDevice;
+ t_hid_element *current_element;
+ char type_name[256];
+ char usage_name[256];
+
+ pCurrentHIDDevice = device_pointer[x->x_device_number];
+ if ( ! HIDIsValidDevice(pCurrentHIDDevice) )
+ {
+ error("[hidio]: device %d is not a valid device\n",x->x_device_number);
+ return;
+ }
+ post("[hidio] found %d elements:",element_count[x->x_device_number]);
+ post("\n TYPE\tCODE\t#\tEVENT NAME");
+ post("-----------------------------------------------------------");
+ for(i=0; i<element_count[x->x_device_number]; i++)
+ {
+ current_element = element[x->x_device_number][i];
+ pCurrentHIDElement = (pRecElement) current_element->pHIDElement;
+ HIDGetTypeName((IOHIDElementType) pCurrentHIDElement->type, type_name);
+ HIDGetUsageName(pCurrentHIDElement->usagePage,
+ pCurrentHIDElement->usage, usage_name);
+ post(" %s\t%s\t%d\t%s, %s", current_element->type->s_name,
+ current_element->name->s_name,(int) current_element->instance,
+ type_name, usage_name);
+ }
+ post("");
+}
+
+
+void hidio_ff_print( t_hidio *x )
+{
+ debug_print(LOG_DEBUG,"hidio_ff_print");
+ HRESULT result;
+ UInt32 value;
+
+ if ( x->x_has_ff )
+ {
+ result = FFDeviceGetForceFeedbackProperty( (FFDeviceObjectReference) x->x_ff_device,
+ FFPROP_AUTOCENTER,
+ &value,
+ (IOByteCount) sizeof( value ) );
+ if ( result == FF_OK ) post( "autocenter: %d",value );
+
+ result = FFDeviceGetForceFeedbackProperty( (FFDeviceObjectReference) x->x_ff_device,
+ FFPROP_FFGAIN,
+ &value,
+ (IOByteCount) sizeof( value ) );
+ if ( result == FF_OK ) post( "gain: %d", value );
+ }
+
+// FFEffectGetParameters( );
+}
+
+
+static void hidio_print_device_list(t_hidio *x)
+{
+ char device_type_buffer[256];
+ t_int i, numdevs;
+ unsigned int j;
+ pRecDevice pCurrentHIDDevice = NULL;
+
+ if( HIDHaveDeviceList() )
+ {
+ numdevs = (t_int) HIDCountDevices();
+
+ post("");
+ /* display device list in console */
+ for(i=0; i < numdevs; i++)
+ {
+ pCurrentHIDDevice = device_pointer[i];
+ post("__________________________________________________");
+ post("Device %d: '%s' '%s' version %d @ location 0x%08x", i,
+ pCurrentHIDDevice->manufacturer, pCurrentHIDDevice->product,
+ pCurrentHIDDevice->version,pCurrentHIDDevice->locID);
+ HIDGetUsageName(pCurrentHIDDevice->usagePage, pCurrentHIDDevice->usage,
+ device_type_buffer);
+ for(j=0; j< strlen(device_type_buffer); ++j)
+ device_type_buffer[j] = tolower(device_type_buffer[j]);
+ post("\tdevice type: %s\tusage page: 0x%04x\tusage: 0x%04x",
+ device_type_buffer, pCurrentHIDDevice->usagePage,
+ pCurrentHIDDevice->usage);
+ post("\tvendorID: 0x%04x\tproductID: 0x%04x",
+ pCurrentHIDDevice->vendorID, pCurrentHIDDevice->productID);
+ }
+ post("");
+ }
+}
+/* ==============================================================================
+ * STATUS/INFO OUTPUT
+ * ============================================================================== */
+
+void hidio_platform_specific_info(t_hidio *x)
+{
+ unsigned int i;
+ pRecDevice pCurrentHIDDevice = NULL;
+ char vendor_id_string[7];
+ char product_id_string[7];
+ char device_type_buffer[256];
+ t_symbol *output_symbol;
+ t_atom *output_atom = getbytes(sizeof(t_atom));
+
+ if(x->x_device_number > -1)
+ {
+// pCurrentHIDDevice = hidio_get_device_by_number(x->x_device_number);
+ pCurrentHIDDevice = device_pointer[x->x_device_number];
+ if(pCurrentHIDDevice != NULL)
+ {
+ /* product */
+ SETSYMBOL(output_atom, gensym(pCurrentHIDDevice->product));
+ outlet_anything( x->x_status_outlet, gensym("product"),
+ 1, output_atom);
+ /* manufacturer */
+ SETSYMBOL(output_atom, gensym(pCurrentHIDDevice->manufacturer));
+ outlet_anything( x->x_status_outlet, gensym("manufacturer"),
+ 1, output_atom);
+ /* serial number */
+ if(pCurrentHIDDevice->serial != NULL)
+ {
+ output_symbol = gensym(pCurrentHIDDevice->serial);
+ if( output_symbol != &s_ )
+ { /* the serial is rarely used on USB devices, so test for it */
+ SETSYMBOL(output_atom, output_symbol);
+ outlet_anything( x->x_status_outlet, gensym("serial"),
+ 1, output_atom);
+ }
+ }
+ /* transport */
+ SETSYMBOL(output_atom, gensym(pCurrentHIDDevice->transport));
+ outlet_anything( x->x_status_outlet, gensym("transport"),
+ 1, output_atom);
+ /* vendor id */
+ sprintf(vendor_id_string,"0x%04x",
+ (unsigned int)pCurrentHIDDevice->vendorID);
+ SETSYMBOL(output_atom, gensym(vendor_id_string));
+ outlet_anything( x->x_status_outlet, gensym("vendorID"),
+ 1, output_atom);
+ /* product id */
+ sprintf(product_id_string,"0x%04x",
+ (unsigned int)pCurrentHIDDevice->productID);
+ SETSYMBOL(output_atom, gensym(product_id_string));
+ outlet_anything( x->x_status_outlet, gensym("productID"),
+ 1, output_atom);
+ /* type */
+ HIDGetUsageName(pCurrentHIDDevice->usagePage,
+ pCurrentHIDDevice->usage,
+ device_type_buffer);
+ for(i=0; i< strlen(device_type_buffer); ++i)
+ device_type_buffer[i] = tolower(device_type_buffer[i]);
+ SETSYMBOL(output_atom, gensym(device_type_buffer));
+ outlet_anything( x->x_status_outlet, gensym("type"),
+ 1, output_atom);
+ }
+ }
+ freebytes(output_atom,sizeof(t_atom));
+}
+
+/* ============================================================================== */
+/* Pd [hidio] FUNCTIONS */
+/* ============================================================================== */
+
+void hidio_get_events(t_hidio *x)
+{
+ unsigned int i;
+ pRecDevice pCurrentHIDDevice;
+ t_hid_element *current_element;
+ IOHIDEventStruct event;
+
+ pCurrentHIDDevice = device_pointer[x->x_device_number];
+
+ /* get the queued events first and store them */
+// while( (HIDGetEvent(pCurrentHIDDevice, (void*) &event)) && (event_counter < MAX_EVENTS_PER_POLL) )
+ while(HIDGetEvent(pCurrentHIDDevice, (void*) &event))
+ {
+ i=0;
+ do {
+ current_element = element[x->x_device_number][i];
+ ++i;
+ } while( (i < element_count[x->x_device_number]) &&
+ (((pRecElement)current_element->pHIDElement)->cookie !=
+ (IOHIDElementCookie) event.elementCookie) );
+
+ current_element->value = event.value;
+ debug_print(LOG_DEBUG,"output this: %s %s %d prev %d",current_element->type->s_name,
+ current_element->name->s_name, current_element->value,
+ current_element->previous_value);
+ }
+ /* absolute axes don't need to be queued, they can just be polled */
+ for(i=0; i< element_count[x->x_device_number]; ++i)
+ {
+ current_element = element[x->x_device_number][i];
+ if(current_element->polled)
+ {
+ current_element->value =
+ HIDGetElementValue(pCurrentHIDDevice,
+ (pRecElement)current_element->pHIDElement);
+ }
+ }
+}
+
+
+t_int hidio_open_device(t_hidio *x, short device_number)
+{
+ debug_print(LOG_DEBUG,"hidio_open_device");
+
+ t_int result = 0;
+ pRecDevice pCurrentHIDDevice = NULL;
+
+ io_service_t hidDevice = 0;
+ FFDeviceObjectReference ffDeviceReference = NULL;
+
+/* rebuild device list to make sure the list is current */
+ if( !HIDHaveDeviceList() ) hidio_build_device_list();
+
+// pCurrentHIDDevice = hidio_get_device_by_number(device_number);
+ pCurrentHIDDevice = device_pointer[device_number];
+ if( HIDIsValidDevice(pCurrentHIDDevice) )
+ {
+ x->x_device_number = device_number;
+ }
+ else
+ {
+ debug_error(x,LOG_ERR,"[hidio]: device %d is not a valid device\n",device_number);
+ return(1);
+ }
+ debug_print(LOG_WARNING,"[hidio] opened device %d: %s %s",
+ device_number, pCurrentHIDDevice->manufacturer, pCurrentHIDDevice->product);
+
+ hidio_build_element_list(x);
+
+ hidDevice = AllocateHIDObjectFromRecDevice( pCurrentHIDDevice );
+ if( FFIsForceFeedback(hidDevice) == FF_OK )
+ {
+ debug_print(LOG_WARNING,"\tdevice has Force Feedback support");
+ if( FFCreateDevice(hidDevice,&ffDeviceReference) == FF_OK )
+ {
+ x->x_has_ff = 1;
+ x->x_ff_device = ffDeviceReference;
+ }
+ else
+ {
+ x->x_has_ff = 0;
+ post("[hidio]: FF device creation failed!");
+ return( -1 );
+ }
+ }
+ return(result);
+}
+
+
+t_int hidio_close_device(t_hidio *x)
+{
+ debug_print(LOG_DEBUG,"hidio_close_device");
+
+ t_int result = 0;
+// pRecDevice pCurrentHIDDevice = hidio_get_device_by_number(x->x_device_number);
+ pRecDevice pCurrentHIDDevice = device_pointer[x->x_device_number];
+
+ HIDDequeueDevice(pCurrentHIDDevice);
+// this doesn't seem to be needed at all, but why not use it?
+// result = HIDCloseReleaseInterface(pCurrentHIDDevice);
+
+ return(result);
+}
+
+
+void hidio_build_device_list(void)
+{
+ int device_number = 0;
+ pRecDevice pCurrentHIDDevice;
+
+ debug_print(LOG_DEBUG,"hidio_build_device_list");
+
+ debug_print(LOG_WARNING,"[hidio] Building device list...");
+ if(HIDBuildDeviceList (0, 0))
+ post("[hidio]: no HID devices found\n");
+
+/* The most recently discovered HID is the first element of the list here. I
+ * want the oldest to be number 0 rather than the newest. */
+ device_number = (int) HIDCountDevices();
+ pCurrentHIDDevice = HIDGetFirstDevice();
+ while(pCurrentHIDDevice != NULL)
+ {
+ --device_number;
+ if(device_number < MAX_DEVICES)
+ device_pointer[device_number] = pCurrentHIDDevice;
+ pCurrentHIDDevice = HIDGetNextDevice(pCurrentHIDDevice);
+ }
+ device_count = (unsigned int) HIDCountDevices(); // set the global variable
+ debug_print(LOG_WARNING,"[hidio] completed device list.");
+}
+
+
+void hidio_print(t_hidio *x)
+{
+ if( !HIDHaveDeviceList() ) hidio_build_device_list();
+ hidio_print_device_list(x);
+ if(x->x_device_open)
+ {
+ hidio_print_element_list(x);
+ hidio_ff_print(x);
+ }
+}
+
+
+void hidio_platform_specific_free(t_hidio *x)
+{
+ debug_print(LOG_DEBUG,"hidio_platform_specific_free");
+/* only call this if the last instance is being freed */
+ if (hidio_instance_count < 1)
+ {
+ DEBUG(post("RELEASE ALL hidio_instance_count: %d", hidio_instance_count););
+ HIDReleaseAllDeviceQueues();
+ HIDReleaseDeviceList();
+ }
+}
+
+
+/* ==============================================================================
+ * FORCE FEEDBACK
+ * ============================================================================== */
+
+/* --------------------------------------------------------------------------
+ * FF "Properties"
+ * autocenter ( 0/1 ), ffgain (overall feedback gain 0-10000)
+ */
+
+t_int hidio_ff_autocenter(t_hidio *x, t_float value)
+{
+ debug_print(LOG_DEBUG,"hidio_ff_autocenter");
+ HRESULT result;
+ UInt32 autocenter_value;
+
+ if( x->x_has_ff )
+ {
+ if ( value > 0 ) autocenter_value = 1;
+ else if ( value <= 0 ) autocenter_value = 0;
+ /* FFPROP_AUTOCENTER is either 0 or 1 */
+ result = FFDeviceSetForceFeedbackProperty(
+ (FFDeviceObjectReference) x->x_ff_device,
+ FFPROP_AUTOCENTER,
+ &autocenter_value );
+ if ( result != FF_OK )
+ {
+ post("[hidio]: ff_autocenter failed!");
+ }
+ }
+
+ return(0);
+}
+
+t_int hidio_ff_gain(t_hidio *x, t_float value)
+{
+ debug_print(LOG_DEBUG,"hidio_ff_gain");
+ HRESULT result;
+ UInt32 ffgain_value;
+
+ if( x->x_has_ff )
+ {
+ if ( value > 1 ) value = 1;
+ else if ( value < 0 ) value = 0;
+ ffgain_value = value * 10000;
+ /* FFPROP_FFGAIN has a integer range of 0-10000 */
+ result = FFDeviceSetForceFeedbackProperty(
+ (FFDeviceObjectReference)x->x_ff_device, FFPROP_FFGAIN, &ffgain_value );
+ if ( result != FF_OK )
+ {
+ post("[hidio]: ff_gain failed!");
+ }
+ }
+
+ return(0);
+}
+
+/* --------------------------------------------------------------------------
+ * FF "Commands"
+ * continue, pause, reset, setactuatorsoff, setactuatorson, stopall
+ */
+
+t_int hidio_ff_send_ff_command (t_hidio *x, UInt32 ff_command)
+{
+ HRESULT result = 0;
+
+ if( x->x_has_ff )
+ {
+ result = FFDeviceSendForceFeedbackCommand( x->x_ff_device, ff_command );
+ }
+
+ return ( (t_int) result );
+}
+
+t_int hidio_ff_continue( t_hidio *x )
+{
+ debug_print(LOG_DEBUG,"hidio_ff_continue");
+ return( hidio_ff_send_ff_command( x, FFSFFC_CONTINUE ) );
+}
+
+t_int hidio_ff_pause( t_hidio *x )
+{
+ debug_print(LOG_DEBUG,"hidio_ff_pause");
+ return( hidio_ff_send_ff_command( x, FFSFFC_PAUSE ) );
+}
+
+t_int hidio_ff_reset( t_hidio *x )
+{
+ debug_print(LOG_DEBUG,"hidio_ff_reset");
+ return( hidio_ff_send_ff_command( x, FFSFFC_RESET ) );
+}
+
+t_int hidio_ff_setactuatorsoff( t_hidio *x )
+{
+ debug_print(LOG_DEBUG,"hidio_ff_setactuatorsoff");
+ return( hidio_ff_send_ff_command( x, FFSFFC_SETACTUATORSOFF ) );
+}
+
+t_int hidio_ff_setactuatorson( t_hidio *x )
+{
+ debug_print(LOG_DEBUG,"hidio_ff_setactuatorson");
+ return( hidio_ff_send_ff_command( x, FFSFFC_SETACTUATORSON ) );
+}
+
+t_int hidio_ff_stopall( t_hidio *x )
+{
+ debug_print(LOG_DEBUG,"hidio_ff_stopall");
+ return( hidio_ff_send_ff_command( x, FFSFFC_STOPALL ) );
+}
+
+t_int hidio_ff_motors( t_hidio *x, t_float value )
+{
+ if ( value > 0 )
+ {
+ return ( hidio_ff_setactuatorson( x ) );
+ }
+ else
+ {
+ return ( hidio_ff_setactuatorsoff( x ) );
+ }
+}
+
+
+/* --------------------------------------------------------------------------
+ * FF test functions
+ */
+
+t_int hidio_ff_fftest ( t_hidio *x, t_float value)
+{
+ debug_print(LOG_DEBUG,"hidio_ff_fftest");
+
+ return( 0 );
+}
+
+/* ----------------------------------------------------------------------------------------------------
+ * the big monster look up table (not used yet)
+ */
+
+//void HIDGetUsageName (const long valueUsagePage, const long valueUsage, char * cstrName)
+char *convertEventsFromDarwinToLinux(pRecElement element)
+{
+ char *cstrName = "";
+// this allows these definitions to exist in an XML .plist file
+/* if (xml_GetUsageName(valueUsagePage, valueUsage, cstrName)) */
+/* return; */
+
+ switch (element->usagePage)
+ {
+ case kHIDPage_Undefined:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Undefined Page, Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_GenericDesktop:
+ switch (element->usage)
+ {
+ case kHIDUsage_GD_Pointer: sprintf (cstrName, "Pointer"); break;
+ case kHIDUsage_GD_Mouse: sprintf (cstrName, "Mouse"); break;
+ case kHIDUsage_GD_Joystick: sprintf (cstrName, "Joystick"); break;
+ case kHIDUsage_GD_GamePad: sprintf (cstrName, "GamePad"); break;
+ case kHIDUsage_GD_Keyboard: sprintf (cstrName, "Keyboard"); break;
+ case kHIDUsage_GD_Keypad: sprintf (cstrName, "Keypad"); break;
+ case kHIDUsage_GD_MultiAxisController: sprintf (cstrName, "Multi-Axis Controller"); break;
+
+ case kHIDUsage_GD_X: sprintf (cstrName, "X-Axis"); break;
+ case kHIDUsage_GD_Y: sprintf (cstrName, "Y-Axis"); break;
+ case kHIDUsage_GD_Z: sprintf (cstrName, "Z-Axis"); break;
+ case kHIDUsage_GD_Rx: sprintf (cstrName, "X-Rotation"); break;
+ case kHIDUsage_GD_Ry: sprintf (cstrName, "Y-Rotation"); break;
+ case kHIDUsage_GD_Rz: sprintf (cstrName, "Z-Rotation"); break;
+ case kHIDUsage_GD_Slider: sprintf (cstrName, "Slider"); break;
+ case kHIDUsage_GD_Dial: sprintf (cstrName, "Dial"); break;
+ case kHIDUsage_GD_Wheel: sprintf (cstrName, "Wheel"); break;
+ case kHIDUsage_GD_Hatswitch: sprintf (cstrName, "Hatswitch"); break;
+ case kHIDUsage_GD_CountedBuffer: sprintf (cstrName, "Counted Buffer"); break;
+ case kHIDUsage_GD_ByteCount: sprintf (cstrName, "Byte Count"); break;
+ case kHIDUsage_GD_MotionWakeup: sprintf (cstrName, "Motion Wakeup"); break;
+ case kHIDUsage_GD_Start: sprintf (cstrName, "Start"); break;
+ case kHIDUsage_GD_Select: sprintf (cstrName, "Select"); break;
+
+ case kHIDUsage_GD_Vx: sprintf (cstrName, "X-Velocity"); break;
+ case kHIDUsage_GD_Vy: sprintf (cstrName, "Y-Velocity"); break;
+ case kHIDUsage_GD_Vz: sprintf (cstrName, "Z-Velocity"); break;
+ case kHIDUsage_GD_Vbrx: sprintf (cstrName, "X-Rotation Velocity"); break;
+ case kHIDUsage_GD_Vbry: sprintf (cstrName, "Y-Rotation Velocity"); break;
+ case kHIDUsage_GD_Vbrz: sprintf (cstrName, "Z-Rotation Velocity"); break;
+ case kHIDUsage_GD_Vno: sprintf (cstrName, "Vno"); break;
+
+ case kHIDUsage_GD_SystemControl: sprintf (cstrName, "System Control"); break;
+ case kHIDUsage_GD_SystemPowerDown: sprintf (cstrName, "System Power Down"); break;
+ case kHIDUsage_GD_SystemSleep: sprintf (cstrName, "System Sleep"); break;
+ case kHIDUsage_GD_SystemWakeUp: sprintf (cstrName, "System Wake Up"); break;
+ case kHIDUsage_GD_SystemContextMenu: sprintf (cstrName, "System Context Menu"); break;
+ case kHIDUsage_GD_SystemMainMenu: sprintf (cstrName, "System Main Menu"); break;
+ case kHIDUsage_GD_SystemAppMenu: sprintf (cstrName, "System App Menu"); break;
+ case kHIDUsage_GD_SystemMenuHelp: sprintf (cstrName, "System Menu Help"); break;
+ case kHIDUsage_GD_SystemMenuExit: sprintf (cstrName, "System Menu Exit"); break;
+ case kHIDUsage_GD_SystemMenu: sprintf (cstrName, "System Menu"); break;
+ case kHIDUsage_GD_SystemMenuRight: sprintf (cstrName, "System Menu Right"); break;
+ case kHIDUsage_GD_SystemMenuLeft: sprintf (cstrName, "System Menu Left"); break;
+ case kHIDUsage_GD_SystemMenuUp: sprintf (cstrName, "System Menu Up"); break;
+ case kHIDUsage_GD_SystemMenuDown: sprintf (cstrName, "System Menu Down"); break;
+
+ case kHIDUsage_GD_DPadUp: sprintf (cstrName, "DPad Up"); break;
+ case kHIDUsage_GD_DPadDown: sprintf (cstrName, "DPad Down"); break;
+ case kHIDUsage_GD_DPadRight: sprintf (cstrName, "DPad Right"); break;
+ case kHIDUsage_GD_DPadLeft: sprintf (cstrName, "DPad Left"); break;
+
+ case kHIDUsage_GD_Reserved: sprintf (cstrName, "Reserved"); break;
+
+ default: sprintf (cstrName, "Generic Desktop Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_Simulation:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Simulation Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_VR:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "VR Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_Sport:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Sport Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_Game:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Game Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_KeyboardOrKeypad:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Keyboard Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_LEDs:
+ switch (element->usage)
+ {
+ // some LED usages
+ case kHIDUsage_LED_IndicatorRed: sprintf (cstrName, "Red LED"); break;
+ case kHIDUsage_LED_IndicatorGreen: sprintf (cstrName, "Green LED"); break;
+ case kHIDUsage_LED_IndicatorAmber: sprintf (cstrName, "Amber LED"); break;
+ case kHIDUsage_LED_GenericIndicator: sprintf (cstrName, "Generic LED"); break;
+ case kHIDUsage_LED_SystemSuspend: sprintf (cstrName, "System Suspend LED"); break;
+ case kHIDUsage_LED_ExternalPowerConnected: sprintf (cstrName, "External Power LED"); break;
+ default: sprintf (cstrName, "LED Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_Button:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Button #%ld", element->usage); break;
+ }
+ break;
+ case kHIDPage_Ordinal:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Ordinal Instance %lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_Telephony:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Telephony Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_Consumer:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Consumer Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_Digitizer:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Digitizer Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_PID:
+ if (((element->usage >= 0x02) && (element->usage <= 0x1F)) || ((element->usage >= 0x29) && (element->usage <= 0x2F)) ||
+ ((element->usage >= 0x35) && (element->usage <= 0x3F)) || ((element->usage >= 0x44) && (element->usage <= 0x4F)) ||
+ (element->usage == 0x8A) || (element->usage == 0x93) || ((element->usage >= 0x9D) && (element->usage <= 0x9E)) ||
+ ((element->usage >= 0xA1) && (element->usage <= 0xA3)) || ((element->usage >= 0xAD) && (element->usage <= 0xFFFF)))
+ sprintf (cstrName, "PID Reserved");
+ else
+ switch (element->usage)
+ {
+ case 0x00: sprintf (cstrName, "PID Undefined Usage"); break;
+ case kHIDUsage_PID_PhysicalInterfaceDevice: sprintf (cstrName, "Physical Interface Device"); break;
+ case kHIDUsage_PID_Normal: sprintf (cstrName, "Normal Force"); break;
+
+ case kHIDUsage_PID_SetEffectReport: sprintf (cstrName, "Set Effect Report"); break;
+ case kHIDUsage_PID_EffectBlockIndex: sprintf (cstrName, "Effect Block Index"); break;
+ case kHIDUsage_PID_ParamBlockOffset: sprintf (cstrName, "Parameter Block Offset"); break;
+ case kHIDUsage_PID_ROM_Flag: sprintf (cstrName, "ROM Flag"); break;
+
+ case kHIDUsage_PID_EffectType: sprintf (cstrName, "Effect Type"); break;
+ case kHIDUsage_PID_ET_ConstantForce: sprintf (cstrName, "Effect Type Constant Force"); break;
+ case kHIDUsage_PID_ET_Ramp: sprintf (cstrName, "Effect Type Ramp"); break;
+ case kHIDUsage_PID_ET_CustomForceData: sprintf (cstrName, "Effect Type Custom Force Data"); break;
+ case kHIDUsage_PID_ET_Square: sprintf (cstrName, "Effect Type Square"); break;
+ case kHIDUsage_PID_ET_Sine: sprintf (cstrName, "Effect Type Sine"); break;
+ case kHIDUsage_PID_ET_Triangle: sprintf (cstrName, "Effect Type Triangle"); break;
+ case kHIDUsage_PID_ET_SawtoothUp: sprintf (cstrName, "Effect Type Sawtooth Up"); break;
+ case kHIDUsage_PID_ET_SawtoothDown: sprintf (cstrName, "Effect Type Sawtooth Down"); break;
+ case kHIDUsage_PID_ET_Spring: sprintf (cstrName, "Effect Type Spring"); break;
+ case kHIDUsage_PID_ET_Damper: sprintf (cstrName, "Effect Type Damper"); break;
+ case kHIDUsage_PID_ET_Inertia: sprintf (cstrName, "Effect Type Inertia"); break;
+ case kHIDUsage_PID_ET_Friction: sprintf (cstrName, "Effect Type Friction"); break;
+ case kHIDUsage_PID_Duration: sprintf (cstrName, "Effect Duration"); break;
+ case kHIDUsage_PID_SamplePeriod: sprintf (cstrName, "Effect Sample Period"); break;
+ case kHIDUsage_PID_Gain: sprintf (cstrName, "Effect Gain"); break;
+ case kHIDUsage_PID_TriggerButton: sprintf (cstrName, "Effect Trigger Button"); break;
+ case kHIDUsage_PID_TriggerRepeatInterval: sprintf (cstrName, "Effect Trigger Repeat Interval"); break;
+
+ case kHIDUsage_PID_AxesEnable: sprintf (cstrName, "Axis Enable"); break;
+ case kHIDUsage_PID_DirectionEnable: sprintf (cstrName, "Direction Enable"); break;
+
+ case kHIDUsage_PID_Direction: sprintf (cstrName, "Direction"); break;
+
+ case kHIDUsage_PID_TypeSpecificBlockOffset: sprintf (cstrName, "Type Specific Block Offset"); break;
+
+ case kHIDUsage_PID_BlockType: sprintf (cstrName, "Block Type"); break;
+
+ case kHIDUsage_PID_SetEnvelopeReport: sprintf (cstrName, "Set Envelope Report"); break;
+ case kHIDUsage_PID_AttackLevel: sprintf (cstrName, "Envelope Attack Level"); break;
+ case kHIDUsage_PID_AttackTime: sprintf (cstrName, "Envelope Attack Time"); break;
+ case kHIDUsage_PID_FadeLevel: sprintf (cstrName, "Envelope Fade Level"); break;
+ case kHIDUsage_PID_FadeTime: sprintf (cstrName, "Envelope Fade Time"); break;
+
+ case kHIDUsage_PID_SetConditionReport: sprintf (cstrName, "Set Condition Report"); break;
+ case kHIDUsage_PID_CP_Offset: sprintf (cstrName, "Condition CP Offset"); break;
+ case kHIDUsage_PID_PositiveCoefficient: sprintf (cstrName, "Condition Positive Coefficient"); break;
+ case kHIDUsage_PID_NegativeCoefficient: sprintf (cstrName, "Condition Negative Coefficient"); break;
+ case kHIDUsage_PID_PositiveSaturation: sprintf (cstrName, "Condition Positive Saturation"); break;
+ case kHIDUsage_PID_NegativeSaturation: sprintf (cstrName, "Condition Negative Saturation"); break;
+ case kHIDUsage_PID_DeadBand: sprintf (cstrName, "Condition Dead Band"); break;
+
+ case kHIDUsage_PID_DownloadForceSample: sprintf (cstrName, "Download Force Sample"); break;
+ case kHIDUsage_PID_IsochCustomForceEnable: sprintf (cstrName, "Isoch Custom Force Enable"); break;
+
+ case kHIDUsage_PID_CustomForceDataReport: sprintf (cstrName, "Custom Force Data Report"); break;
+ case kHIDUsage_PID_CustomForceData: sprintf (cstrName, "Custom Force Data"); break;
+
+ case kHIDUsage_PID_CustomForceVendorDefinedData: sprintf (cstrName, "Custom Force Vendor Defined Data"); break;
+ case kHIDUsage_PID_SetCustomForceReport: sprintf (cstrName, "Set Custom Force Report"); break;
+ case kHIDUsage_PID_CustomForceDataOffset: sprintf (cstrName, "Custom Force Data Offset"); break;
+ case kHIDUsage_PID_SampleCount: sprintf (cstrName, "Custom Force Sample Count"); break;
+
+ case kHIDUsage_PID_SetPeriodicReport: sprintf (cstrName, "Set Periodic Report"); break;
+ case kHIDUsage_PID_Offset: sprintf (cstrName, "Periodic Offset"); break;
+ case kHIDUsage_PID_Magnitude: sprintf (cstrName, "Periodic Magnitude"); break;
+ case kHIDUsage_PID_Phase: sprintf (cstrName, "Periodic Phase"); break;
+ case kHIDUsage_PID_Period: sprintf (cstrName, "Periodic Period"); break;
+
+ case kHIDUsage_PID_SetConstantForceReport: sprintf (cstrName, "Set Constant Force Report"); break;
+
+ case kHIDUsage_PID_SetRampForceReport: sprintf (cstrName, "Set Ramp Force Report"); break;
+ case kHIDUsage_PID_RampStart: sprintf (cstrName, "Ramp Start"); break;
+ case kHIDUsage_PID_RampEnd: sprintf (cstrName, "Ramp End"); break;
+
+ case kHIDUsage_PID_EffectOperationReport: sprintf (cstrName, "Effect Operation Report"); break;
+
+ case kHIDUsage_PID_EffectOperation: sprintf (cstrName, "Effect Operation"); break;
+ case kHIDUsage_PID_OpEffectStart: sprintf (cstrName, "Op Effect Start"); break;
+ case kHIDUsage_PID_OpEffectStartSolo: sprintf (cstrName, "Op Effect Start Solo"); break;
+ case kHIDUsage_PID_OpEffectStop: sprintf (cstrName, "Op Effect Stop"); break;
+ case kHIDUsage_PID_LoopCount: sprintf (cstrName, "Op Effect Loop Count"); break;
+
+ case kHIDUsage_PID_DeviceGainReport: sprintf (cstrName, "Device Gain Report"); break;
+ case kHIDUsage_PID_DeviceGain: sprintf (cstrName, "Device Gain"); break;
+
+ case kHIDUsage_PID_PoolReport: sprintf (cstrName, "PID Pool Report"); break;
+ case kHIDUsage_PID_RAM_PoolSize: sprintf (cstrName, "RAM Pool Size"); break;
+ case kHIDUsage_PID_ROM_PoolSize: sprintf (cstrName, "ROM Pool Size"); break;
+ case kHIDUsage_PID_ROM_EffectBlockCount: sprintf (cstrName, "ROM Effect Block Count"); break;
+ case kHIDUsage_PID_SimultaneousEffectsMax: sprintf (cstrName, "Simultaneous Effects Max"); break;
+ case kHIDUsage_PID_PoolAlignment: sprintf (cstrName, "Pool Alignment"); break;
+
+ case kHIDUsage_PID_PoolMoveReport: sprintf (cstrName, "PID Pool Move Report"); break;
+ case kHIDUsage_PID_MoveSource: sprintf (cstrName, "Move Source"); break;
+ case kHIDUsage_PID_MoveDestination: sprintf (cstrName, "Move Destination"); break;
+ case kHIDUsage_PID_MoveLength: sprintf (cstrName, "Move Length"); break;
+
+ case kHIDUsage_PID_BlockLoadReport: sprintf (cstrName, "PID Block Load Report"); break;
+
+ case kHIDUsage_PID_BlockLoadStatus: sprintf (cstrName, "Block Load Status"); break;
+ case kHIDUsage_PID_BlockLoadSuccess: sprintf (cstrName, "Block Load Success"); break;
+ case kHIDUsage_PID_BlockLoadFull: sprintf (cstrName, "Block Load Full"); break;
+ case kHIDUsage_PID_BlockLoadError: sprintf (cstrName, "Block Load Error"); break;
+ case kHIDUsage_PID_BlockHandle: sprintf (cstrName, "Block Handle"); break;
+
+ case kHIDUsage_PID_BlockFreeReport: sprintf (cstrName, "PID Block Free Report"); break;
+
+ case kHIDUsage_PID_TypeSpecificBlockHandle: sprintf (cstrName, "Type Specific Block Handle"); break;
+
+ case kHIDUsage_PID_StateReport: sprintf (cstrName, "PID State Report"); break;
+ case kHIDUsage_PID_EffectPlaying: sprintf (cstrName, "Effect Playing"); break;
+
+ case kHIDUsage_PID_DeviceControlReport: sprintf (cstrName, "PID Device Control Report"); break;
+
+ case kHIDUsage_PID_DeviceControl: sprintf (cstrName, "PID Device Control"); break;
+ case kHIDUsage_PID_DC_EnableActuators: sprintf (cstrName, "Device Control Enable Actuators"); break;
+ case kHIDUsage_PID_DC_DisableActuators: sprintf (cstrName, "Device Control Disable Actuators"); break;
+ case kHIDUsage_PID_DC_StopAllEffects: sprintf (cstrName, "Device Control Stop All Effects"); break;
+ case kHIDUsage_PID_DC_DeviceReset: sprintf (cstrName, "Device Control Reset"); break;
+ case kHIDUsage_PID_DC_DevicePause: sprintf (cstrName, "Device Control Pause"); break;
+ case kHIDUsage_PID_DC_DeviceContinue: sprintf (cstrName, "Device Control Continue"); break;
+ case kHIDUsage_PID_DevicePaused: sprintf (cstrName, "Device Paused"); break;
+ case kHIDUsage_PID_ActuatorsEnabled: sprintf (cstrName, "Actuators Enabled"); break;
+ case kHIDUsage_PID_SafetySwitch: sprintf (cstrName, "Safety Switch"); break;
+ case kHIDUsage_PID_ActuatorOverrideSwitch: sprintf (cstrName, "Actuator Override Switch"); break;
+ case kHIDUsage_PID_ActuatorPower: sprintf (cstrName, "Actuator Power"); break;
+ case kHIDUsage_PID_StartDelay: sprintf (cstrName, "Start Delay"); break;
+
+ case kHIDUsage_PID_ParameterBlockSize: sprintf (cstrName, "Parameter Block Size"); break;
+ case kHIDUsage_PID_DeviceManagedPool: sprintf (cstrName, "Device Managed Pool"); break;
+ case kHIDUsage_PID_SharedParameterBlocks: sprintf (cstrName, "Shared Parameter Blocks"); break;
+
+ case kHIDUsage_PID_CreateNewEffectReport: sprintf (cstrName, "Create New Effect Report"); break;
+ case kHIDUsage_PID_RAM_PoolAvailable: sprintf (cstrName, "RAM Pool Available"); break;
+ default: sprintf (cstrName, "PID Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_Unicode:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Unicode Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_PowerDevice:
+ if (((element->usage >= 0x06) && (element->usage <= 0x0F)) || ((element->usage >= 0x26) && (element->usage <= 0x2F)) ||
+ ((element->usage >= 0x39) && (element->usage <= 0x3F)) || ((element->usage >= 0x48) && (element->usage <= 0x4F)) ||
+ ((element->usage >= 0x58) && (element->usage <= 0x5F)) || (element->usage == 0x6A) ||
+ ((element->usage >= 0x74) && (element->usage <= 0xFC)))
+ sprintf (cstrName, "Power Device Reserved");
+ else
+ switch (element->usage)
+ {
+ case kHIDUsage_PD_Undefined: sprintf (cstrName, "Power Device Undefined Usage"); break;
+ case kHIDUsage_PD_iName: sprintf (cstrName, "Power Device Name Index"); break;
+ case kHIDUsage_PD_PresentStatus: sprintf (cstrName, "Power Device Present Status"); break;
+ case kHIDUsage_PD_ChangedStatus: sprintf (cstrName, "Power Device Changed Status"); break;
+ case kHIDUsage_PD_UPS: sprintf (cstrName, "Uninterruptible Power Supply"); break;
+ case kHIDUsage_PD_PowerSupply: sprintf (cstrName, "Power Supply"); break;
+
+ case kHIDUsage_PD_BatterySystem: sprintf (cstrName, "Battery System Power Module"); break;
+ case kHIDUsage_PD_BatterySystemID: sprintf (cstrName, "Battery System ID"); break;
+ case kHIDUsage_PD_Battery: sprintf (cstrName, "Battery"); break;
+ case kHIDUsage_PD_BatteryID: sprintf (cstrName, "Battery ID"); break;
+ case kHIDUsage_PD_Charger: sprintf (cstrName, "Charger"); break;
+ case kHIDUsage_PD_ChargerID: sprintf (cstrName, "Charger ID"); break;
+ case kHIDUsage_PD_PowerConverter: sprintf (cstrName, "Power Converter Power Module"); break;
+ case kHIDUsage_PD_PowerConverterID: sprintf (cstrName, "Power Converter ID"); break;
+ case kHIDUsage_PD_OutletSystem: sprintf (cstrName, "Outlet System power module"); break;
+ case kHIDUsage_PD_OutletSystemID: sprintf (cstrName, "Outlet System ID"); break;
+ case kHIDUsage_PD_Input: sprintf (cstrName, "Power Device Input"); break;
+ case kHIDUsage_PD_InputID: sprintf (cstrName, "Power Device Input ID"); break;
+ case kHIDUsage_PD_Output: sprintf (cstrName, "Power Device Output"); break;
+ case kHIDUsage_PD_OutputID: sprintf (cstrName, "Power Device Output ID"); break;
+ case kHIDUsage_PD_Flow: sprintf (cstrName, "Power Device Flow"); break;
+ case kHIDUsage_PD_FlowID: sprintf (cstrName, "Power Device Flow ID"); break;
+ case kHIDUsage_PD_Outlet: sprintf (cstrName, "Power Device Outlet"); break;
+ case kHIDUsage_PD_OutletID: sprintf (cstrName, "Power Device Outlet ID"); break;
+ case kHIDUsage_PD_Gang: sprintf (cstrName, "Power Device Gang"); break;
+ case kHIDUsage_PD_GangID: sprintf (cstrName, "Power Device Gang ID"); break;
+ case kHIDUsage_PD_PowerSummary: sprintf (cstrName, "Power Device Power Summary"); break;
+ case kHIDUsage_PD_PowerSummaryID: sprintf (cstrName, "Power Device Power Summary ID"); break;
+
+ case kHIDUsage_PD_Voltage: sprintf (cstrName, "Power Device Voltage"); break;
+ case kHIDUsage_PD_Current: sprintf (cstrName, "Power Device Current"); break;
+ case kHIDUsage_PD_Frequency: sprintf (cstrName, "Power Device Frequency"); break;
+ case kHIDUsage_PD_ApparentPower: sprintf (cstrName, "Power Device Apparent Power"); break;
+ case kHIDUsage_PD_ActivePower: sprintf (cstrName, "Power Device RMS Power"); break;
+ case kHIDUsage_PD_PercentLoad: sprintf (cstrName, "Power Device Percent Load"); break;
+ case kHIDUsage_PD_Temperature: sprintf (cstrName, "Power Device Temperature"); break;
+ case kHIDUsage_PD_Humidity: sprintf (cstrName, "Power Device Humidity"); break;
+ case kHIDUsage_PD_BadCount: sprintf (cstrName, "Power Device Bad Condition Count"); break;
+
+ case kHIDUsage_PD_ConfigVoltage: sprintf (cstrName, "Power Device Nominal Voltage"); break;
+ case kHIDUsage_PD_ConfigCurrent: sprintf (cstrName, "Power Device Nominal Current"); break;
+ case kHIDUsage_PD_ConfigFrequency: sprintf (cstrName, "Power Device Nominal Frequency"); break;
+ case kHIDUsage_PD_ConfigApparentPower: sprintf (cstrName, "Power Device Nominal Apparent Power"); break;
+ case kHIDUsage_PD_ConfigActivePower: sprintf (cstrName, "Power Device Nominal RMS Power"); break;
+ case kHIDUsage_PD_ConfigPercentLoad: sprintf (cstrName, "Power Device Nominal Percent Load"); break;
+ case kHIDUsage_PD_ConfigTemperature: sprintf (cstrName, "Power Device Nominal Temperature"); break;
+
+ case kHIDUsage_PD_ConfigHumidity: sprintf (cstrName, "Power Device Nominal Humidity"); break;
+ case kHIDUsage_PD_SwitchOnControl: sprintf (cstrName, "Power Device Switch On Control"); break;
+ case kHIDUsage_PD_SwitchOffControl: sprintf (cstrName, "Power Device Switch Off Control"); break;
+ case kHIDUsage_PD_ToggleControl: sprintf (cstrName, "Power Device Toogle Sequence Control"); break;
+ case kHIDUsage_PD_LowVoltageTransfer: sprintf (cstrName, "Power Device Min Transfer Voltage"); break;
+ case kHIDUsage_PD_HighVoltageTransfer: sprintf (cstrName, "Power Device Max Transfer Voltage"); break;
+ case kHIDUsage_PD_DelayBeforeReboot: sprintf (cstrName, "Power Device Delay Before Reboot"); break;
+ case kHIDUsage_PD_DelayBeforeStartup: sprintf (cstrName, "Power Device Delay Before Startup"); break;
+ case kHIDUsage_PD_DelayBeforeShutdown: sprintf (cstrName, "Power Device Delay Before Shutdown"); break;
+ case kHIDUsage_PD_Test: sprintf (cstrName, "Power Device Test Request/Result"); break;
+ case kHIDUsage_PD_ModuleReset: sprintf (cstrName, "Power Device Reset Request/Result"); break;
+ case kHIDUsage_PD_AudibleAlarmControl: sprintf (cstrName, "Power Device Audible Alarm Control"); break;
+
+ case kHIDUsage_PD_Present: sprintf (cstrName, "Power Device Present"); break;
+ case kHIDUsage_PD_Good: sprintf (cstrName, "Power Device Good"); break;
+ case kHIDUsage_PD_InternalFailure: sprintf (cstrName, "Power Device Internal Failure"); break;
+ case kHIDUsage_PD_VoltageOutOfRange: sprintf (cstrName, "Power Device Voltage Out Of Range"); break;
+ case kHIDUsage_PD_FrequencyOutOfRange: sprintf (cstrName, "Power Device Frequency Out Of Range"); break;
+ case kHIDUsage_PD_Overload: sprintf (cstrName, "Power Device Overload"); break;
+ case kHIDUsage_PD_OverCharged: sprintf (cstrName, "Power Device Over Charged"); break;
+ case kHIDUsage_PD_OverTemperature: sprintf (cstrName, "Power Device Over Temperature"); break;
+ case kHIDUsage_PD_ShutdownRequested: sprintf (cstrName, "Power Device Shutdown Requested"); break;
+
+ case kHIDUsage_PD_ShutdownImminent: sprintf (cstrName, "Power Device Shutdown Imminent"); break;
+ case kHIDUsage_PD_SwitchOnOff: sprintf (cstrName, "Power Device On/Off Switch Status"); break;
+ case kHIDUsage_PD_Switchable: sprintf (cstrName, "Power Device Switchable"); break;
+ case kHIDUsage_PD_Used: sprintf (cstrName, "Power Device Used"); break;
+ case kHIDUsage_PD_Boost: sprintf (cstrName, "Power Device Boosted"); break;
+ case kHIDUsage_PD_Buck: sprintf (cstrName, "Power Device Bucked"); break;
+ case kHIDUsage_PD_Initialized: sprintf (cstrName, "Power Device Initialized"); break;
+ case kHIDUsage_PD_Tested: sprintf (cstrName, "Power Device Tested"); break;
+ case kHIDUsage_PD_AwaitingPower: sprintf (cstrName, "Power Device Awaiting Power"); break;
+ case kHIDUsage_PD_CommunicationLost: sprintf (cstrName, "Power Device Communication Lost"); break;
+
+ case kHIDUsage_PD_iManufacturer: sprintf (cstrName, "Power Device Manufacturer String Index"); break;
+ case kHIDUsage_PD_iProduct: sprintf (cstrName, "Power Device Product String Index"); break;
+ case kHIDUsage_PD_iserialNumber: sprintf (cstrName, "Power Device Serial Number String Index"); break;
+ default: sprintf (cstrName, "Power Device Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_BatterySystem:
+ if (((element->usage >= 0x0A) && (element->usage <= 0x0F)) || ((element->usage >= 0x1E) && (element->usage <= 0x27)) ||
+ ((element->usage >= 0x30) && (element->usage <= 0x3F)) || ((element->usage >= 0x4C) && (element->usage <= 0x5F)) ||
+ ((element->usage >= 0x6C) && (element->usage <= 0x7F)) || ((element->usage >= 0x90) && (element->usage <= 0xBF)) ||
+ ((element->usage >= 0xC3) && (element->usage <= 0xCF)) || ((element->usage >= 0xDD) && (element->usage <= 0xEF)) ||
+ ((element->usage >= 0xF2) && (element->usage <= 0xFF)))
+ sprintf (cstrName, "Power Device Reserved");
+ else
+ switch (element->usage)
+ {
+ case kHIDUsage_BS_Undefined: sprintf (cstrName, "Battery System Undefined"); break;
+ case kHIDUsage_BS_SMBBatteryMode: sprintf (cstrName, "SMB Mode"); break;
+ case kHIDUsage_BS_SMBBatteryStatus: sprintf (cstrName, "SMB Status"); break;
+ case kHIDUsage_BS_SMBAlarmWarning: sprintf (cstrName, "SMB Alarm Warning"); break;
+ case kHIDUsage_BS_SMBChargerMode: sprintf (cstrName, "SMB Charger Mode"); break;
+ case kHIDUsage_BS_SMBChargerStatus: sprintf (cstrName, "SMB Charger Status"); break;
+ case kHIDUsage_BS_SMBChargerSpecInfo: sprintf (cstrName, "SMB Charger Extended Status"); break;
+ case kHIDUsage_BS_SMBSelectorState: sprintf (cstrName, "SMB Selector State"); break;
+ case kHIDUsage_BS_SMBSelectorPresets: sprintf (cstrName, "SMB Selector Presets"); break;
+ case kHIDUsage_BS_SMBSelectorInfo: sprintf (cstrName, "SMB Selector Info"); break;
+ case kHIDUsage_BS_OptionalMfgFunction1: sprintf (cstrName, "Battery System Optional SMB Mfg Function 1"); break;
+ case kHIDUsage_BS_OptionalMfgFunction2: sprintf (cstrName, "Battery System Optional SMB Mfg Function 2"); break;
+ case kHIDUsage_BS_OptionalMfgFunction3: sprintf (cstrName, "Battery System Optional SMB Mfg Function 3"); break;
+ case kHIDUsage_BS_OptionalMfgFunction4: sprintf (cstrName, "Battery System Optional SMB Mfg Function 4"); break;
+ case kHIDUsage_BS_OptionalMfgFunction5: sprintf (cstrName, "Battery System Optional SMB Mfg Function 5"); break;
+ case kHIDUsage_BS_ConnectionToSMBus: sprintf (cstrName, "Battery System Connection To System Management Bus"); break;
+ case kHIDUsage_BS_OutputConnection: sprintf (cstrName, "Battery System Output Connection Status"); break;
+ case kHIDUsage_BS_ChargerConnection: sprintf (cstrName, "Battery System Charger Connection"); break;
+ case kHIDUsage_BS_BatteryInsertion: sprintf (cstrName, "Battery System Battery Insertion"); break;
+ case kHIDUsage_BS_Usenext: sprintf (cstrName, "Battery System Use Next"); break;
+ case kHIDUsage_BS_OKToUse: sprintf (cstrName, "Battery System OK To Use"); break;
+ case kHIDUsage_BS_BatterySupported: sprintf (cstrName, "Battery System Battery Supported"); break;
+ case kHIDUsage_BS_SelectorRevision: sprintf (cstrName, "Battery System Selector Revision"); break;
+ case kHIDUsage_BS_ChargingIndicator: sprintf (cstrName, "Battery System Charging Indicator"); break;
+ case kHIDUsage_BS_ManufacturerAccess: sprintf (cstrName, "Battery System Manufacturer Access"); break;
+ case kHIDUsage_BS_RemainingCapacityLimit: sprintf (cstrName, "Battery System Remaining Capacity Limit"); break;
+ case kHIDUsage_BS_RemainingTimeLimit: sprintf (cstrName, "Battery System Remaining Time Limit"); break;
+ case kHIDUsage_BS_AtRate: sprintf (cstrName, "Battery System At Rate..."); break;
+ case kHIDUsage_BS_CapacityMode: sprintf (cstrName, "Battery System Capacity Mode"); break;
+ case kHIDUsage_BS_BroadcastToCharger: sprintf (cstrName, "Battery System Broadcast To Charger"); break;
+ case kHIDUsage_BS_PrimaryBattery: sprintf (cstrName, "Battery System Primary Battery"); break;
+ case kHIDUsage_BS_ChargeController: sprintf (cstrName, "Battery System Charge Controller"); break;
+ case kHIDUsage_BS_TerminateCharge: sprintf (cstrName, "Battery System Terminate Charge"); break;
+ case kHIDUsage_BS_TerminateDischarge: sprintf (cstrName, "Battery System Terminate Discharge"); break;
+ case kHIDUsage_BS_BelowRemainingCapacityLimit: sprintf (cstrName, "Battery System Below Remaining Capacity Limit"); break;
+ case kHIDUsage_BS_RemainingTimeLimitExpired: sprintf (cstrName, "Battery System Remaining Time Limit Expired"); break;
+ case kHIDUsage_BS_Charging: sprintf (cstrName, "Battery System Charging"); break;
+ case kHIDUsage_BS_Discharging: sprintf (cstrName, "Battery System Discharging"); break;
+ case kHIDUsage_BS_FullyCharged: sprintf (cstrName, "Battery System Fully Charged"); break;
+ case kHIDUsage_BS_FullyDischarged: sprintf (cstrName, "Battery System Fully Discharged"); break;
+ case kHIDUsage_BS_ConditioningFlag: sprintf (cstrName, "Battery System Conditioning Flag"); break;
+ case kHIDUsage_BS_AtRateOK: sprintf (cstrName, "Battery System At Rate OK"); break;
+ case kHIDUsage_BS_SMBErrorCode: sprintf (cstrName, "Battery System SMB Error Code"); break;
+ case kHIDUsage_BS_NeedReplacement: sprintf (cstrName, "Battery System Need Replacement"); break;
+ case kHIDUsage_BS_AtRateTimeToFull: sprintf (cstrName, "Battery System At Rate Time To Full"); break;
+ case kHIDUsage_BS_AtRateTimeToEmpty: sprintf (cstrName, "Battery System At Rate Time To Empty"); break;
+ case kHIDUsage_BS_AverageCurrent: sprintf (cstrName, "Battery System Average Current"); break;
+ case kHIDUsage_BS_Maxerror: sprintf (cstrName, "Battery System Max Error"); break;
+ case kHIDUsage_BS_RelativeStateOfCharge: sprintf (cstrName, "Battery System Relative State Of Charge"); break;
+ case kHIDUsage_BS_AbsoluteStateOfCharge: sprintf (cstrName, "Battery System Absolute State Of Charge"); break;
+ case kHIDUsage_BS_RemainingCapacity: sprintf (cstrName, "Battery System Remaining Capacity"); break;
+ case kHIDUsage_BS_FullChargeCapacity: sprintf (cstrName, "Battery System Full Charge Capacity"); break;
+ case kHIDUsage_BS_RunTimeToEmpty: sprintf (cstrName, "Battery System Run Time To Empty"); break;
+ case kHIDUsage_BS_AverageTimeToEmpty: sprintf (cstrName, "Battery System Average Time To Empty"); break;
+ case kHIDUsage_BS_AverageTimeToFull: sprintf (cstrName, "Battery System Average Time To Full"); break;
+ case kHIDUsage_BS_CycleCount: sprintf (cstrName, "Battery System Cycle Count"); break;
+ case kHIDUsage_BS_BattPackModelLevel: sprintf (cstrName, "Battery System Batt Pack Model Level"); break;
+ case kHIDUsage_BS_InternalChargeController: sprintf (cstrName, "Battery System Internal Charge Controller"); break;
+ case kHIDUsage_BS_PrimaryBatterySupport: sprintf (cstrName, "Battery System Primary Battery Support"); break;
+ case kHIDUsage_BS_DesignCapacity: sprintf (cstrName, "Battery System Design Capacity"); break;
+ case kHIDUsage_BS_SpecificationInfo: sprintf (cstrName, "Battery System Specification Info"); break;
+ case kHIDUsage_BS_ManufacturerDate: sprintf (cstrName, "Battery System Manufacturer Date"); break;
+ case kHIDUsage_BS_SerialNumber: sprintf (cstrName, "Battery System Serial Number"); break;
+ case kHIDUsage_BS_iManufacturerName: sprintf (cstrName, "Battery System Manufacturer Name Index"); break;
+ case kHIDUsage_BS_iDevicename: sprintf (cstrName, "Battery System Device Name Index"); break;
+ case kHIDUsage_BS_iDeviceChemistry: sprintf (cstrName, "Battery System Device Chemistry Index"); break;
+ case kHIDUsage_BS_ManufacturerData: sprintf (cstrName, "Battery System Manufacturer Data"); break;
+ case kHIDUsage_BS_Rechargable: sprintf (cstrName, "Battery System Rechargable"); break;
+ case kHIDUsage_BS_WarningCapacityLimit: sprintf (cstrName, "Battery System Warning Capacity Limit"); break;
+ case kHIDUsage_BS_CapacityGranularity1: sprintf (cstrName, "Battery System Capacity Granularity 1"); break;
+ case kHIDUsage_BS_CapacityGranularity2: sprintf (cstrName, "Battery System Capacity Granularity 2"); break;
+ case kHIDUsage_BS_iOEMInformation: sprintf (cstrName, "Battery System OEM Information Index"); break;
+ case kHIDUsage_BS_InhibitCharge: sprintf (cstrName, "Battery System Inhibit Charge"); break;
+ case kHIDUsage_BS_EnablePolling: sprintf (cstrName, "Battery System Enable Polling"); break;
+ case kHIDUsage_BS_ResetToZero: sprintf (cstrName, "Battery System Reset To Zero"); break;
+ case kHIDUsage_BS_ACPresent: sprintf (cstrName, "Battery System AC Present"); break;
+ case kHIDUsage_BS_BatteryPresent: sprintf (cstrName, "Battery System Battery Present"); break;
+ case kHIDUsage_BS_PowerFail: sprintf (cstrName, "Battery System Power Fail"); break;
+ case kHIDUsage_BS_AlarmInhibited: sprintf (cstrName, "Battery System Alarm Inhibited"); break;
+ case kHIDUsage_BS_ThermistorUnderRange: sprintf (cstrName, "Battery System Thermistor Under Range"); break;
+ case kHIDUsage_BS_ThermistorHot: sprintf (cstrName, "Battery System Thermistor Hot"); break;
+ case kHIDUsage_BS_ThermistorCold: sprintf (cstrName, "Battery System Thermistor Cold"); break;
+ case kHIDUsage_BS_ThermistorOverRange: sprintf (cstrName, "Battery System Thermistor Over Range"); break;
+ case kHIDUsage_BS_VoltageOutOfRange: sprintf (cstrName, "Battery System Voltage Out Of Range"); break;
+ case kHIDUsage_BS_CurrentOutOfRange: sprintf (cstrName, "Battery System Current Out Of Range"); break;
+ case kHIDUsage_BS_CurrentNotRegulated: sprintf (cstrName, "Battery System Current Not Regulated"); break;
+ case kHIDUsage_BS_VoltageNotRegulated: sprintf (cstrName, "Battery System Voltage Not Regulated"); break;
+ case kHIDUsage_BS_MasterMode: sprintf (cstrName, "Battery System Master Mode"); break;
+ case kHIDUsage_BS_ChargerSelectorSupport: sprintf (cstrName, "Battery System Charger Support Selector"); break;
+ case kHIDUsage_BS_ChargerSpec: sprintf (cstrName, "attery System Charger Specification"); break;
+ case kHIDUsage_BS_Level2: sprintf (cstrName, "Battery System Charger Level 2"); break;
+ case kHIDUsage_BS_Level3: sprintf (cstrName, "Battery System Charger Level 3"); break;
+ default: sprintf (cstrName, "Battery System Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_AlphanumericDisplay:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Alphanumeric Display Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_BarCodeScanner:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Bar Code Scanner Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_Scale:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Scale Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_CameraControl:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Camera Control Usage 0x%lx", element->usage); break;
+ }
+ break;
+ case kHIDPage_Arcade:
+ switch (element->usage)
+ {
+ default: sprintf (cstrName, "Arcade Usage 0x%lx", element->usage); break;
+ }
+ break;
+ default:
+ if (element->usagePage > kHIDPage_VendorDefinedStart)
+ sprintf (cstrName, "Vendor Defined Usage 0x%lx", element->usage);
+ else
+ sprintf (cstrName, "Page: 0x%lx, Usage: 0x%lx", element->usagePage, element->usage);
+ break;
+ }
+
+ return(cstrName);
+}
+
+
+
+
+#endif /* #ifdef __APPLE__ */
+
diff --git a/hidio_linux.c b/hidio_linux.c
new file mode 100644
index 0000000..a7e1c1c
--- /dev/null
+++ b/hidio_linux.c
@@ -0,0 +1,648 @@
+/* this code only works for Linux kernels */
+#ifdef __linux__
+
+
+#include <linux/input.h>
+#include <sys/ioctl.h>
+
+#include <sys/stat.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "hidio.h"
+
+#define DEBUG(x)
+//#define DEBUG(x) x
+
+#define LINUX_BLOCK_DEVICE "/dev/input/event"
+
+
+/*------------------------------------------------------------------------------
+ * from evtest.c from the ff-utils package
+ */
+
+/* from asm/types.h and linux/input.h __kernel__ sections */
+#define BITS_PER_LONG (sizeof(long) * 8)
+#define NBITS(x) (((x)/BITS_PER_LONG)+1)
+#define LONG(x) ((x)/BITS_PER_LONG)
+#define test_bit(bit, array) ((array[LONG(bit)] >> (bit%BITS_PER_LONG)) & 1)
+
+
+/*
+ * from an email from Vojtech:
+ *
+ * The application reading the device is supposed to queue all events up to
+ * the SYN_REPORT event, and then process them, so that a mouse pointer
+ * will move diagonally instead of following the sides of a rectangle,
+ * which would be very annoying.
+ */
+
+
+/* ------------------------------------------------------------------------------ */
+/* LINUX-SPECIFIC SUPPORT FUNCTIONS */
+/* ------------------------------------------------------------------------------ */
+
+t_symbol* hidio_convert_linux_buttons_to_numbers(__u16 linux_code)
+{
+ char hidio_code[MAXPDSTRING];
+ if(linux_code >= 0x100)
+ {
+ if(linux_code < BTN_MOUSE) /* numbered buttons */
+ snprintf(hidio_code, MAXPDSTRING,"btn_%d",linux_code - BTN_MISC);
+ else if(linux_code < BTN_JOYSTICK) /* mouse buttons */
+ snprintf(hidio_code, MAXPDSTRING,"btn_%d",linux_code - BTN_MOUSE);
+ else if(linux_code < BTN_GAMEPAD) /* joystick buttons */
+ snprintf(hidio_code, MAXPDSTRING,"btn_%d",linux_code - BTN_JOYSTICK);
+ else if(linux_code < BTN_DIGI) /* gamepad buttons */
+ snprintf(hidio_code, MAXPDSTRING,"btn_%d",linux_code - BTN_GAMEPAD);
+ else if(linux_code < BTN_WHEEL) /* tablet buttons */
+ snprintf(hidio_code, MAXPDSTRING,"btn_%d",linux_code - BTN_DIGI);
+ else if(linux_code < KEY_OK) /* wheel buttons */
+ snprintf(hidio_code, MAXPDSTRING,"btn_%d",linux_code - BTN_WHEEL);
+ else return 0;
+ }
+ return gensym(hidio_code ? hidio_code : "?");
+}
+
+/* Georg Holzmann: implementation of the keys */
+/* JMZ: use t_symbol instead of char[] (s.a.) AND
+ * appended "key_" in the array so we don't have to append it each time AND
+ * made the table static
+ */
+t_symbol* hidio_convert_linux_keys(__u16 linux_code)
+{
+ if(linux_code > 226)
+ return 0;
+
+ static char key_names[227][32] =
+ {
+ "key_reserved", "key_esc", "key_1", "key_2", "key_3", "key_4",
+ "key_5", "key_6", "key_7", "key_8", "key_9", "key_0", "key_minus",
+ "key_equal", "key_backspace", "key_tab", "key_q", "key_w",
+ "key_e", "key_r", "key_t", "key_y", "key_u", "key_i", "key_o",
+ "key_p","key_leftbrace", "key_rightbrace", "key_enter",
+ "key_leftctrl", "key_a","key_s", "key_d", "key_f", "key_g",
+ "key_h", "key_j", "key_k", "key_l", "key_semicolon",
+ "key_apostrophe", "key_grave", "key_leftshift", "key_backslash",
+ "key_z","key_x", "key_c", "key_v", "key_b", "key_n", "key_m",
+ "key_comma", "key_dot", "key_slash","key_rightshift",
+ "key_kpasterisk", "key_leftalt", "key_space", "key_capslock",
+ "key_f1", "key_f2", "key_f3", "key_f4", "key_f5", "key_f6",
+ "key_f7", "key_f8", "key_f9", "key_f10","key_numlock",
+ "key_scrolllock", "key_kp7", "key_kp8", "key_kp9", "key_kpminus",
+ "key_kp4", "key_kp5", "key_kp6", "key_kpplus", "key_kp1", "key_kp2",
+ "key_kp3", "key_kp3", "key_kpdot","key_103rd", "key_f13",
+ "key_102nd", "key_f11", "key_f12", "key_f14", "key_f15", "key_f16",
+ "key_f17", "key_f18", "key_f19", "key_f20", "key_kpenter",
+ "key_rightctrl", "key_kpslash","key_sysrq", "key_rightalt",
+ "key_linefeed", "key_home", "key_up", "key_pageup", "key_left",
+ "key_right", "key_end", "key_down", "key_pagedown", "key_insert",
+ "key_delete", "key_macro","key_mute", "key_volumedown",
+ "key_volumeup", "key_power", "key_kpequal", "key_kpplusminus",
+ "key_pause", "key_f21", "key_f22", "key_f23", "key_f24",
+ "key_kpcomma", "key_leftmeta","key_rightmeta", "key_compose",
+ "key_stop", "key_again", "key_props", "key_undo", "key_front",
+ "key_copy", "key_open","key_paste", "key_find","key_cut","key_help",
+ "key_menu", "key_calc", "key_setup", "key_sleep", "key_wakeup",
+ "key_file", "key_sendfile", "key_deletefile","key_xfer","key_prog1",
+ "key_prog2", "key_www","key_msdos", "key_coffee", "key_direction",
+ "key_cyclewindows", "key_mail", "key_bookmarks","key_computer",
+ "key_back", "key_forward", "key_colsecd", "key_ejectcd",
+ "key_ejectclosecd","key_nextsong","key_playpause","key_previoussong",
+ "key_stopcd", "key_record","key_rewind", "key_phone", "key_iso",
+ "key_config", "key_homepage", "key_refresh", "key_exit","key_move",
+ "key_edit", "key_scrollup", "key_scrolldown", "key_kpleftparen",
+ "key_kprightparen","key_intl1", "key_intl2", "key_intl3","key_intl4",
+ "key_intl5", "key_intl6", "key_intl7","key_intl8", "key_intl9",
+ "key_lang1", "key_lang2", "key_lang3", "key_lang4", "key_lang5",
+ "key_lang6", "key_lang7", "key_lang8", "key_lang9", "key_playcd",
+ "key_pausecd", "key_prog3","key_prog4", "key_suspend", "key_close",
+ "key_play", "key_fastforward", "key_bassboost","key_print", "key_hp",
+ "key_camera", "key_sound", "key_question", "key_email", "key_chat",
+ "key_search", "key_connect", "key_finance", "key_sport", "key_shop",
+ "key_alterase","key_cancel", "key_brightnessdown", "key_brightnessup",
+ "key_media"
+ };
+ return gensym(key_names[linux_code]); // TODO: this should just return the char *
+}
+
+
+
+
+void hidio_print_element_list(t_hidio *x)
+{
+ debug_print(LOG_DEBUG,"hidio_print_element_list");
+ unsigned long element_bitmask[EV_MAX][NBITS(KEY_MAX)];
+// char event_type_string[256];
+// char event_code_string[256];
+ char *event_type_name = "";
+ t_int i, j;
+ /* counts for various event types */
+ t_int syn_count,key_count,rel_count,abs_count,msc_count,led_count,
+ snd_count,rep_count,ff_count,pwr_count,ff_status_count;
+
+ /* get bitmask representing supported element (axes, keys, etc.) */
+ memset(element_bitmask, 0, sizeof(element_bitmask));
+ ioctl(x->x_fd, EVIOCGBIT(0, EV_MAX), element_bitmask[0]);
+ post("\nSupported events:");
+
+/* init all count vars */
+ syn_count = key_count = rel_count = abs_count = msc_count = led_count = 0;
+ snd_count = rep_count = ff_count = pwr_count = ff_status_count = 0;
+
+ /* cycle through all possible event types
+ * i = i j = j
+ */
+ for(i = 1; i < EV_MAX; i++)
+ {
+ if(test_bit(i, element_bitmask[0]))
+ {
+ /* make pretty names for event types */
+ switch(i)
+ {
+// case EV_SYN: event_type_name = "Synchronization"; break;
+ case EV_KEY: event_type_name = "Keys/Buttons"; break;
+ case EV_REL: event_type_name = "Relative Axis"; break;
+ case EV_ABS: event_type_name = "Absolute Axis"; break;
+ case EV_MSC: event_type_name = "Miscellaneous"; break;
+ case EV_LED: event_type_name = "LEDs"; break;
+ case EV_SND: event_type_name = "System Sounds"; break;
+ case EV_REP: event_type_name = "Autorepeat Values"; break;
+ case EV_FF: event_type_name = "Force Feedback"; break;
+ case EV_PWR: event_type_name = "Power"; break;
+ case EV_FF_STATUS: event_type_name = "Force Feedback Status"; break;
+ default: event_type_name = "UNSUPPORTED";
+ }
+
+ /* get bitmask representing supported button types */
+ ioctl(x->x_fd, EVIOCGBIT(i, KEY_MAX), element_bitmask[i]);
+
+ post("");
+ post(" TYPE\tCODE\tEVENT NAME");
+ post("-----------------------------------------------------------");
+
+ /* cycle through all possible event codes (axes, keys, etc.)
+ * testing to see which are supported.
+ * i = i j = j
+ */
+ for(j = 0; j < KEY_MAX; j++)
+ {
+ if(test_bit(j, element_bitmask[i]))
+ {
+ if((i == EV_KEY) && (j >= BTN_MISC) && (j < KEY_OK) )
+ {
+ t_symbol * hidio_codesym = hidio_convert_linux_buttons_to_numbers(j);
+ if(hidio_codesym)
+ {
+ post(" %s\t%s\t%s (%s)",
+ ev[i] ? ev[i] : "?",
+ hidio_codesym->s_name,
+ event_type_name,
+ event_names[i] ? (event_names[i][j] ? event_names[i][j] : "?") : "?");
+ }
+ }
+ else if(i != EV_SYN)
+ {
+ post(" %s\t%s\t%s",
+ ev[i] ? ev[i] : "?",
+ event_names[i][j] ? event_names[i][j] : "?",
+ event_type_name);
+
+/* post(" Event code %d (%s)", j, names[i] ? (names[i][j] ? names[i][j] : "?") : "?"); */
+ }
+
+ switch(i) {
+/*
+ * the API changed at some point... EV_SYN seems to be the new name
+ * from "Reset" events to "Syncronization" events
+ */
+/* #ifdef EV_RST */
+/* case EV_RST: syn_count++; break; */
+/* #else */
+/* case EV_SYN: syn_count++; break; */
+/* #endif */
+ case EV_KEY: key_count++; break;
+ case EV_REL: rel_count++; break;
+ case EV_ABS: abs_count++; break;
+ case EV_MSC: msc_count++; break;
+ case EV_LED: led_count++; break;
+ case EV_SND: snd_count++; break;
+ case EV_REP: rep_count++; break;
+ case EV_FF: ff_count++; break;
+ case EV_PWR: pwr_count++; break;
+ case EV_FF_STATUS: ff_status_count++; break;
+ }
+ }
+ }
+ }
+ }
+
+ post("\nDetected:");
+// if(syn_count > 0) post (" %d Synchronization types",syn_count);
+ if(key_count > 0) post (" %d Key/Button types",key_count);
+ if(rel_count > 0) post (" %d Relative Axis types",rel_count);
+ if(abs_count > 0) post (" %d Absolute Axis types",abs_count);
+ if(msc_count > 0) post (" %d Misc types",msc_count);
+ if(led_count > 0) post (" %d LED types",led_count);
+ if(snd_count > 0) post (" %d System Sound types",snd_count);
+ if(rep_count > 0) post (" %d Key Repeat types",rep_count);
+ if(ff_count > 0) post (" %d Force Feedback types",ff_count);
+ if(pwr_count > 0) post (" %d Power types",pwr_count);
+ if(ff_status_count > 0) post (" %d Force Feedback types",ff_status_count);
+}
+
+
+void hidio_print_device_list(void)
+{
+ debug_print(LOG_DEBUG,"hidio_print_device_list");
+ int i,fd;
+ char device_output_string[MAXPDSTRING] = "Unknown";
+ char dev_handle_name[MAXPDSTRING] = "/dev/input/event0";
+
+ post("");
+ for(i=0;i<128;++i)
+ {
+ snprintf(dev_handle_name, MAXPDSTRING, "/dev/input/event%d", i);
+ if(dev_handle_name)
+ {
+ /* open the device read-only, non-exclusive */
+ fd = open (dev_handle_name, O_RDONLY | O_NONBLOCK);
+ /* test if device open */
+ if(fd < 0 )
+ {
+ fd = -1;
+ }
+ else
+ {
+ /* get name of device */
+ ioctl(fd, EVIOCGNAME(sizeof(device_output_string)), device_output_string);
+ post("Device %d: '%s' on '%s'", i, device_output_string, dev_handle_name);
+
+ close (fd);
+ }
+ }
+ }
+ post("");
+}
+
+
+
+static void hidio_build_element_list(t_hidio *x)
+{
+ debug_print(LOG_DEBUG,"hidio_build_element_list");
+ unsigned long element_bitmask[EV_MAX][NBITS(KEY_MAX)];
+ uint8_t abs_bitmask[ABS_MAX/8 + 1];
+ struct input_absinfo abs_features;
+ t_hid_element *new_element = NULL;
+ t_int i, j;
+
+ element_count[x->x_device_number] = 0;
+ if( x->x_fd )
+ {
+ /* get bitmask representing supported elements (axes, keys, etc.) */
+ memset(element_bitmask, 0, sizeof(element_bitmask));
+ if( ioctl(x->x_fd, EVIOCGBIT(0, EV_MAX), element_bitmask[0]) < 0 )
+ perror("[hidio] error: evdev ioctl: element_bitmask");
+ memset(abs_bitmask, 0, sizeof(abs_bitmask));
+ if( ioctl(x->x_fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) < 0 )
+ perror("[hidio] error: evdev ioctl: abs_bitmask");
+ for( i = 1; i < EV_MAX; i++ )
+ {
+ if(test_bit(i, element_bitmask[0]))
+ {
+ /* get bitmask representing supported button types */
+ ioctl(x->x_fd, EVIOCGBIT(i, KEY_MAX), element_bitmask[i]);
+ /* cycle through all possible event codes (axes, keys, etc.)
+ * testing to see which are supported.
+ * i = i j = j
+ */
+ for(j = 0; j < KEY_MAX; j++)
+ {
+ new_element = getbytes(sizeof(t_hid_element));
+ if( (i == EV_ABS) && (test_bit(j, abs_bitmask)) )
+ {
+ /* this means that the bit is set in the axes list */
+ if(ioctl(x->x_fd, EVIOCGABS(j), &abs_features))
+ perror("evdev EVIOCGABS ioctl");
+ new_element->min = abs_features.minimum;
+ new_element->max = abs_features.maximum;
+ }
+ else
+ {
+ new_element->min = 0;
+ new_element->max = 0;
+ }
+ if(test_bit(j, element_bitmask[i]))
+ {
+ new_element->linux_type = i; /* the int from linux/input.h */
+ new_element->type = gensym(ev[i] ? ev[i] : "?"); /* the symbol */
+ new_element->linux_code = j;
+ if((i == EV_KEY) && (j >= BTN_MISC) && (j < KEY_OK) )
+ {
+ new_element->name = hidio_convert_linux_buttons_to_numbers(j);
+ }
+ else
+ {
+ new_element->name = gensym(event_names[i][j] ? event_names[i][j] : "?");
+ }
+ if( i == EV_REL )
+ new_element->relative = 1;
+ else
+ new_element->relative = 0;
+ // fill in the t_hid_element struct here
+ post("x->x_device_number: %d element_count[]: %d",
+ x->x_device_number, element_count[x->x_device_number]);
+ post("linux_type/linux_code: %d/%d type/name: %s/%s max: %d min: %d ",
+ new_element->linux_type, new_element->linux_code,
+ new_element->type->s_name, new_element->name->s_name,
+ new_element->max, new_element->min);
+ post("\tpolled: %d relative: %d",
+ new_element->polled, new_element->relative);
+ element[x->x_device_number][element_count[x->x_device_number]] = new_element;
+ ++element_count[x->x_device_number];
+ }
+ }
+ }
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------------ */
+/* Pd [hidio] FUNCTIONS */
+/* ------------------------------------------------------------------------------ */
+
+void hidio_get_events(t_hidio *x)
+{
+ debug_print(9,"hidio_get_events");
+
+/* for debugging, counts how many events are processed each time hidio_read() is called */
+ DEBUG(t_int event_counter = 0;);
+ unsigned short i;
+ t_hid_element *output_element = NULL;
+
+/* this will go into the generic read function declared in hidio.h and
+ * implemented in hidio_linux.c
+ */
+ struct input_event hidio_input_event;
+
+ if(x->x_fd < 0) return;
+
+ while( read (x->x_fd, &(hidio_input_event), sizeof(struct input_event)) > -1 )
+ {
+ if( hidio_input_event.type != EV_SYN )
+ {
+ for( i=0; i < element_count[x->x_device_number]; ++i )
+ {
+ output_element = element[x->x_device_number][i];
+ if( (hidio_input_event.type == output_element->linux_type) && \
+ (hidio_input_event.code == output_element->linux_code) )
+ {
+ output_element->value = hidio_input_event.value;
+ debug_print(9,"i: %d linux_type: %d linux_code: %d", i,
+ output_element->linux_type, output_element->linux_code);
+ debug_print(9,"value to output: %d",output_element->value);
+ break;
+ }
+ }
+ if( output_element != NULL )
+ hidio_output_event(x, output_element);
+ }
+ DEBUG(++event_counter;);
+ }
+ DEBUG(
+ if(event_counter > 0)
+ debug_print(8,"output %d events",event_counter);
+ );
+
+ return;
+}
+
+
+void hidio_print(t_hidio* x)
+{
+ hidio_print_device_list();
+ hidio_print_element_list(x);
+}
+
+
+t_int hidio_open_device(t_hidio *x, short device_number)
+{
+ debug_print(LOG_DEBUG,"hidio_open_device");
+
+ char device_name[MAXPDSTRING] = "Unknown";
+ char block_device[MAXPDSTRING] = "/dev/input/event0";
+ struct input_event hidio_input_event;
+
+ x->x_fd = -1;
+
+ x->x_device_number = device_number;
+ snprintf(block_device,MAXPDSTRING,"/dev/input/event%d",x->x_device_number);
+
+ if(block_device)
+ {
+ /* open the device read-only, non-exclusive */
+ x->x_fd = open(block_device, O_RDONLY | O_NONBLOCK);
+ /* test if device open */
+ if(x->x_fd < 0 )
+ {
+ error("[hidio] open %s failed",block_device);
+ x->x_fd = -1;
+ return 1;
+ }
+ }
+
+ /* read input_events from the HID_DEVICE stream
+ * It seems that is just there to flush the input event queue
+ */
+ while (read (x->x_fd, &(hidio_input_event), sizeof(struct input_event)) > -1);
+
+ /* get name of device */
+ ioctl(x->x_fd, EVIOCGNAME(sizeof(device_name)), device_name);
+ post ("[hidio] opened device %d (%s): %s",
+ x->x_device_number,block_device,device_name);
+
+ post("pre hidio_build_element_list");
+ hidio_build_element_list(x);
+
+ return (0);
+}
+
+/*
+ * Under GNU/Linux, the device is a filehandle
+ */
+t_int hidio_close_device(t_hidio *x)
+{
+ debug_print(LOG_DEBUG,"hidio_close_device");
+ if(x->x_fd <0)
+ return 0;
+ else
+ return (close(x->x_fd));
+}
+
+
+void hidio_build_device_list(void)
+{
+/*
+ * since in GNU/Linux the device list is the input event devices
+ * (/dev/input/event?), nothing needs to be done as of yet to refresh
+ * the device list. Once the device name can be other things in addition
+ * the current t_float, then this will probably need to be changed.
+ */
+ int fd;
+ unsigned int i;
+ unsigned int last_active_device = 0;
+ char device_name[MAXPDSTRING] = "Unknown";
+ char block_device[MAXPDSTRING] = "/dev/input/event0";
+ struct input_event x_input_event;
+
+ debug_print(LOG_DEBUG,"hidio_build_device_list");
+
+ debug_print(LOG_WARNING,"[hidio] Building device list...");
+
+ for(i=0; i<MAX_DEVICES; ++i)
+ {
+ snprintf(block_device, MAXPDSTRING, "%s%d", LINUX_BLOCK_DEVICE, i);
+ /* open the device read-only, non-exclusive */
+ fd = open (block_device, O_RDONLY | O_NONBLOCK);
+ /* test if device open */
+ if(fd < 0 ) {
+ /* post("Nothing on %s.", &block_device); */
+ fd = -1;
+/* return 0; */
+ } else {
+ /* read input_events from the LINUX_BLOCK_DEVICE stream
+ * It seems that is just there to flush the event input buffer?
+ */
+ while (read (fd, &(x_input_event), sizeof(struct input_event)) > -1);
+
+ /* get name of device */
+ ioctl(fd, EVIOCGNAME(sizeof(device_name)), device_name);
+ post("Found '%s' on '%s'",device_name, &block_device);
+
+ close (fd);
+ }
+ last_active_device = i;
+
+ }
+ device_count = last_active_device ; // set the global variable
+ debug_print(LOG_WARNING,"[hidio] completed device list.");
+}
+
+
+
+void hidio_platform_specific_free(t_hidio *x)
+{
+ /* nothing to be done here on GNU/Linux */
+}
+
+
+
+
+/* device info on the status outlet */
+void hidio_platform_specific_info(t_hidio* x)
+{
+ struct input_id my_id;
+ char device_name[MAXPDSTRING] = "Unknown";
+ char vendor_id_string[7];
+ char product_id_string[7];
+ t_atom *output_atom = getbytes(sizeof(t_atom));
+
+ ioctl(x->x_fd, EVIOCGID);
+ snprintf(vendor_id_string,7,"0x%04x", my_id.vendor);
+ SETSYMBOL(output_atom, gensym(vendor_id_string));
+ outlet_anything( x->x_status_outlet, gensym("vendorID"),
+ 1, output_atom);
+ snprintf(product_id_string,7,"0x%04x", my_id.product);
+ SETSYMBOL(output_atom, gensym(product_id_string));
+ outlet_anything( x->x_status_outlet, gensym("productID"),
+ 1, output_atom);
+ ioctl(x->x_fd, EVIOCGNAME(sizeof(device_name)), device_name);
+ SETSYMBOL(output_atom, gensym(device_name));
+ outlet_anything( x->x_status_outlet, gensym("name"),
+ 1, output_atom);
+ freebytes(output_atom,sizeof(t_atom));
+}
+
+
+short get_device_number_by_id(unsigned short vendor_id, unsigned short product_id)
+{
+
+ return -1;
+}
+
+short get_device_number_from_usage(short device_number,
+ unsigned short usage_page,
+ unsigned short usage)
+{
+
+ return -1;
+}
+
+
+
+/* ------------------------------------------------------------------------------ */
+/* FORCE FEEDBACK FUNCTIONS */
+/* ------------------------------------------------------------------------------ */
+
+/* cross-platform force feedback functions */
+t_int hidio_ff_autocenter( t_hidio *x, t_float value )
+{
+ return ( 0 );
+}
+
+
+t_int hidio_ff_gain( t_hidio *x, t_float value )
+{
+ return ( 0 );
+}
+
+
+t_int hidio_ff_motors( t_hidio *x, t_float value )
+{
+ return ( 0 );
+}
+
+
+t_int hidio_ff_continue( t_hidio *x )
+{
+ return ( 0 );
+}
+
+
+t_int hidio_ff_pause( t_hidio *x )
+{
+ return ( 0 );
+}
+
+
+t_int hidio_ff_reset( t_hidio *x )
+{
+ return ( 0 );
+}
+
+
+t_int hidio_ff_stopall( t_hidio *x )
+{
+ return ( 0 );
+}
+
+
+
+// these are just for testing...
+t_int hidio_ff_fftest ( t_hidio *x, t_float value)
+{
+ return ( 0 );
+}
+
+
+void hidio_ff_print( t_hidio *x )
+{
+}
+
+
+#endif /* #ifdef __linux__ */
+
diff --git a/hidio_windows.c b/hidio_windows.c
new file mode 100644
index 0000000..2bc98ae
--- /dev/null
+++ b/hidio_windows.c
@@ -0,0 +1,337 @@
+#ifdef _WIN32
+/*
+ * Microsoft Windows DDK HID support for Pd [hidio] object
+ *
+ * Copyright (c) 2004 Hans-Christoph All rights reserved.
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ */
+
+#include <windows.h>
+#include <winbase.h>
+#include <stdio.h>
+#include <setupapi.h>
+#ifdef _MSC_VER
+#include <hidsdi.h>
+#else
+#include <ddk/hidsdi.h>
+#endif /* _MSC_VER */
+#include "hidio.h"
+
+//#define DEBUG(x)
+#define DEBUG(x) x
+
+/*==============================================================================
+ * GLOBAL VARS
+ *======================================================================== */
+
+extern t_int hidio_instance_count;
+
+/*==============================================================================
+ * FUNCTION PROTOTYPES
+ *==============================================================================
+ */
+
+
+/*==============================================================================
+ * Event TYPE/CODE CONVERSION FUNCTIONS
+ *==============================================================================
+ */
+
+
+
+
+/* ============================================================================== */
+/* WINDOWS DDK HID SPECIFIC SUPPORT FUNCTIONS */
+/* ============================================================================== */
+
+void hidio_get_device_by_number(t_int device_number)
+{
+
+}
+
+
+void hidio_build_element_list(t_hidio *x)
+{
+
+}
+
+t_int hidio_print_element_list(t_hidio *x)
+{
+ debug_print(LOG_DEBUG,"hidio_print_element_list");
+
+
+ return (0);
+}
+
+t_int hidio_print_device_list(t_hidio *x)
+{
+ struct _GUID GUID;
+ SP_INTERFACE_DEVICE_DATA DeviceInterfaceData;
+ struct {DWORD cbSize; char DevicePath[256];} FunctionClassDeviceData;
+ HIDD_ATTRIBUTES HIDAttributes;
+ SECURITY_ATTRIBUTES SecurityAttributes;
+ int i;
+ HANDLE PnPHandle, HIDHandle;
+ ULONG BytesReturned;
+ int Success, ManufacturerName, ProductName;
+ char ManufacturerBuffer[256];
+ char ProductBuffer[256];
+ const char NotSupplied[] = "NULL";
+ DWORD lastError = 0;
+
+#if 0
+// Initialize the GUID array and setup the security attributes for Win2000
+ HidD_GetHidGuid(&GUID);
+ SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+ SecurityAttributes.lpSecurityDescriptor = NULL;
+ SecurityAttributes.bInheritHandle = FALSE;
+
+// Get a handle for the Plug and Play node and request currently active devices
+ PnPHandle = SetupDiGetClassDevs(&GUID, NULL, NULL,
+ DIGCF_PRESENT|DIGCF_INTERFACEDEVICE);
+
+ if ((int)PnPHandle == -1)
+ {
+ error("[hidio] ERROR: Could not attach to PnP node\n");
+ return (t_int) GetLastError();
+ }
+
+// Lets look for a maximum of 32 Devices
+ for (i = 0; i < 32; i++) {
+// Initialize our data
+ DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData);
+// Is there a device at this table entry
+ Success = SetupDiEnumDeviceInterfaces(PnPHandle, NULL, &GUID, i,
+ &DeviceInterfaceData);
+ if (Success) {
+// There is a device here, get it's name
+ FunctionClassDeviceData.cbSize = 5;
+ Success = SetupDiGetDeviceInterfaceDetail(PnPHandle,
+ &DeviceInterfaceData,
+ (PSP_INTERFACE_DEVICE_DETAIL_DATA)&FunctionClassDeviceData,
+ 256, &BytesReturned, NULL);
+ if (!Success)
+ {
+ error("[hidio] ERROR: Could not find the system name for device %d\n",i);
+ return GetLastError();
+ }
+// Can now open this device
+ HIDHandle = CreateFile(FunctionClassDeviceData.DevicePath,
+ 0,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ &SecurityAttributes, OPEN_EXISTING, 0, NULL);
+ lastError = GetLastError();
+ if (HIDHandle == INVALID_HANDLE_VALUE)
+ {
+ error("[hidio] ERROR: Could not open HID #%d, Errorcode = %d\n", i, (int)lastError);
+ return lastError;
+ }
+
+// Get the information about this HID
+ Success = HidD_GetAttributes(HIDHandle, &HIDAttributes);
+ if (!Success)
+ {
+ error("[hidio] ERROR: Could not get HID attributes\n");
+ return GetLastError();
+ }
+ ManufacturerName = HidD_GetManufacturerString(HIDHandle, ManufacturerBuffer, 256);
+ ProductName = HidD_GetProductString(HIDHandle, ProductBuffer, 256);
+// And display it!
+ post("[hidio]: Device %d: %s %s\n",i,
+ ManufacturerName ? ManufacturerBuffer : NotSupplied,
+ ProductName ? ProductBuffer : NotSupplied);
+ post("\tVenderID = %4.4x, Name = ", HIDAttributes.VendorID);
+ post("%s\n", ManufacturerName ? ManufacturerBuffer : NotSupplied);
+ post("\tProductID = %4.4x, Name = ", HIDAttributes.ProductID);
+ post("%s\n", ProductName ? ProductBuffer : NotSupplied);
+
+ CloseHandle(HIDHandle);
+ } // if (SetupDiEnumDeviceInterfaces . .
+ } // for (i = 0; i < 32; i++)
+ SetupDiDestroyDeviceInfoList(PnPHandle);
+#endif
+ return 0;
+}
+
+void hidio_output_device_name(t_hidio *x, char *manufacturer, char *product)
+{
+ char *device_name;
+ t_symbol *device_name_symbol;
+
+ device_name = malloc( strlen(manufacturer) + 1 + strlen(product) + 1 );
+// device_name = malloc( 7 + strlen(manufacturer) + 1 + strlen(product) + 1 );
+// strcpy( device_name, "append " );
+ strcat( device_name, manufacturer );
+ strcat ( device_name, " ");
+ strcat( device_name, product );
+// outlet_anything( x->x_status_outlet, gensym( device_name ),0,NULL );
+ outlet_symbol( x->x_status_outlet, gensym( device_name ) );
+}
+
+/* ------------------------------------------------------------------------------ */
+/* FORCE FEEDBACK FUNCTIONS */
+/* ------------------------------------------------------------------------------ */
+
+/* cross-platform force feedback functions */
+t_int hidio_ff_autocenter( t_hidio *x, t_float value )
+{
+ return ( 0 );
+}
+
+
+t_int hidio_ff_gain( t_hidio *x, t_float value )
+{
+ return ( 0 );
+}
+
+
+t_int hidio_ff_motors( t_hidio *x, t_float value )
+{
+ return ( 0 );
+}
+
+
+t_int hidio_ff_continue( t_hidio *x )
+{
+ return ( 0 );
+}
+
+
+t_int hidio_ff_pause( t_hidio *x )
+{
+ return ( 0 );
+}
+
+
+t_int hidio_ff_reset( t_hidio *x )
+{
+ return ( 0 );
+}
+
+
+t_int hidio_ff_stopall( t_hidio *x )
+{
+ return ( 0 );
+}
+
+
+
+// these are just for testing...
+t_int hidio_ff_fftest ( t_hidio *x, t_float value)
+{
+ return ( 0 );
+}
+
+
+void hidio_ff_print( t_hidio *x )
+{
+}
+
+/* ============================================================================== */
+/* Pd [hidio] FUNCTIONS */
+/* ============================================================================== */
+
+t_int hidio_get_events(t_hidio *x)
+{
+ //debug_print(LOG_DEBUG,"hidio_get_events");
+
+ return (0);
+}
+
+
+t_int hidio_open_device(t_hidio *x, t_int device_number)
+{
+ debug_print(LOG_DEBUG,"hidio_open_device");
+ t_int result = 0;
+
+
+ return(result);
+}
+
+
+t_int hidio_close_device(t_hidio *x)
+{
+ debug_print(LOG_DEBUG,"hidio_close_device");
+
+ t_int result = 0;
+
+ return(result);
+}
+
+
+t_int hidio_build_device_list(t_hidio *x)
+{
+ debug_print(LOG_DEBUG,"hidio_build_device_list");
+
+/*
+ * The Windows DDK "hid.dll" has to be loaded manually because Windows gets
+ * confused by this object, which is also named "hid.dll". This is the first
+ * platform-specific function called in hid.c, so that's why this is happening
+ * here.
+ */
+ TCHAR hidDllPath[MAX_PATH];
+ UINT hidDllPathLength;
+ HMODULE hModule = NULL;
+
+ hidDllPathLength = GetSystemDirectory(hidDllPath, MAX_PATH);
+ if( !hidDllPathLength )
+ {
+ error("[hidio] ERROR: cannot get SystemRoot");
+ return 0;
+ }
+ strcat(hidDllPath,"\\hid.dll");
+ post("hidDllPath: %s",hidDllPath);
+ hModule = LoadLibrary(hidDllPath);
+ if ( !hModule )
+ {
+ error("[hidio] ERROR: couldn't load %s: error %d",hidDllPath,GetLastError());
+ return 0;
+ }
+
+ return 1;
+}
+
+
+void hidio_print(t_hidio *x)
+{
+ hidio_print_device_list(x);
+
+ if(x->x_device_open)
+ {
+ hidio_print_element_list(x);
+ hidio_ff_print( x );
+ }
+}
+
+
+void hidio_platform_specific_free(t_hidio *x)
+{
+ debug_print(LOG_DEBUG,"hidio_platform_specific_free");
+/* only call this if the last instance is being freed */
+ if (hidio_instance_count < 1)
+ {
+ DEBUG(post("RELEASE ALL hidio_instance_count: %d", hidio_instance_count););
+ }
+}
+
+
+
+
+
+
+#endif /* _WIN32 */
diff --git a/input_arrays.c b/input_arrays.c
new file mode 100644
index 0000000..4bc5c43
--- /dev/null
+++ b/input_arrays.c
@@ -0,0 +1,463 @@
+#include "hidio.h"
+
+int ev_total = 32; /* # of elements in array */
+char *ev[32] = {
+ "syn","key","rel","abs","msc","ev_5",
+ "ev_6","ev_7","ev_8","ev_9","ev_10","ev_11",
+ "ev_12","ev_13","ev_14","ev_15","ev_16","led",
+ "snd","ev_19","rep","ff","pwr","ff_status",
+ "ev_24","ev_25","ev_26","ev_27","ev_28","ev_29",
+ "ev_30","ev_31"
+ };
+
+
+int ev_syn_total = 512; /* # of elements in array */
+char *ev_syn[512] = {
+ "syn_report","syn_config","syn_2","syn_3","syn_4","syn_5",
+ "syn_6","syn_7","syn_8","syn_9","syn_10","syn_11",
+ "syn_12","syn_13","syn_14","syn_15","syn_16","syn_17",
+ "syn_18","syn_19","syn_20","syn_21","syn_22","syn_23",
+ "syn_24","syn_25","syn_26","syn_27","syn_28","syn_29",
+ "syn_30","syn_31","syn_32","syn_33","syn_34","syn_35",
+ "syn_36","syn_37","syn_38","syn_39","syn_40","syn_41",
+ "syn_42","syn_43","syn_44","syn_45","syn_46","syn_47",
+ "syn_48","syn_49","syn_50","syn_51","syn_52","syn_53",
+ "syn_54","syn_55","syn_56","syn_57","syn_58","syn_59",
+ "syn_60","syn_61","syn_62","syn_63","syn_64","syn_65",
+ "syn_66","syn_67","syn_68","syn_69","syn_70","syn_71",
+ "syn_72","syn_73","syn_74","syn_75","syn_76","syn_77",
+ "syn_78","syn_79","syn_80","syn_81","syn_82","syn_83",
+ "syn_84","syn_85","syn_86","syn_87","syn_88","syn_89",
+ "syn_90","syn_91","syn_92","syn_93","syn_94","syn_95",
+ "syn_96","syn_97","syn_98","syn_99","syn_100","syn_101",
+ "syn_102","syn_103","syn_104","syn_105","syn_106","syn_107",
+ "syn_108","syn_109","syn_110","syn_111","syn_112","syn_113",
+ "syn_114","syn_115","syn_116","syn_117","syn_118","syn_119",
+ "syn_120","syn_121","syn_122","syn_123","syn_124","syn_125",
+ "syn_126","syn_127","syn_128","syn_129","syn_130","syn_131",
+ "syn_132","syn_133","syn_134","syn_135","syn_136","syn_137",
+ "syn_138","syn_139","syn_140","syn_141","syn_142","syn_143",
+ "syn_144","syn_145","syn_146","syn_147","syn_148","syn_149",
+ "syn_150","syn_151","syn_152","syn_153","syn_154","syn_155",
+ "syn_156","syn_157","syn_158","syn_159","syn_160","syn_161",
+ "syn_162","syn_163","syn_164","syn_165","syn_166","syn_167",
+ "syn_168","syn_169","syn_170","syn_171","syn_172","syn_173",
+ "syn_174","syn_175","syn_176","syn_177","syn_178","syn_179",
+ "syn_180","syn_181","syn_182","syn_183","syn_184","syn_185",
+ "syn_186","syn_187","syn_188","syn_189","syn_190","syn_191",
+ "syn_192","syn_193","syn_194","syn_195","syn_196","syn_197",
+ "syn_198","syn_199","syn_200","syn_201","syn_202","syn_203",
+ "syn_204","syn_205","syn_206","syn_207","syn_208","syn_209",
+ "syn_210","syn_211","syn_212","syn_213","syn_214","syn_215",
+ "syn_216","syn_217","syn_218","syn_219","syn_220","syn_221",
+ "syn_222","syn_223","syn_224","syn_225","syn_226","syn_227",
+ "syn_228","syn_229","syn_230","syn_231","syn_232","syn_233",
+ "syn_234","syn_235","syn_236","syn_237","syn_238","syn_239",
+ "syn_240","syn_241","syn_242","syn_243","syn_244","syn_245",
+ "syn_246","syn_247","syn_248","syn_249","syn_250","syn_251",
+ "syn_252","syn_253","syn_254","syn_255","syn_256","syn_257",
+ "syn_258","syn_259","syn_260","syn_261","syn_262","syn_263",
+ "syn_264","syn_265","syn_266","syn_267","syn_268","syn_269",
+ "syn_270","syn_271","syn_272","syn_273","syn_274","syn_275",
+ "syn_276","syn_277","syn_278","syn_279","syn_280","syn_281",
+ "syn_282","syn_283","syn_284","syn_285","syn_286","syn_287",
+ "syn_288","syn_289","syn_290","syn_291","syn_292","syn_293",
+ "syn_294","syn_295","syn_296","syn_297","syn_298","syn_299",
+ "syn_300","syn_301","syn_302","syn_303","syn_304","syn_305",
+ "syn_306","syn_307","syn_308","syn_309","syn_310","syn_311",
+ "syn_312","syn_313","syn_314","syn_315","syn_316","syn_317",
+ "syn_318","syn_319","syn_320","syn_321","syn_322","syn_323",
+ "syn_324","syn_325","syn_326","syn_327","syn_328","syn_329",
+ "syn_330","syn_331","syn_332","syn_333","syn_334","syn_335",
+ "syn_336","syn_337","syn_338","syn_339","syn_340","syn_341",
+ "syn_342","syn_343","syn_344","syn_345","syn_346","syn_347",
+ "syn_348","syn_349","syn_350","syn_351","syn_352","syn_353",
+ "syn_354","syn_355","syn_356","syn_357","syn_358","syn_359",
+ "syn_360","syn_361","syn_362","syn_363","syn_364","syn_365",
+ "syn_366","syn_367","syn_368","syn_369","syn_370","syn_371",
+ "syn_372","syn_373","syn_374","syn_375","syn_376","syn_377",
+ "syn_378","syn_379","syn_380","syn_381","syn_382","syn_383",
+ "syn_384","syn_385","syn_386","syn_387","syn_388","syn_389",
+ "syn_390","syn_391","syn_392","syn_393","syn_394","syn_395",
+ "syn_396","syn_397","syn_398","syn_399","syn_400","syn_401",
+ "syn_402","syn_403","syn_404","syn_405","syn_406","syn_407",
+ "syn_408","syn_409","syn_410","syn_411","syn_412","syn_413",
+ "syn_414","syn_415","syn_416","syn_417","syn_418","syn_419",
+ "syn_420","syn_421","syn_422","syn_423","syn_424","syn_425",
+ "syn_426","syn_427","syn_428","syn_429","syn_430","syn_431",
+ "syn_432","syn_433","syn_434","syn_435","syn_436","syn_437",
+ "syn_438","syn_439","syn_440","syn_441","syn_442","syn_443",
+ "syn_444","syn_445","syn_446","syn_447","syn_448","syn_449",
+ "syn_450","syn_451","syn_452","syn_453","syn_454","syn_455",
+ "syn_456","syn_457","syn_458","syn_459","syn_460","syn_461",
+ "syn_462","syn_463","syn_464","syn_465","syn_466","syn_467",
+ "syn_468","syn_469","syn_470","syn_471","syn_472","syn_473",
+ "syn_474","syn_475","syn_476","syn_477","syn_478","syn_479",
+ "syn_480","syn_481","syn_482","syn_483","syn_484","syn_485",
+ "syn_486","syn_487","syn_488","syn_489","syn_490","syn_491",
+ "syn_492","syn_493","syn_494","syn_495","syn_496","syn_497",
+ "syn_498","syn_499","syn_500","syn_501","syn_502","syn_503",
+ "syn_504","syn_505","syn_506","syn_507","syn_508","syn_509",
+ "syn_510","syn_511"
+ };
+
+
+int ev_key_total = 512; /* # of elements in array */
+char *ev_key[512] = {
+ "key_reserved","key_esc","key_1","key_2","key_3","key_4",
+ "key_5","key_6","key_7","key_8","key_9","key_0",
+ "key_minus","key_equal","key_backspace","key_tab","key_q","key_w",
+ "key_e","key_r","key_t","key_y","key_u","key_i",
+ "key_o","key_p","key_leftbrace","key_rightbrace","key_enter","key_leftctrl",
+ "key_a","key_s","key_d","key_f","key_g","key_h",
+ "key_j","key_k","key_l","key_semicolon","key_apostrophe","key_grave",
+ "key_leftshift","key_backslash","key_z","key_x","key_c","key_v",
+ "key_b","key_n","key_m","key_comma","key_dot","key_slash",
+ "key_rightshift","key_kpasterisk","key_leftalt","key_space","key_capslock","key_f1",
+ "key_f2","key_f3","key_f4","key_f5","key_f6","key_f7",
+ "key_f8","key_f9","key_f10","key_numlock","key_scrolllock","key_kp7",
+ "key_kp8","key_kp9","key_kpminus","key_kp4","key_kp5","key_kp6",
+ "key_kpplus","key_kp1","key_kp2","key_kp3","key_kp0","key_kpdot",
+ "key_84","key_zenkakuhankaku","key_102nd","key_f11","key_f12","key_ro",
+ "key_katakana","key_hiragana","key_henkan","key_katakanahiragana","key_muhenkan","key_kpjpcomma",
+ "key_kpenter","key_rightctrl","key_kpslash","key_sysrq","key_rightalt","key_linefeed",
+ "key_home","key_up","key_pageup","key_left","key_right","key_end",
+ "key_down","key_pagedown","key_insert","key_delete","key_macro","key_mute",
+ "key_volumedown","key_volumeup","key_power","key_kpequal","key_kpplusminus","key_pause",
+ "key_120","key_kpcomma","key_hanguel","key_hanja","key_yen","key_leftmeta",
+ "key_rightmeta","key_compose","key_stop","key_again","key_props","key_undo",
+ "key_front","key_copy","key_open","key_paste","key_find","key_cut",
+ "key_help","key_menu","key_calc","key_setup","key_sleep","key_wakeup",
+ "key_file","key_sendfile","key_deletefile","key_xfer","key_prog1","key_prog2",
+ "key_www","key_msdos","key_coffee","key_direction","key_cyclewindows","key_mail",
+ "key_bookmarks","key_computer","key_back","key_forward","key_closecd","key_ejectcd",
+ "key_ejectclosecd","key_nextsong","key_playpause","key_previoussong","key_stopcd","key_record",
+ "key_rewind","key_phone","key_iso","key_config","key_homepage","key_refresh",
+ "key_exit","key_move","key_edit","key_scrollup","key_scrolldown","key_kpleftparen",
+ "key_kprightparen","key_181","key_182","key_f13","key_f14","key_f15",
+ "key_f16","key_f17","key_f18","key_f19","key_f20","key_f21",
+ "key_f22","key_f23","key_f24","key_195","key_196","key_197",
+ "key_198","key_199","key_playcd","key_pausecd","key_prog3","key_prog4",
+ "key_204","key_suspend","key_close","key_play","key_fastforward","key_bassboost",
+ "key_print","key_hp","key_camera","key_sound","key_question","key_email",
+ "key_chat","key_search","key_connect","key_finance","key_sport","key_shop",
+ "key_alterase","key_cancel","key_brightnessdown","key_brightnessup","key_media","key_227",
+ "key_228","key_229","key_230","key_231","key_232","key_233",
+ "key_234","key_235","key_236","key_237","key_238","key_239",
+ "key_unknown","key_241","key_242","key_243","key_244","key_245",
+ "key_246","key_247","key_248","key_249","key_250","key_251",
+ "key_252","key_253","key_254","key_255","btn_0","btn_1",
+ "btn_2","btn_3","btn_4","btn_5","btn_6","btn_7",
+ "btn_8","btn_9","key_266","key_267","key_268","key_269",
+ "key_270","key_271","btn_left","btn_right","btn_middle","btn_side",
+ "btn_extra","btn_forward","btn_back","btn_task","key_280","key_281",
+ "key_282","key_283","key_284","key_285","key_286","key_287",
+ "btn_trigger","btn_thumb","btn_thumb2","btn_top","btn_top2","btn_pinkie",
+ "btn_base","btn_base2","btn_base3","btn_base4","btn_base5","btn_base6",
+ "key_300","key_301","key_302","btn_dead","btn_a","btn_b",
+ "btn_c","btn_x","btn_y","btn_z","btn_tl","btn_tr",
+ "btn_tl2","btn_tr2","btn_select","btn_start","btn_mode","btn_thumbl",
+ "btn_thumbr","key_319","btn_tool_pen","btn_tool_rubber","btn_tool_brush","btn_tool_pencil",
+ "btn_tool_airbrush","btn_tool_finger","btn_tool_mouse","btn_tool_lens","key_328","key_329",
+ "btn_touch","btn_stylus","btn_stylus2","btn_tool_doubletap","btn_tool_tripletap","key_335",
+ "btn_gear_down","btn_gear_up","key_338","key_339","key_340","key_341",
+ "key_342","key_343","key_344","key_345","key_346","key_347",
+ "key_348","key_349","key_350","key_351","key_ok","key_select",
+ "key_goto","key_clear","key_power2","key_option","key_info","key_time",
+ "key_vendor","key_archive","key_program","key_channel","key_favorites","key_epg",
+ "key_pvr","key_mhp","key_language","key_title","key_subtitle","key_angle",
+ "key_zoom","key_mode","key_keyboard","key_screen","key_pc","key_tv",
+ "key_tv2","key_vcr","key_vcr2","key_sat","key_sat2","key_cd",
+ "key_tape","key_radio","key_tuner","key_player","key_text","key_dvd",
+ "key_aux","key_mp3","key_audio","key_video","key_directory","key_list",
+ "key_memo","key_calendar","key_red","key_green","key_yellow","key_blue",
+ "key_channelup","key_channeldown","key_first","key_last","key_ab","key_next",
+ "key_restart","key_slow","key_shuffle","key_break","key_previous","key_digits",
+ "key_teen","key_twen","key_416","key_417","key_418","key_419",
+ "key_420","key_421","key_422","key_423","key_424","key_425",
+ "key_426","key_427","key_428","key_429","key_430","key_431",
+ "key_432","key_433","key_434","key_435","key_436","key_437",
+ "key_438","key_439","key_440","key_441","key_442","key_443",
+ "key_444","key_445","key_446","key_447","key_del_eol","key_del_eos",
+ "key_ins_line","key_del_line","key_452","key_453","key_454","key_455",
+ "key_456","key_457","key_458","key_459","key_460","key_461",
+ "key_462","key_463","key_fn","key_fn_esc","key_fn_f1","key_fn_f2",
+ "key_fn_f3","key_fn_f4","key_fn_f5","key_fn_f6","key_fn_f7","key_fn_f8",
+ "key_fn_f9","key_fn_f10","key_fn_f11","key_fn_f12","key_fn_1","key_fn_2",
+ "key_fn_d","key_fn_e","key_fn_f","key_fn_s","key_fn_b","key_485",
+ "key_486","key_487","key_488","key_489","key_490","key_491",
+ "key_492","key_493","key_494","key_495","key_496","key_497",
+ "key_498","key_499","key_500","key_501","key_502","key_503",
+ "key_504","key_505","key_506","key_507","key_508","key_509",
+ "key_510","key_511"
+ };
+
+
+int ev_rel_total = 16; /* # of elements in array */
+char *ev_rel[16] = {
+ "rel_x","rel_y","rel_z","rel_rx","rel_ry","rel_rz",
+ "rel_hwheel","rel_dial","rel_wheel","rel_misc","rel_10","rel_11",
+ "rel_12","rel_13","rel_14","rel_15"
+ };
+
+
+int ev_abs_total = 64; /* # of elements in array */
+char *ev_abs[64] = {
+ "abs_x","abs_y","abs_z","abs_rx","abs_ry","abs_rz",
+ "abs_throttle","abs_rudder","abs_wheel","abs_gas","abs_brake","abs_11",
+ "abs_12","abs_13","abs_14","abs_15","abs_hat0x","abs_hat0y",
+ "abs_hat1x","abs_hat1y","abs_hat2x","abs_hat2y","abs_hat3x","abs_hat3y",
+ "abs_pressure","abs_distance","abs_tilt_x","abs_tilt_y","abs_tool_width","abs_29",
+ "abs_30","abs_31","abs_volume","abs_33","abs_34","abs_35",
+ "abs_36","abs_37","abs_38","abs_39","abs_misc","abs_41",
+ "abs_42","abs_43","abs_44","abs_45","abs_46","abs_47",
+ "abs_48","abs_49","abs_50","abs_51","abs_52","abs_53",
+ "abs_54","abs_55","abs_56","abs_57","abs_58","abs_59",
+ "abs_60","abs_61","abs_62","abs_63"
+ };
+
+
+int ev_msc_total = 8; /* # of elements in array */
+char *ev_msc[8] = {
+ "msc_serial","msc_pulseled","msc_gesture","msc_raw","msc_scan","msc_5",
+ "msc_6","msc_7"
+ };
+
+
+int ev_led_total = 16; /* # of elements in array */
+char *ev_led[16] = {
+ "led_numl","led_capsl","led_scrolll","led_compose","led_kana","led_sleep",
+ "led_suspend","led_mute","led_misc","led_mail","led_charging","led_11",
+ "led_12","led_13","led_14","led_15"
+ };
+
+
+int ev_snd_total = 8; /* # of elements in array */
+char *ev_snd[8] = {
+ "snd_click","snd_bell","snd_tone","snd_3","snd_4","snd_5",
+ "snd_6","snd_7"
+ };
+
+
+int ev_rep_total = 2; /* # of elements in array */
+char *ev_rep[2] = {
+ "rep_delay","rep_period"
+ };
+
+
+int ev_ff_total = 128; /* # of elements in array */
+char *ev_ff[128] = {
+ "ff_0","ff_1","ff_2","ff_3","ff_4","ff_5",
+ "ff_6","ff_7","ff_8","ff_9","ff_10","ff_11",
+ "ff_12","ff_13","ff_14","ff_15","ff_16","ff_17",
+ "ff_18","ff_19","ff_20","ff_21","ff_22","ff_23",
+ "ff_24","ff_25","ff_26","ff_27","ff_28","ff_29",
+ "ff_30","ff_31","ff_32","ff_33","ff_34","ff_35",
+ "ff_36","ff_37","ff_38","ff_39","ff_40","ff_41",
+ "ff_42","ff_43","ff_44","ff_45","ff_46","ff_47",
+ "ff_48","ff_49","ff_50","ff_51","ff_52","ff_53",
+ "ff_54","ff_55","ff_56","ff_57","ff_58","ff_59",
+ "ff_60","ff_61","ff_62","ff_63","ff_64","ff_65",
+ "ff_66","ff_67","ff_68","ff_69","ff_70","ff_71",
+ "ff_72","ff_73","ff_74","ff_75","ff_76","ff_77",
+ "ff_78","ff_79","ff_rumble","ff_periodic","ff_constant","ff_spring",
+ "ff_friction","ff_damper","ff_inertia","ff_ramp","ff_square","ff_triangle",
+ "ff_sine","ff_saw_up","ff_saw_down","ff_custom","ff_94","ff_95",
+ "ff_gain","ff_autocenter","ff_98","ff_99","ff_100","ff_101",
+ "ff_102","ff_103","ff_104","ff_105","ff_106","ff_107",
+ "ff_108","ff_109","ff_110","ff_111","ff_112","ff_113",
+ "ff_114","ff_115","ff_116","ff_117","ff_118","ff_119",
+ "ff_120","ff_121","ff_122","ff_123","ff_124","ff_125",
+ "ff_126","ff_127"
+ };
+
+
+char *ev_pwr[1] = { NULL };
+
+int ev_ff_status_total = 2; /* # of elements in array */
+char *ev_ff_status[2] = {
+ "ff_status_stopped","ff_status_playing"
+ };
+
+
+
+ int ev_5_total = 16; /* # of elements in array */
+char *ev_5[16] = {
+ "ev_5_1","ev_5_2","ev_5_3","ev_5_4","ev_5_5","ev_5_6",
+ "ev_5_7","ev_5_8","ev_5_9","ev_5_10","ev_5_11","ev_5_12",
+ "ev_5_13","ev_5_14","ev_5_15","ev_5_16"
+ };
+
+
+int ev_6_total = 16; /* # of elements in array */
+char *ev_6[16] = {
+ "ev_6_1","ev_6_2","ev_6_3","ev_6_4","ev_6_5","ev_6_6",
+ "ev_6_7","ev_6_8","ev_6_9","ev_6_10","ev_6_11","ev_6_12",
+ "ev_6_13","ev_6_14","ev_6_15","ev_6_16"
+ };
+
+
+
+ int ev_7_total = 16; /* # of elements in array */
+char *ev_7[16] = {
+ "ev_7_1","ev_7_2","ev_7_3","ev_7_4","ev_7_5","ev_7_6",
+ "ev_7_7","ev_7_8","ev_7_9","ev_7_10","ev_7_11","ev_7_12",
+ "ev_7_13","ev_7_14","ev_7_15","ev_7_16"
+ };
+
+
+int ev_8_total = 16; /* # of elements in array */
+char *ev_8[16] = {
+ "ev_8_1","ev_8_2","ev_8_3","ev_8_4","ev_8_5","ev_8_6",
+ "ev_8_7","ev_8_8","ev_8_9","ev_8_10","ev_8_11","ev_8_12",
+ "ev_8_13","ev_8_14","ev_8_15","ev_8_16"
+ };
+
+
+int ev_9_total = 16; /* # of elements in array */
+char *ev_9[16] = {
+ "ev_9_1","ev_9_2","ev_9_3","ev_9_4","ev_9_5","ev_9_6",
+ "ev_9_7","ev_9_8","ev_9_9","ev_9_10","ev_9_11","ev_9_12",
+ "ev_9_13","ev_9_14","ev_9_15","ev_9_16"
+ };
+
+
+int ev_10_total = 16; /* # of elements in array */
+char *ev_10[16] = {
+ "ev_10_1","ev_10_2","ev_10_3","ev_10_4","ev_10_5","ev_10_6",
+ "ev_10_7","ev_10_8","ev_10_9","ev_10_10","ev_10_11","ev_10_12",
+ "ev_10_13","ev_10_14","ev_10_15","ev_10_16"
+ };
+
+
+int ev_11_total = 16; /* # of elements in array */
+char *ev_11[16] = {
+ "ev_11_1","ev_11_2","ev_11_3","ev_11_4","ev_11_5","ev_11_6",
+ "ev_11_7","ev_11_8","ev_11_9","ev_11_10","ev_11_11","ev_11_12",
+ "ev_11_13","ev_11_14","ev_11_15","ev_11_16"
+ };
+
+
+int ev_12_total = 16; /* # of elements in array */
+char *ev_12[16] = {
+ "ev_12_1","ev_12_2","ev_12_3","ev_12_4","ev_12_5","ev_12_6",
+ "ev_12_7","ev_12_8","ev_12_9","ev_12_10","ev_12_11","ev_12_12",
+ "ev_12_13","ev_12_14","ev_12_15","ev_12_16"
+ };
+
+
+
+ int ev_13_total = 16; /* # of elements in array */
+char *ev_13[16] = {
+ "ev_13_1","ev_13_2","ev_13_3","ev_13_4","ev_13_5","ev_13_6",
+ "ev_13_7","ev_13_8","ev_13_9","ev_13_10","ev_13_11","ev_13_12",
+ "ev_13_13","ev_13_14","ev_13_15","ev_13_16"
+ };
+
+
+int ev_14_total = 16; /* # of elements in array */
+char *ev_14[16] = {
+ "ev_14_1","ev_14_2","ev_14_3","ev_14_4","ev_14_5","ev_14_6",
+ "ev_14_7","ev_14_8","ev_14_9","ev_14_10","ev_14_11","ev_14_12",
+ "ev_14_13","ev_14_14","ev_14_15","ev_14_16"
+ };
+
+
+int ev_15_total = 16; /* # of elements in array */
+char *ev_15[16] = {
+ "ev_15_1","ev_15_2","ev_15_3","ev_15_4","ev_15_5","ev_15_6",
+ "ev_15_7","ev_15_8","ev_15_9","ev_15_10","ev_15_11","ev_15_12",
+ "ev_15_13","ev_15_14","ev_15_15","ev_15_16"
+ };
+
+
+int ev_16_total = 16; /* # of elements in array */
+char *ev_16[16] = {
+ "ev_16_1","ev_16_2","ev_16_3","ev_16_4","ev_16_5","ev_16_6",
+ "ev_16_7","ev_16_8","ev_16_9","ev_16_10","ev_16_11","ev_16_12",
+ "ev_16_13","ev_16_14","ev_16_15","ev_16_16"
+ };
+
+
+
+ int ev_19_total = 16; /* # of elements in array */
+char *ev_19[16] = {
+ "ev_19_1","ev_19_2","ev_19_3","ev_19_4","ev_19_5","ev_19_6",
+ "ev_19_7","ev_19_8","ev_19_9","ev_19_10","ev_19_11","ev_19_12",
+ "ev_19_13","ev_19_14","ev_19_15","ev_19_16"
+ };
+
+
+int ev_24_total = 16; /* # of elements in array */
+char *ev_24[16] = {
+ "ev_24_1","ev_24_2","ev_24_3","ev_24_4","ev_24_5","ev_24_6",
+ "ev_24_7","ev_24_8","ev_24_9","ev_24_10","ev_24_11","ev_24_12",
+ "ev_24_13","ev_24_14","ev_24_15","ev_24_16"
+ };
+
+
+
+ int ev_25_total = 16; /* # of elements in array */
+char *ev_25[16] = {
+ "ev_25_1","ev_25_2","ev_25_3","ev_25_4","ev_25_5","ev_25_6",
+ "ev_25_7","ev_25_8","ev_25_9","ev_25_10","ev_25_11","ev_25_12",
+ "ev_25_13","ev_25_14","ev_25_15","ev_25_16"
+ };
+
+
+int ev_26_total = 16; /* # of elements in array */
+char *ev_26[16] = {
+ "ev_26_1","ev_26_2","ev_26_3","ev_26_4","ev_26_5","ev_26_6",
+ "ev_26_7","ev_26_8","ev_26_9","ev_26_10","ev_26_11","ev_26_12",
+ "ev_26_13","ev_26_14","ev_26_15","ev_26_16"
+ };
+
+
+int ev_27_total = 16; /* # of elements in array */
+char *ev_27[16] = {
+ "ev_27_1","ev_27_2","ev_27_3","ev_27_4","ev_27_5","ev_27_6",
+ "ev_27_7","ev_27_8","ev_27_9","ev_27_10","ev_27_11","ev_27_12",
+ "ev_27_13","ev_27_14","ev_27_15","ev_27_16"
+ };
+
+
+int ev_28_total = 16; /* # of elements in array */
+char *ev_28[16] = {
+ "ev_28_1","ev_28_2","ev_28_3","ev_28_4","ev_28_5","ev_28_6",
+ "ev_28_7","ev_28_8","ev_28_9","ev_28_10","ev_28_11","ev_28_12",
+ "ev_28_13","ev_28_14","ev_28_15","ev_28_16"
+ };
+
+
+int ev_29_total = 16; /* # of elements in array */
+char *ev_29[16] = {
+ "ev_29_1","ev_29_2","ev_29_3","ev_29_4","ev_29_5","ev_29_6",
+ "ev_29_7","ev_29_8","ev_29_9","ev_29_10","ev_29_11","ev_29_12",
+ "ev_29_13","ev_29_14","ev_29_15","ev_29_16"
+ };
+
+
+int ev_30_total = 16; /* # of elements in array */
+char *ev_30[16] = {
+ "ev_30_1","ev_30_2","ev_30_3","ev_30_4","ev_30_5","ev_30_6",
+ "ev_30_7","ev_30_8","ev_30_9","ev_30_10","ev_30_11","ev_30_12",
+ "ev_30_13","ev_30_14","ev_30_15","ev_30_16"
+ };
+
+
+
+ int ev_31_total = 16; /* # of elements in array */
+char *ev_31[16] = {
+ "ev_31_1","ev_31_2","ev_31_3","ev_31_4","ev_31_5","ev_31_6",
+ "ev_31_7","ev_31_8","ev_31_9","ev_31_10","ev_31_11","ev_31_12",
+ "ev_31_13","ev_31_14","ev_31_15","ev_31_16"
+ };
+
+
+char **event_names[32] = {ev_syn,
+ ev_key,ev_rel,ev_abs,ev_msc,ev_5,ev_6,
+ ev_7,ev_8,ev_9,ev_10,ev_11,ev_12,
+ ev_13,ev_14,ev_15,ev_16,ev_led,ev_snd,
+ ev_19,ev_rep,ev_ff,ev_pwr,ev_ff_status,ev_24,
+ ev_25,ev_26,ev_27,ev_28,ev_29,ev_30,ev_31
+ };
diff --git a/input_arrays.h b/input_arrays.h
new file mode 100644
index 0000000..ea3ce75
--- /dev/null
+++ b/input_arrays.h
@@ -0,0 +1,42 @@
+#ifndef _INPUT_ARRAYS_H
+#define _INPUT_ARRAYS_H
+
+
+char *ev[32];
+char *ev_syn[512];
+char *ev_key[512];
+char *ev_rel[16];
+char *ev_abs[64];
+char *ev_msc[8];
+char *ev_led[16];
+char *ev_snd[8];
+char *ev_rep[2];
+char *ev_ff[128];
+char *ev_pwr[1];
+char *ev_ff_status[2];
+char *ev_5[16];
+char *ev_6[16];
+char *ev_7[16];
+char *ev_8[16];
+char *ev_9[16];
+char *ev_10[16];
+char *ev_11[16];
+char *ev_12[16];
+char *ev_13[16];
+char *ev_14[16];
+char *ev_15[16];
+char *ev_16[16];
+char *ev_19[16];
+char *ev_24[16];
+char *ev_25[16];
+char *ev_26[16];
+char *ev_27[16];
+char *ev_28[16];
+char *ev_29[16];
+char *ev_30[16];
+char *ev_31[16];
+char **event_names[32];
+
+
+
+#endif /* #ifndef _INPUT_ARRAYS_H */
diff --git a/linux/input.h b/linux/input.h
new file mode 100644
index 0000000..aa20409
--- /dev/null
+++ b/linux/input.h
@@ -0,0 +1,1016 @@
+#ifndef _INPUT_H
+#define _INPUT_H
+
+/*
+ * Copyright (c) 1999-2002 Vojtech Pavlik
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#ifdef __KERNEL__
+#include <linux/time.h>
+#include <linux/list.h>
+#else
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <asm/types.h>
+#endif
+
+/*
+ * The event structure itself
+ */
+
+struct input_event {
+ struct timeval time;
+ __u16 type;
+ __u16 code;
+ __s32 value;
+};
+
+/*
+ * Protocol version.
+ */
+
+#define EV_VERSION 0x010000
+
+/*
+ * IOCTLs (0x00 - 0x7f)
+ */
+
+struct input_id {
+ __u16 bustype;
+ __u16 vendor;
+ __u16 product;
+ __u16 version;
+};
+
+struct input_absinfo {
+ __s32 value;
+ __s32 minimum;
+ __s32 maximum;
+ __s32 fuzz;
+ __s32 flat;
+};
+
+#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */
+#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */
+#define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */
+#define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */
+
+#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
+#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */
+#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
+
+#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */
+#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
+#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
+
+#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */
+#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */
+#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */
+
+#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */
+#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
+#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */
+
+#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
+
+/*
+ * Event types
+ */
+
+#define EV_SYN 0x00
+#define EV_KEY 0x01
+#define EV_REL 0x02
+#define EV_ABS 0x03
+#define EV_MSC 0x04
+#define EV_LED 0x11
+#define EV_SND 0x12
+#define EV_REP 0x14
+#define EV_FF 0x15
+#define EV_PWR 0x16
+#define EV_FF_STATUS 0x17
+#define EV_MAX 0x1f
+
+/*
+ * Synchronization events.
+ */
+
+#define SYN_REPORT 0
+#define SYN_CONFIG 1
+
+/*
+ * Keys and buttons
+ */
+
+#define KEY_RESERVED 0
+#define KEY_ESC 1
+#define KEY_1 2
+#define KEY_2 3
+#define KEY_3 4
+#define KEY_4 5
+#define KEY_5 6
+#define KEY_6 7
+#define KEY_7 8
+#define KEY_8 9
+#define KEY_9 10
+#define KEY_0 11
+#define KEY_MINUS 12
+#define KEY_EQUAL 13
+#define KEY_BACKSPACE 14
+#define KEY_TAB 15
+#define KEY_Q 16
+#define KEY_W 17
+#define KEY_E 18
+#define KEY_R 19
+#define KEY_T 20
+#define KEY_Y 21
+#define KEY_U 22
+#define KEY_I 23
+#define KEY_O 24
+#define KEY_P 25
+#define KEY_LEFTBRACE 26
+#define KEY_RIGHTBRACE 27
+#define KEY_ENTER 28
+#define KEY_LEFTCTRL 29
+#define KEY_A 30
+#define KEY_S 31
+#define KEY_D 32
+#define KEY_F 33
+#define KEY_G 34
+#define KEY_H 35
+#define KEY_J 36
+#define KEY_K 37
+#define KEY_L 38
+#define KEY_SEMICOLON 39
+#define KEY_APOSTROPHE 40
+#define KEY_GRAVE 41
+#define KEY_LEFTSHIFT 42
+#define KEY_BACKSLASH 43
+#define KEY_Z 44
+#define KEY_X 45
+#define KEY_C 46
+#define KEY_V 47
+#define KEY_B 48
+#define KEY_N 49
+#define KEY_M 50
+#define KEY_COMMA 51
+#define KEY_DOT 52
+#define KEY_SLASH 53
+#define KEY_RIGHTSHIFT 54
+#define KEY_KPASTERISK 55
+#define KEY_LEFTALT 56
+#define KEY_SPACE 57
+#define KEY_CAPSLOCK 58
+#define KEY_F1 59
+#define KEY_F2 60
+#define KEY_F3 61
+#define KEY_F4 62
+#define KEY_F5 63
+#define KEY_F6 64
+#define KEY_F7 65
+#define KEY_F8 66
+#define KEY_F9 67
+#define KEY_F10 68
+#define KEY_NUMLOCK 69
+#define KEY_SCROLLLOCK 70
+#define KEY_KP7 71
+#define KEY_KP8 72
+#define KEY_KP9 73
+#define KEY_KPMINUS 74
+#define KEY_KP4 75
+#define KEY_KP5 76
+#define KEY_KP6 77
+#define KEY_KPPLUS 78
+#define KEY_KP1 79
+#define KEY_KP2 80
+#define KEY_KP3 81
+#define KEY_KP0 82
+#define KEY_KPDOT 83
+
+#define KEY_ZENKAKUHANKAKU 85
+#define KEY_102ND 86
+#define KEY_F11 87
+#define KEY_F12 88
+#define KEY_RO 89
+#define KEY_KATAKANA 90
+#define KEY_HIRAGANA 91
+#define KEY_HENKAN 92
+#define KEY_KATAKANAHIRAGANA 93
+#define KEY_MUHENKAN 94
+#define KEY_KPJPCOMMA 95
+#define KEY_KPENTER 96
+#define KEY_RIGHTCTRL 97
+#define KEY_KPSLASH 98
+#define KEY_SYSRQ 99
+#define KEY_RIGHTALT 100
+#define KEY_LINEFEED 101
+#define KEY_HOME 102
+#define KEY_UP 103
+#define KEY_PAGEUP 104
+#define KEY_LEFT 105
+#define KEY_RIGHT 106
+#define KEY_END 107
+#define KEY_DOWN 108
+#define KEY_PAGEDOWN 109
+#define KEY_INSERT 110
+#define KEY_DELETE 111
+#define KEY_MACRO 112
+#define KEY_MUTE 113
+#define KEY_VOLUMEDOWN 114
+#define KEY_VOLUMEUP 115
+#define KEY_POWER 116
+#define KEY_KPEQUAL 117
+#define KEY_KPPLUSMINUS 118
+#define KEY_PAUSE 119
+
+#define KEY_KPCOMMA 121
+#define KEY_HANGUEL 122
+#define KEY_HANJA 123
+#define KEY_YEN 124
+#define KEY_LEFTMETA 125
+#define KEY_RIGHTMETA 126
+#define KEY_COMPOSE 127
+
+#define KEY_STOP 128
+#define KEY_AGAIN 129
+#define KEY_PROPS 130
+#define KEY_UNDO 131
+#define KEY_FRONT 132
+#define KEY_COPY 133
+#define KEY_OPEN 134
+#define KEY_PASTE 135
+#define KEY_FIND 136
+#define KEY_CUT 137
+#define KEY_HELP 138
+#define KEY_MENU 139
+#define KEY_CALC 140
+#define KEY_SETUP 141
+#define KEY_SLEEP 142
+#define KEY_WAKEUP 143
+#define KEY_FILE 144
+#define KEY_SENDFILE 145
+#define KEY_DELETEFILE 146
+#define KEY_XFER 147
+#define KEY_PROG1 148
+#define KEY_PROG2 149
+#define KEY_WWW 150
+#define KEY_MSDOS 151
+#define KEY_COFFEE 152
+#define KEY_DIRECTION 153
+#define KEY_CYCLEWINDOWS 154
+#define KEY_MAIL 155
+#define KEY_BOOKMARKS 156
+#define KEY_COMPUTER 157
+#define KEY_BACK 158
+#define KEY_FORWARD 159
+#define KEY_CLOSECD 160
+#define KEY_EJECTCD 161
+#define KEY_EJECTCLOSECD 162
+#define KEY_NEXTSONG 163
+#define KEY_PLAYPAUSE 164
+#define KEY_PREVIOUSSONG 165
+#define KEY_STOPCD 166
+#define KEY_RECORD 167
+#define KEY_REWIND 168
+#define KEY_PHONE 169
+#define KEY_ISO 170
+#define KEY_CONFIG 171
+#define KEY_HOMEPAGE 172
+#define KEY_REFRESH 173
+#define KEY_EXIT 174
+#define KEY_MOVE 175
+#define KEY_EDIT 176
+#define KEY_SCROLLUP 177
+#define KEY_SCROLLDOWN 178
+#define KEY_KPLEFTPAREN 179
+#define KEY_KPRIGHTPAREN 180
+
+#define KEY_F13 183
+#define KEY_F14 184
+#define KEY_F15 185
+#define KEY_F16 186
+#define KEY_F17 187
+#define KEY_F18 188
+#define KEY_F19 189
+#define KEY_F20 190
+#define KEY_F21 191
+#define KEY_F22 192
+#define KEY_F23 193
+#define KEY_F24 194
+
+#define KEY_PLAYCD 200
+#define KEY_PAUSECD 201
+#define KEY_PROG3 202
+#define KEY_PROG4 203
+#define KEY_SUSPEND 205
+#define KEY_CLOSE 206
+#define KEY_PLAY 207
+#define KEY_FASTFORWARD 208
+#define KEY_BASSBOOST 209
+#define KEY_PRINT 210
+#define KEY_HP 211
+#define KEY_CAMERA 212
+#define KEY_SOUND 213
+#define KEY_QUESTION 214
+#define KEY_EMAIL 215
+#define KEY_CHAT 216
+#define KEY_SEARCH 217
+#define KEY_CONNECT 218
+#define KEY_FINANCE 219
+#define KEY_SPORT 220
+#define KEY_SHOP 221
+#define KEY_ALTERASE 222
+#define KEY_CANCEL 223
+#define KEY_BRIGHTNESSDOWN 224
+#define KEY_BRIGHTNESSUP 225
+#define KEY_MEDIA 226
+
+#define KEY_UNKNOWN 240
+
+#define BTN_MISC 0x100
+#define BTN_0 0x100
+#define BTN_1 0x101
+#define BTN_2 0x102
+#define BTN_3 0x103
+#define BTN_4 0x104
+#define BTN_5 0x105
+#define BTN_6 0x106
+#define BTN_7 0x107
+#define BTN_8 0x108
+#define BTN_9 0x109
+
+#define BTN_MOUSE 0x110
+#define BTN_LEFT 0x110
+#define BTN_RIGHT 0x111
+#define BTN_MIDDLE 0x112
+#define BTN_SIDE 0x113
+#define BTN_EXTRA 0x114
+#define BTN_FORWARD 0x115
+#define BTN_BACK 0x116
+#define BTN_TASK 0x117
+
+#define BTN_JOYSTICK 0x120
+#define BTN_TRIGGER 0x120
+#define BTN_THUMB 0x121
+#define BTN_THUMB2 0x122
+#define BTN_TOP 0x123
+#define BTN_TOP2 0x124
+#define BTN_PINKIE 0x125
+#define BTN_BASE 0x126
+#define BTN_BASE2 0x127
+#define BTN_BASE3 0x128
+#define BTN_BASE4 0x129
+#define BTN_BASE5 0x12a
+#define BTN_BASE6 0x12b
+#define BTN_DEAD 0x12f
+
+#define BTN_GAMEPAD 0x130
+#define BTN_A 0x130
+#define BTN_B 0x131
+#define BTN_C 0x132
+#define BTN_X 0x133
+#define BTN_Y 0x134
+#define BTN_Z 0x135
+#define BTN_TL 0x136
+#define BTN_TR 0x137
+#define BTN_TL2 0x138
+#define BTN_TR2 0x139
+#define BTN_SELECT 0x13a
+#define BTN_START 0x13b
+#define BTN_MODE 0x13c
+#define BTN_THUMBL 0x13d
+#define BTN_THUMBR 0x13e
+
+#define BTN_DIGI 0x140
+#define BTN_TOOL_PEN 0x140
+#define BTN_TOOL_RUBBER 0x141
+#define BTN_TOOL_BRUSH 0x142
+#define BTN_TOOL_PENCIL 0x143
+#define BTN_TOOL_AIRBRUSH 0x144
+#define BTN_TOOL_FINGER 0x145
+#define BTN_TOOL_MOUSE 0x146
+#define BTN_TOOL_LENS 0x147
+#define BTN_TOUCH 0x14a
+#define BTN_STYLUS 0x14b
+#define BTN_STYLUS2 0x14c
+#define BTN_TOOL_DOUBLETAP 0x14d
+#define BTN_TOOL_TRIPLETAP 0x14e
+
+#define BTN_WHEEL 0x150
+#define BTN_GEAR_DOWN 0x150
+#define BTN_GEAR_UP 0x151
+
+#define KEY_OK 0x160
+#define KEY_SELECT 0x161
+#define KEY_GOTO 0x162
+#define KEY_CLEAR 0x163
+#define KEY_POWER2 0x164
+#define KEY_OPTION 0x165
+#define KEY_INFO 0x166
+#define KEY_TIME 0x167
+#define KEY_VENDOR 0x168
+#define KEY_ARCHIVE 0x169
+#define KEY_PROGRAM 0x16a
+#define KEY_CHANNEL 0x16b
+#define KEY_FAVORITES 0x16c
+#define KEY_EPG 0x16d
+#define KEY_PVR 0x16e
+#define KEY_MHP 0x16f
+#define KEY_LANGUAGE 0x170
+#define KEY_TITLE 0x171
+#define KEY_SUBTITLE 0x172
+#define KEY_ANGLE 0x173
+#define KEY_ZOOM 0x174
+#define KEY_MODE 0x175
+#define KEY_KEYBOARD 0x176
+#define KEY_SCREEN 0x177
+#define KEY_PC 0x178
+#define KEY_TV 0x179
+#define KEY_TV2 0x17a
+#define KEY_VCR 0x17b
+#define KEY_VCR2 0x17c
+#define KEY_SAT 0x17d
+#define KEY_SAT2 0x17e
+#define KEY_CD 0x17f
+#define KEY_TAPE 0x180
+#define KEY_RADIO 0x181
+#define KEY_TUNER 0x182
+#define KEY_PLAYER 0x183
+#define KEY_TEXT 0x184
+#define KEY_DVD 0x185
+#define KEY_AUX 0x186
+#define KEY_MP3 0x187
+#define KEY_AUDIO 0x188
+#define KEY_VIDEO 0x189
+#define KEY_DIRECTORY 0x18a
+#define KEY_LIST 0x18b
+#define KEY_MEMO 0x18c
+#define KEY_CALENDAR 0x18d
+#define KEY_RED 0x18e
+#define KEY_GREEN 0x18f
+#define KEY_YELLOW 0x190
+#define KEY_BLUE 0x191
+#define KEY_CHANNELUP 0x192
+#define KEY_CHANNELDOWN 0x193
+#define KEY_FIRST 0x194
+#define KEY_LAST 0x195
+#define KEY_AB 0x196
+#define KEY_NEXT 0x197
+#define KEY_RESTART 0x198
+#define KEY_SLOW 0x199
+#define KEY_SHUFFLE 0x19a
+#define KEY_BREAK 0x19b
+#define KEY_PREVIOUS 0x19c
+#define KEY_DIGITS 0x19d
+#define KEY_TEEN 0x19e
+#define KEY_TWEN 0x19f
+
+#define KEY_DEL_EOL 0x1c0
+#define KEY_DEL_EOS 0x1c1
+#define KEY_INS_LINE 0x1c2
+#define KEY_DEL_LINE 0x1c3
+
+#define KEY_FN 0x1d0
+#define KEY_FN_ESC 0x1d1
+#define KEY_FN_F1 0x1d2
+#define KEY_FN_F2 0x1d3
+#define KEY_FN_F3 0x1d4
+#define KEY_FN_F4 0x1d5
+#define KEY_FN_F5 0x1d6
+#define KEY_FN_F6 0x1d7
+#define KEY_FN_F7 0x1d8
+#define KEY_FN_F8 0x1d9
+#define KEY_FN_F9 0x1da
+#define KEY_FN_F10 0x1db
+#define KEY_FN_F11 0x1dc
+#define KEY_FN_F12 0x1dd
+#define KEY_FN_1 0x1de
+#define KEY_FN_2 0x1df
+#define KEY_FN_D 0x1e0
+#define KEY_FN_E 0x1e1
+#define KEY_FN_F 0x1e2
+#define KEY_FN_S 0x1e3
+#define KEY_FN_B 0x1e4
+
+#define KEY_MAX 0x1ff
+
+/*
+ * Relative axes
+ */
+
+#define REL_X 0x00
+#define REL_Y 0x01
+#define REL_Z 0x02
+#define REL_RX 0x03
+#define REL_RY 0x04
+#define REL_RZ 0x05
+#define REL_HWHEEL 0x06
+#define REL_DIAL 0x07
+#define REL_WHEEL 0x08
+#define REL_MISC 0x09
+#define REL_MAX 0x0f
+
+/*
+ * Absolute axes
+ */
+
+#define ABS_X 0x00
+#define ABS_Y 0x01
+#define ABS_Z 0x02
+#define ABS_RX 0x03
+#define ABS_RY 0x04
+#define ABS_RZ 0x05
+#define ABS_THROTTLE 0x06
+#define ABS_RUDDER 0x07
+#define ABS_WHEEL 0x08
+#define ABS_GAS 0x09
+#define ABS_BRAKE 0x0a
+#define ABS_HAT0X 0x10
+#define ABS_HAT0Y 0x11
+#define ABS_HAT1X 0x12
+#define ABS_HAT1Y 0x13
+#define ABS_HAT2X 0x14
+#define ABS_HAT2Y 0x15
+#define ABS_HAT3X 0x16
+#define ABS_HAT3Y 0x17
+#define ABS_PRESSURE 0x18
+#define ABS_DISTANCE 0x19
+#define ABS_TILT_X 0x1a
+#define ABS_TILT_Y 0x1b
+#define ABS_TOOL_WIDTH 0x1c
+#define ABS_VOLUME 0x20
+#define ABS_MISC 0x28
+#define ABS_MAX 0x3f
+
+/*
+ * Misc events
+ */
+
+#define MSC_SERIAL 0x00
+#define MSC_PULSELED 0x01
+#define MSC_GESTURE 0x02
+#define MSC_RAW 0x03
+#define MSC_SCAN 0x04
+#define MSC_MAX 0x07
+
+/*
+ * LEDs
+ */
+
+#define LED_NUML 0x00
+#define LED_CAPSL 0x01
+#define LED_SCROLLL 0x02
+#define LED_COMPOSE 0x03
+#define LED_KANA 0x04
+#define LED_SLEEP 0x05
+#define LED_SUSPEND 0x06
+#define LED_MUTE 0x07
+#define LED_MISC 0x08
+#define LED_MAIL 0x09
+#define LED_CHARGING 0x0a
+#define LED_MAX 0x0f
+
+/*
+ * Autorepeat values
+ */
+
+#define REP_DELAY 0x00
+#define REP_PERIOD 0x01
+#define REP_MAX 0x01
+
+/*
+ * Sounds
+ */
+
+#define SND_CLICK 0x00
+#define SND_BELL 0x01
+#define SND_TONE 0x02
+#define SND_MAX 0x07
+
+/*
+ * IDs.
+ */
+
+#define ID_BUS 0
+#define ID_VENDOR 1
+#define ID_PRODUCT 2
+#define ID_VERSION 3
+
+#define BUS_PCI 0x01
+#define BUS_ISAPNP 0x02
+#define BUS_USB 0x03
+#define BUS_HIL 0x04
+#define BUS_BLUETOOTH 0x05
+
+#define BUS_ISA 0x10
+#define BUS_I8042 0x11
+#define BUS_XTKBD 0x12
+#define BUS_RS232 0x13
+#define BUS_GAMEPORT 0x14
+#define BUS_PARPORT 0x15
+#define BUS_AMIGA 0x16
+#define BUS_ADB 0x17
+#define BUS_I2C 0x18
+#define BUS_HOST 0x19
+
+/*
+ * Values describing the status of an effect
+ */
+#define FF_STATUS_STOPPED 0x00
+#define FF_STATUS_PLAYING 0x01
+#define FF_STATUS_MAX 0x01
+
+/*
+ * Structures used in ioctls to upload effects to a device
+ * The first structures are not passed directly by using ioctls.
+ * They are sub-structures of the actually sent structure (called ff_effect)
+ */
+
+struct ff_replay {
+ __u16 length; /* Duration of an effect in ms. All other times are also expressed in ms */
+ __u16 delay; /* Time to wait before to start playing an effect */
+};
+
+struct ff_trigger {
+ __u16 button; /* Number of button triggering an effect */
+ __u16 interval; /* Time to wait before an effect can be re-triggered (ms) */
+};
+
+struct ff_envelope {
+ __u16 attack_length; /* Duration of attack (ms) */
+ __u16 attack_level; /* Level at beginning of attack */
+ __u16 fade_length; /* Duration of fade (ms) */
+ __u16 fade_level; /* Level at end of fade */
+};
+
+/* FF_CONSTANT */
+struct ff_constant_effect {
+ __s16 level; /* Strength of effect. Negative values are OK */
+ struct ff_envelope envelope;
+};
+
+/* FF_RAMP */
+struct ff_ramp_effect {
+ __s16 start_level;
+ __s16 end_level;
+ struct ff_envelope envelope;
+};
+
+/* FF_SPRING of FF_FRICTION */
+struct ff_condition_effect {
+ __u16 right_saturation; /* Max level when joystick is on the right */
+ __u16 left_saturation; /* Max level when joystick in on the left */
+
+ __s16 right_coeff; /* Indicates how fast the force grows when the
+ joystick moves to the right */
+ __s16 left_coeff; /* Same for left side */
+
+ __u16 deadband; /* Size of area where no force is produced */
+ __s16 center; /* Position of dead zone */
+
+};
+
+/* FF_PERIODIC */
+struct ff_periodic_effect {
+ __u16 waveform; /* Kind of wave (sine, square...) */
+ __u16 period; /* in ms */
+ __s16 magnitude; /* Peak value */
+ __s16 offset; /* Mean value of wave (roughly) */
+ __u16 phase; /* 'Horizontal' shift */
+
+ struct ff_envelope envelope;
+
+/* Only used if waveform == FF_CUSTOM */
+ __u32 custom_len; /* Number of samples */
+ __s16 *custom_data; /* Buffer of samples */
+/* Note: the data pointed by custom_data is copied by the driver. You can
+ * therefore dispose of the memory after the upload/update */
+};
+
+/* FF_RUMBLE */
+/* Some rumble pads have two motors of different weight.
+ strong_magnitude represents the magnitude of the vibration generated
+ by the heavy motor.
+*/
+struct ff_rumble_effect {
+ __u16 strong_magnitude; /* Magnitude of the heavy motor */
+ __u16 weak_magnitude; /* Magnitude of the light one */
+};
+
+/*
+ * Structure sent through ioctl from the application to the driver
+ */
+struct ff_effect {
+ __u16 type;
+/* Following field denotes the unique id assigned to an effect.
+ * If user sets if to -1, a new effect is created, and its id is returned in the same field
+ * Else, the user sets it to the effect id it wants to update.
+ */
+ __s16 id;
+
+ __u16 direction; /* Direction. 0 deg -> 0x0000 (down)
+ 90 deg -> 0x4000 (left)
+ 180 deg -> 0x8000 (up)
+ 270 deg -> 0xC000 (right)
+ */
+
+ struct ff_trigger trigger;
+ struct ff_replay replay;
+
+ union {
+ struct ff_constant_effect constant;
+ struct ff_ramp_effect ramp;
+ struct ff_periodic_effect periodic;
+ struct ff_condition_effect condition[2]; /* One for each axis */
+ struct ff_rumble_effect rumble;
+ } u;
+};
+
+/*
+ * Force feedback effect types
+ */
+
+#define FF_RUMBLE 0x50
+#define FF_PERIODIC 0x51
+#define FF_CONSTANT 0x52
+#define FF_SPRING 0x53
+#define FF_FRICTION 0x54
+#define FF_DAMPER 0x55
+#define FF_INERTIA 0x56
+#define FF_RAMP 0x57
+
+/*
+ * Force feedback periodic effect types
+ */
+
+#define FF_SQUARE 0x58
+#define FF_TRIANGLE 0x59
+#define FF_SINE 0x5a
+#define FF_SAW_UP 0x5b
+#define FF_SAW_DOWN 0x5c
+#define FF_CUSTOM 0x5d
+
+/*
+ * Set ff device properties
+ */
+
+#define FF_GAIN 0x60
+#define FF_AUTOCENTER 0x61
+
+#define FF_MAX 0x7f
+
+#ifdef __KERNEL__
+
+/*
+ * In-kernel definitions.
+ */
+
+#include <linux/fs.h>
+#include <linux/timer.h>
+
+#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
+#define BIT(x) (1UL<<((x)%BITS_PER_LONG))
+#define LONG(x) ((x)/BITS_PER_LONG)
+
+#define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \
+ ((dev->keycodesize == 2) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode])))
+
+#define SET_INPUT_KEYCODE(dev, scancode, val) \
+ ({ unsigned __old; \
+ switch (dev->keycodesize) { \
+ case 1: { \
+ u8 *k = (u8 *)dev->keycode; \
+ __old = k[scancode]; \
+ k[scancode] = val; \
+ break; \
+ } \
+ case 2: { \
+ u16 *k = (u16 *)dev->keycode; \
+ __old = k[scancode]; \
+ k[scancode] = val; \
+ break; \
+ } \
+ default: { \
+ u32 *k = (u32 *)dev->keycode; \
+ __old = k[scancode]; \
+ k[scancode] = val; \
+ break; \
+ } \
+ } \
+ __old; })
+
+struct input_dev {
+
+ void *private;
+
+ char *name;
+ char *phys;
+ char *uniq;
+ struct input_id id;
+
+ unsigned long evbit[NBITS(EV_MAX)];
+ unsigned long keybit[NBITS(KEY_MAX)];
+ unsigned long relbit[NBITS(REL_MAX)];
+ unsigned long absbit[NBITS(ABS_MAX)];
+ unsigned long mscbit[NBITS(MSC_MAX)];
+ unsigned long ledbit[NBITS(LED_MAX)];
+ unsigned long sndbit[NBITS(SND_MAX)];
+ unsigned long ffbit[NBITS(FF_MAX)];
+ int ff_effects_max;
+
+ unsigned int keycodemax;
+ unsigned int keycodesize;
+ void *keycode;
+
+ unsigned int repeat_key;
+ struct timer_list timer;
+
+ struct pt_regs *regs;
+ int state;
+
+ int sync;
+
+ int abs[ABS_MAX + 1];
+ int rep[REP_MAX + 1];
+
+ unsigned long key[NBITS(KEY_MAX)];
+ unsigned long led[NBITS(LED_MAX)];
+ unsigned long snd[NBITS(SND_MAX)];
+
+ int absmax[ABS_MAX + 1];
+ int absmin[ABS_MAX + 1];
+ int absfuzz[ABS_MAX + 1];
+ int absflat[ABS_MAX + 1];
+
+ int (*open)(struct input_dev *dev);
+ void (*close)(struct input_dev *dev);
+ int (*accept)(struct input_dev *dev, struct file *file);
+ int (*flush)(struct input_dev *dev, struct file *file);
+ int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
+ int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect);
+ int (*erase_effect)(struct input_dev *dev, int effect_id);
+
+ struct input_handle *grab;
+ struct device *dev;
+
+ struct list_head h_list;
+ struct list_head node;
+};
+
+/*
+ * Structure for hotplug & device<->driver matching.
+ */
+
+#define INPUT_DEVICE_ID_MATCH_BUS 1
+#define INPUT_DEVICE_ID_MATCH_VENDOR 2
+#define INPUT_DEVICE_ID_MATCH_PRODUCT 4
+#define INPUT_DEVICE_ID_MATCH_VERSION 8
+
+#define INPUT_DEVICE_ID_MATCH_EVBIT 0x010
+#define INPUT_DEVICE_ID_MATCH_KEYBIT 0x020
+#define INPUT_DEVICE_ID_MATCH_RELBIT 0x040
+#define INPUT_DEVICE_ID_MATCH_ABSBIT 0x080
+#define INPUT_DEVICE_ID_MATCH_MSCIT 0x100
+#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x200
+#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x400
+#define INPUT_DEVICE_ID_MATCH_FFBIT 0x800
+
+#define INPUT_DEVICE_ID_MATCH_DEVICE\
+ (INPUT_DEVICE_ID_MATCH_BUS | INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT)
+#define INPUT_DEVICE_ID_MATCH_DEVICE_AND_VERSION\
+ (INPUT_DEVICE_ID_MATCH_DEVICE | INPUT_DEVICE_ID_MATCH_VERSION)
+
+struct input_device_id {
+
+ unsigned long flags;
+
+ struct input_id id;
+
+ unsigned long evbit[NBITS(EV_MAX)];
+ unsigned long keybit[NBITS(KEY_MAX)];
+ unsigned long relbit[NBITS(REL_MAX)];
+ unsigned long absbit[NBITS(ABS_MAX)];
+ unsigned long mscbit[NBITS(MSC_MAX)];
+ unsigned long ledbit[NBITS(LED_MAX)];
+ unsigned long sndbit[NBITS(SND_MAX)];
+ unsigned long ffbit[NBITS(FF_MAX)];
+
+ unsigned long driver_info;
+};
+
+struct input_handle;
+
+struct input_handler {
+
+ void *private;
+
+ void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
+ struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id);
+ void (*disconnect)(struct input_handle *handle);
+
+ struct file_operations *fops;
+ int minor;
+ char *name;
+
+ struct input_device_id *id_table;
+ struct input_device_id *blacklist;
+
+ struct list_head h_list;
+ struct list_head node;
+};
+
+struct input_handle {
+
+ void *private;
+
+ int open;
+ char *name;
+
+ struct input_dev *dev;
+ struct input_handler *handler;
+
+ struct list_head d_node;
+ struct list_head h_node;
+};
+
+#define to_dev(n) container_of(n,struct input_dev,node)
+#define to_handler(n) container_of(n,struct input_handler,node);
+#define to_handle(n) container_of(n,struct input_handle,d_node)
+#define to_handle_h(n) container_of(n,struct input_handle,h_node)
+
+static inline void init_input_dev(struct input_dev *dev)
+{
+ INIT_LIST_HEAD(&dev->h_list);
+ INIT_LIST_HEAD(&dev->node);
+}
+
+void input_register_device(struct input_dev *);
+void input_unregister_device(struct input_dev *);
+
+void input_register_handler(struct input_handler *);
+void input_unregister_handler(struct input_handler *);
+
+int input_grab_device(struct input_handle *);
+void input_release_device(struct input_handle *);
+
+int input_open_device(struct input_handle *);
+void input_close_device(struct input_handle *);
+
+int input_accept_process(struct input_handle *handle, struct file *file);
+int input_flush_device(struct input_handle* handle, struct file* file);
+
+void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
+
+static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
+{
+ input_event(dev, EV_KEY, code, !!value);
+}
+
+static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
+{
+ input_event(dev, EV_REL, code, value);
+}
+
+static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
+{
+ input_event(dev, EV_ABS, code, value);
+}
+
+static inline void input_report_ff(struct input_dev *dev, unsigned int code, int value)
+{
+ input_event(dev, EV_FF, code, value);
+}
+
+static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value)
+{
+ input_event(dev, EV_FF_STATUS, code, value);
+}
+
+static inline void input_regs(struct input_dev *dev, struct pt_regs *regs)
+{
+ dev->regs = regs;
+}
+
+static inline void input_sync(struct input_dev *dev)
+{
+ input_event(dev, EV_SYN, SYN_REPORT, 0);
+ dev->regs = NULL;
+}
+
+static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
+{
+ dev->absmin[axis] = min;
+ dev->absmax[axis] = max;
+ dev->absfuzz[axis] = fuzz;
+ dev->absflat[axis] = flat;
+
+ dev->absbit[LONG(axis)] |= BIT(axis);
+}
+
+extern struct class_simple *input_class;
+
+#endif
+#endif
diff --git a/make-arrays-from-input.h.pl b/make-arrays-from-input.h.pl
new file mode 100755
index 0000000..2b261e7
--- /dev/null
+++ b/make-arrays-from-input.h.pl
@@ -0,0 +1,321 @@
+#!/usr/bin/perl -w
+
+use Switch;
+
+#========================================================================
+# FUNCTIONS
+#========================================================================
+
+#------------------------------------------------------------------------
+# parse out the types and codes from a line from the header
+# usage: @dataArray initArrayWithGenericNames( $arrayName, $arrayMax );
+sub initArrayWithGenericNames
+{
+ my $arrayName = shift;
+ my $arrayMax = shift;
+ my @returnArray;
+
+ my $displayName = lc( $arrayName );
+# print "$displayName $arrayMax ";
+ for( $i=0; $i<$arrayMax; ++$i )
+ {
+ $returnArray[$i] = "${displayName}_$i";
+ }
+
+ return @returnArray;
+}
+
+#------------------------------------------------------------------------
+# parse out the types and codes from a line from the header
+# usage: @dataArray getDataFromHeaderLine($lineFromHeader);
+sub getDataFromHeaderLine
+{
+ $_ = shift;
+
+ my @returnArray;
+
+ if ( m/#define ([A-Z0-9_]*)\s+(0x)?([0-9a-f]+)/)
+ {
+ if ($2) { $index = hex($3); } else { $index = $3; }
+ if ($index >= 0)
+ {
+ $returnArray[0] = $index;
+ $returnArray[1] = lc("$1");
+ return @returnArray;
+ }
+# print "$1 \t\t\t $index $#returnArray\n ";
+# if ($index == 0) { print("index: $index 3: $3 2: $2 1: $1 value: $returnArray[1]\n"); }
+ }
+}
+
+#------------------------------------------------------------------------
+#
+# this is under construction to make the MAX switch structure cleaner
+# donno if it works yet.
+sub createNewArray
+{
+ my $myTypeName = shift;
+ my $myTypeMaxName = shift;
+
+ my $myIndex;
+ my $myValue;
+ my @myNewArray;
+
+ ($myIndex, $myValue) = getDataFromHeaderLine($myTypeMaxName);
+ @myNewArray = initArrayWithGenericNames( $myTypeName, $myIndex + 1 );
+
+ return @myNewArray;
+}
+
+
+#------------------------------------------------------------------------
+# declare each array in the header
+#
+sub printCArrayDeclarations
+{
+ my @arrayToPrint = @_;
+
+ print(HEADER "char *${arrayToPrint[0]}[$#arrayToPrint];\n");
+}
+
+#------------------------------------------------------------------------
+# print an array out in C format
+#
+sub printCArray
+{
+ my @arrayToPrint = @_;
+
+# print("$arrayToPrint[0] $#arrayToPrint \n");
+
+ print(ARRAYS "int ${arrayToPrint[0]}_total = $#arrayToPrint; /* # of elements in array */\n");
+ print(ARRAYS "char *${arrayToPrint[0]}[$#arrayToPrint] = {");
+
+ for(my $i = 1; $i < $#arrayToPrint; $i++)
+ {
+ # format nicely in sets of 6
+ if ( ($i+4)%6 == 5 ) { print(ARRAYS "\n "); }
+ # only print if there is data
+ if ($arrayToPrint[$i]) { print(ARRAYS "\"$arrayToPrint[$i]\","); }
+# else { print(ARRAYS "${arrayType}_$i,"); }
+ }
+
+ print(ARRAYS "\"$arrayToPrint[$#arrayToPrint]\"\n };\n\n\n");
+}
+
+#------------------------------------------------------------------------
+# print an array out in a comment table in Pd
+#
+sub printPdFile
+{
+ my @arrayToPrint = @_;
+ my $x;
+ my $y;
+ my $lineNum = 1;
+
+ my $PDFILENAME = "doc/$arrayToPrint[0]-list.pd";
+ open(PDFILE, ">$PDFILENAME");
+
+ print(PDFILE "#N canvas 282 80 210 570 10;\n");
+ if ($arrayToPrint[0] eq "ev") { print(PDFILE "#X text 5 5 Event Types;\n"); }
+ else { print(PDFILE "#X text 5 5 Codes for Type: $arrayToPrint[0];\n"); }
+ print(PDFILE "#X text 5 20 ----------------------------;\n");
+
+ for($i = 1; $i <= $#arrayToPrint; $i++)
+ {
+ # if the array element's data is null, print NULL
+ if ($arrayToPrint[$i])
+ {
+ $x = 5;
+ $y = $lineNum * 20 + 20;
+ print(PDFILE "#X text $x $y $arrayToPrint[$i];\n");
+ $lineNum++;
+ }
+ }
+
+ close(PDFILE);
+}
+
+#------------------------------------------------------------------------
+#
+#
+sub printArray
+{
+ printPdFile(@_);
+ printCArray(@_);
+ printCArrayDeclarations(@_);
+}
+
+#========================================================================
+# MAIN
+#========================================================================
+
+# source file
+$SOURCEFILENAME = "linux/input.h";
+open(INPUT_H, "<$SOURCEFILENAME");
+
+# output files
+$HEADERFILENAME = "input_arrays.h";
+open(HEADER, ">$HEADERFILENAME");
+$ARRAYSFILENAME = "input_arrays.c";
+open(ARRAYS, ">$ARRAYSFILENAME");
+
+
+#----------------------------------------
+# create the arrays from INPUT_H
+# find array MAX for each one
+while (<INPUT_H>)
+{
+ if (m/\#define (FF_STATUS|[A-Z_]+?)_MAX/)
+ {
+ switch( $1 ) {
+ # types
+ case "EV" { ($index, $value) = getDataFromHeaderLine($_);
+ @EV = initArrayWithGenericNames( "EV", $index + 1 ); }
+ # codes
+ case "SYN" { ($index, $value) = getDataFromHeaderLine($_);
+ @SYN = initArrayWithGenericNames( "SYN", $index + 1 ); }
+ case "KEY" { ($index, $value) = getDataFromHeaderLine($_);
+ @KEY = initArrayWithGenericNames( "KEY", $index + 1 ); }
+# BTN codes are actually part of the KEY type, so this array is unused
+# case "BTN" { ($index, $value) = getDataFromHeaderLine($_);
+# @BTN = initArrayWithGenericNames( "KEY", $index + 1 ); }
+ case "REL" { ($index, $value) = getDataFromHeaderLine($_);
+ @REL = initArrayWithGenericNames( "REL", $index + 1 ); }
+ case "ABS" { ($index, $value) = getDataFromHeaderLine($_);
+ @ABS = initArrayWithGenericNames( "ABS", $index + 1 ); }
+ case "MSC" { ($index, $value) = getDataFromHeaderLine($_);
+ @MSC = initArrayWithGenericNames( "MSC", $index + 1 ); }
+ case "LED" { ($index, $value) = getDataFromHeaderLine($_);
+ @LED = initArrayWithGenericNames( "LED", $index + 1 ); }
+ case "SND" { ($index, $value) = getDataFromHeaderLine($_);
+ @SND = initArrayWithGenericNames( "SND", $index + 1 ); }
+ case "REP" { ($index, $value) = getDataFromHeaderLine($_);
+ @REP = initArrayWithGenericNames( "REP", $index + 1 ); }
+ case "FF" { ($index, $value) = getDataFromHeaderLine($_);
+ @FF = initArrayWithGenericNames( "FF", $index + 1 ); }
+ # there doesn't seem to be any PWR events yet...
+# case "PWR" { ($index, $value) = getDataFromHeaderLine($_);
+# @PWR = initArrayWithGenericNames( "PWR", $index + 1 ); }
+ case "FF_STATUS" { ($index, $value) = getDataFromHeaderLine($_);
+ @FF_STATUS = initArrayWithGenericNames( "FF_STATUS", $index + 1 ); }
+ }
+ }
+}
+
+# there is no SYN_MAX defined in input.h, so we set it here:
+@SYN = initArrayWithGenericNames( "SYN", 512 );
+
+
+seek( INPUT_H, 0, 0 );
+while (<INPUT_H>)
+{
+# get data from input.h
+ if (m/\#define (FF_STATUS|[A-Z_]*?)_/)
+ {
+# filter EV_VERSION and *_MAX
+ m/\#define\s+(EV_VERSION|[A-Z_]+_MAX)\s+/;
+# print "$1 \n";
+ switch ($1)
+ {
+ # types
+ case "EV" { ($index, $value) = getDataFromHeaderLine($_); $EV[$index] = $value; }
+ # codes
+ case "SYN" { ($index, $value) = getDataFromHeaderLine($_); $SYN[$index] = $value; }
+ case "KEY" { ($index, $value) = getDataFromHeaderLine($_); $KEY[$index] = $value; }
+# BTN codes are actually part of the KEY type
+ case "BTN" { ($index, $value) = getDataFromHeaderLine($_); $KEY[$index] = $value; }
+ case "REL" { ($index, $value) = getDataFromHeaderLine($_); $REL[$index] = $value; }
+ case "ABS" { ($index, $value) = getDataFromHeaderLine($_); $ABS[$index] = $value; }
+ case "MSC" { ($index, $value) = getDataFromHeaderLine($_); $MSC[$index] = $value; }
+ case "LED" { ($index, $value) = getDataFromHeaderLine($_); $LED[$index] = $value; }
+ case "SND" { ($index, $value) = getDataFromHeaderLine($_); $SND[$index] = $value; }
+ case "REP" { ($index, $value) = getDataFromHeaderLine($_); $REP[$index] = $value; }
+ case "FF" { ($index, $value) = getDataFromHeaderLine($_); $FF[$index] = $value; }
+# there doesn't seem to be any PWR events yet...
+# case "PWR" { ($index, $value) = getDataFromHeaderLine($_); $PWR[$index] = $value; }
+ case "FF_STATUS" { ($index, $value) = getDataFromHeaderLine($_); $FF_STATUS[$index] = $value; }
+# else { print " none $_"; }
+ }
+ }
+}
+
+#----------------------------------------
+# create the files from the arrays
+
+# print file headers
+print(ARRAYS "#include \"hidio.h\"\n\n");
+
+print(HEADER "\#ifndef _INPUT_ARRAYS_H\n");
+print(HEADER "\#define _INPUT_ARRAYS_H\n\n\n");
+
+# strip the ev_ from the type names
+for ($i=0; $i <= $#EV; ++$i) {
+ $_ = $EV[$i];
+ s/ev_([a-z_])/\1/;
+ $EVtemp[$i] = $_;
+}
+
+# generate a C array for each array and stick them all in the same file
+printArray("ev",@EVtemp);
+printArray("ev_syn",@SYN);
+printArray("ev_key",@KEY);
+printArray("ev_rel",@REL);
+printArray("ev_abs",@ABS);
+printArray("ev_msc",@MSC);
+printArray("ev_led",@LED);
+printArray("ev_snd",@SND);
+printArray("ev_rep",@REP);
+printArray("ev_ff",@FF);
+# there doesn't seem to be any PWR events yet...
+#printArray("pwr",@PWR);
+print(ARRAYS "char *ev_pwr[1] = { NULL };\n\n");
+print(HEADER "char *ev_pwr[1];\n");
+#
+printArray("ev_ff_status",@FF_STATUS);
+
+#------------------------------------------------------------------------------#
+# print fake event type arrays
+for( my $i = 0; $i <= $#EV; $i++ )
+{
+ # format nicely in sets of 6
+ if ( ($i+4)%6 == 5 ) { print(ARRAYS "\n "); }
+
+ $_ = $EV[$i];
+ if ( m/(ev_[0-9]+)/ )
+ {
+ $temp[0] = $1;
+ for( $j=1; $j<=16; ++$j )
+ {
+ $temp[$j] = "ev_${i}_${j}";
+ }
+ printCArray(@temp);
+ printCArrayDeclarations(@temp);
+ }
+}
+
+#------------------------------------------------------------------------------#
+# print array of arrays
+print(HEADER "char **event_names[",$#EV+1,"];\n\n");
+print(ARRAYS "char **event_names[",$#EV+1,"] = {");
+for( $i = 0; $i < $#EV; $i++ )
+{
+ # format nicely in sets of 6
+ if ( ($i+4)%6 == 5 ) { print(ARRAYS "\n "); }
+
+ $_ = $EV[$i];
+ m/(ev_[0-9a-z_]+)/;
+ print(ARRAYS "$1,");
+}
+$_ = $EV[$#EV];
+m/(ev_[0-9a-z_]+)/;
+print(ARRAYS "$1\n };\n");
+
+# print file footers
+print(HEADER "\n\n\#endif /* #ifndef _INPUT_ARRAYS_H */\n");
+
+close(ARRAYS);
+close(HEADER);
+close(INPUT_H);
+
+
+