diff options
-rw-r--r-- | COPYING | 340 | ||||
-rw-r--r-- | Makefile | 25 | ||||
-rw-r--r-- | README | 13 | ||||
-rw-r--r-- | TODO | 275 | ||||
-rw-r--r-- | hidio-help.pd | 589 | ||||
-rw-r--r-- | hidio.c | 485 | ||||
-rw-r--r-- | hidio.h | 153 | ||||
-rw-r--r-- | hidio_darwin.c | 1468 | ||||
-rw-r--r-- | hidio_linux.c | 648 | ||||
-rw-r--r-- | hidio_windows.c | 337 | ||||
-rw-r--r-- | input_arrays.c | 463 | ||||
-rw-r--r-- | input_arrays.h | 42 | ||||
-rw-r--r-- | linux/input.h | 1016 | ||||
-rwxr-xr-x | make-arrays-from-input.h.pl | 321 |
14 files changed, 6175 insertions, 0 deletions
@@ -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 @@ -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> + + + @@ -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; @@ -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!!!!!!"); +} + @@ -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); + + + |