From 3dccff5811e248b112e7b014be5604667d86e954 Mon Sep 17 00:00:00 2001 From: asdfasdf Date: Sat, 2 May 2020 13:05:26 -0700 Subject: [PATCH] Upload ready --- COPYING | 339 ++++++++++++++++++ README.md | 19 + evabs.c | 1018 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1376 insertions(+) create mode 100644 COPYING create mode 100644 README.md create mode 100644 evabs.c diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser 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 COPYING, 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 + + 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. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) year 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. + + , 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 Lesser General +Public License instead of this License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..5d4b3f4 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# evabs +evabs is modified from evtest. It warps Xorg pointer of the default screen by +multiplying the fraction of the touchpad coordinate over maximum touchpad +range of axises by the resolution of the screen. + +## DEPENDENCIES: +- Xorg +- Xlib +- libXtst + +## BUILD DEPENDENCY: +- GCC + +## Compile with: + $> gcc -o evabs -lX11 -lXtst -lm evabs.c + +This software is licensed under GPL2 or any later version. + +Copyright (c) 2019 Benny diff --git a/evabs.c b/evabs.c new file mode 100644 index 0000000..4e31204 --- /dev/null +++ b/evabs.c @@ -0,0 +1,1018 @@ +/* + * Copyright (c) 1999-2000 Vojtech Pavlik + * Copyright (c) 2009-2011 Red Hat, Inc + * Modifications Copyright (c) 2019 Benny + */ + +/** + * @file + * Event based absolute Xorg movement + * + * evabs prints the capabilities on the kernel devices in /dev/input/eventX + * and move the pointer in Xorg from absolute coordinates events from devices + * + * Compile with + * gcc -o evabs -lX11 -lXtst -lm evabs.c + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 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 + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#define _GNU_SOURCE /* for asprintf */ +#include +#include +#include + +#if HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define BITS_PER_LONG (sizeof(long) * 8) +#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) +#define OFF(x) ((x)%BITS_PER_LONG) +#define BIT(x) (1UL<> OFF(bit)) & 1) + +#define DEV_INPUT_EVENT "/dev/input" +#define EVENT_DEV_NAME "event" + +#ifndef EV_SYN +#define EV_SYN 0 +#endif +#ifndef SYN_MT_REPORT +#define SYN_MT_REPORT 2 +#endif + +#define NAME_ELEMENT(element) [element] = #element + +enum evtest_mode { + MODE_CAPTURE, + MODE_VERSION, +}; + +static const struct query_mode { + const char *name; + int event_type; + int max; + int rq; +} query_modes[] = { + { "EV_KEY", EV_KEY, KEY_MAX, EVIOCGKEY(KEY_MAX) }, + { "EV_LED", EV_LED, LED_MAX, EVIOCGLED(LED_MAX) }, + { "EV_SND", EV_SND, SND_MAX, EVIOCGSND(SND_MAX) }, + { "EV_SW", EV_SW, SW_MAX, EVIOCGSW(SW_MAX) }, +}; + +/** + * Look up an entry in the query_modes table by its textual name. + * + * @param mode The name of the entry to be found. + * + * @return The requested query_mode, or NULL if it could not be found. + */ +static const struct query_mode *find_query_mode_by_name(const char *name) +{ + int i; + for (i = 0; i < sizeof(query_modes) / sizeof(*query_modes); i++) { + const struct query_mode *mode = &query_modes[i]; + if (strcmp(mode->name, name) == 0) + return mode; + } + return NULL; +} + +/** + * Look up an entry in the query_modes table by value. + * + * @param event_type The value of the entry to be found. + * + * @return The requested query_mode, or NULL if it could not be found. + */ +static const struct query_mode *find_query_mode_by_value(int event_type) +{ + int i; + for (i = 0; i < sizeof(query_modes) / sizeof(*query_modes); i++) { + const struct query_mode *mode = &query_modes[i]; + if (mode->event_type == event_type) + return mode; + } + return NULL; +} + +/** + * Find a query_mode based on a string identifier. The string can either + * be a numerical value (e.g. "5") or the name of the event type in question + * (e.g. "EV_SW"). + * + * @param query_mode The mode to search for + * + * @return The requested code's numerical value, or negative on error. + */ +static const struct query_mode *find_query_mode(const char *query_mode) +{ + if (isdigit(query_mode[0])) { + unsigned long val; + errno = 0; + val = strtoul(query_mode, NULL, 0); + if (errno) + return NULL; + return find_query_mode_by_value(val); + } else { + return find_query_mode_by_name(query_mode); + } +} + +static const char * const events[EV_MAX + 1] = { + [0 ... EV_MAX] = NULL, + NAME_ELEMENT(EV_SYN), NAME_ELEMENT(EV_KEY), + NAME_ELEMENT(EV_REL), NAME_ELEMENT(EV_ABS), + NAME_ELEMENT(EV_MSC), NAME_ELEMENT(EV_LED), + NAME_ELEMENT(EV_SND), NAME_ELEMENT(EV_REP), + NAME_ELEMENT(EV_FF), NAME_ELEMENT(EV_PWR), + NAME_ELEMENT(EV_FF_STATUS), NAME_ELEMENT(EV_SW), +}; + +#ifdef INPUT_PROP_SEMI_MT +static const char * const props[INPUT_PROP_MAX + 1] = { + [0 ... INPUT_PROP_MAX] = NULL, + NAME_ELEMENT(INPUT_PROP_POINTER), + NAME_ELEMENT(INPUT_PROP_DIRECT), + NAME_ELEMENT(INPUT_PROP_BUTTONPAD), + NAME_ELEMENT(INPUT_PROP_SEMI_MT), +}; +#endif + +static const char * const keys[KEY_MAX + 1] = { + [0 ... KEY_MAX] = NULL, + NAME_ELEMENT(KEY_RESERVED), NAME_ELEMENT(KEY_ESC), + NAME_ELEMENT(KEY_1), NAME_ELEMENT(KEY_2), + NAME_ELEMENT(KEY_3), NAME_ELEMENT(KEY_4), + NAME_ELEMENT(KEY_5), NAME_ELEMENT(KEY_6), + NAME_ELEMENT(KEY_7), NAME_ELEMENT(KEY_8), + NAME_ELEMENT(KEY_9), NAME_ELEMENT(KEY_0), + NAME_ELEMENT(KEY_MINUS), NAME_ELEMENT(KEY_EQUAL), + NAME_ELEMENT(KEY_BACKSPACE), NAME_ELEMENT(KEY_TAB), + NAME_ELEMENT(KEY_Q), NAME_ELEMENT(KEY_W), + NAME_ELEMENT(KEY_E), NAME_ELEMENT(KEY_R), + NAME_ELEMENT(KEY_T), NAME_ELEMENT(KEY_Y), + NAME_ELEMENT(KEY_U), NAME_ELEMENT(KEY_I), + NAME_ELEMENT(KEY_O), NAME_ELEMENT(KEY_P), + NAME_ELEMENT(KEY_LEFTBRACE), NAME_ELEMENT(KEY_RIGHTBRACE), + NAME_ELEMENT(KEY_ENTER), NAME_ELEMENT(KEY_LEFTCTRL), + NAME_ELEMENT(KEY_A), NAME_ELEMENT(KEY_S), + NAME_ELEMENT(KEY_D), NAME_ELEMENT(KEY_F), + NAME_ELEMENT(KEY_G), NAME_ELEMENT(KEY_H), + NAME_ELEMENT(KEY_J), NAME_ELEMENT(KEY_K), + NAME_ELEMENT(KEY_L), NAME_ELEMENT(KEY_SEMICOLON), + NAME_ELEMENT(KEY_APOSTROPHE), NAME_ELEMENT(KEY_GRAVE), + NAME_ELEMENT(KEY_LEFTSHIFT), NAME_ELEMENT(KEY_BACKSLASH), + NAME_ELEMENT(KEY_Z), NAME_ELEMENT(KEY_X), + NAME_ELEMENT(KEY_C), NAME_ELEMENT(KEY_V), + NAME_ELEMENT(KEY_B), NAME_ELEMENT(KEY_N), + NAME_ELEMENT(KEY_M), NAME_ELEMENT(KEY_COMMA), + NAME_ELEMENT(KEY_DOT), NAME_ELEMENT(KEY_SLASH), + NAME_ELEMENT(KEY_RIGHTSHIFT), NAME_ELEMENT(KEY_KPASTERISK), + NAME_ELEMENT(KEY_LEFTALT), NAME_ELEMENT(KEY_SPACE), + NAME_ELEMENT(KEY_CAPSLOCK), NAME_ELEMENT(KEY_F1), + NAME_ELEMENT(KEY_F2), NAME_ELEMENT(KEY_F3), + NAME_ELEMENT(KEY_F4), NAME_ELEMENT(KEY_F5), + NAME_ELEMENT(KEY_F6), NAME_ELEMENT(KEY_F7), + NAME_ELEMENT(KEY_F8), NAME_ELEMENT(KEY_F9), + NAME_ELEMENT(KEY_F10), NAME_ELEMENT(KEY_NUMLOCK), + NAME_ELEMENT(KEY_SCROLLLOCK), NAME_ELEMENT(KEY_KP7), + NAME_ELEMENT(KEY_KP8), NAME_ELEMENT(KEY_KP9), + NAME_ELEMENT(KEY_KPMINUS), NAME_ELEMENT(KEY_KP4), + NAME_ELEMENT(KEY_KP5), NAME_ELEMENT(KEY_KP6), + NAME_ELEMENT(KEY_KPPLUS), NAME_ELEMENT(KEY_KP1), + NAME_ELEMENT(KEY_KP2), NAME_ELEMENT(KEY_KP3), + NAME_ELEMENT(KEY_KP0), NAME_ELEMENT(KEY_KPDOT), + NAME_ELEMENT(KEY_ZENKAKUHANKAKU), NAME_ELEMENT(KEY_102ND), + NAME_ELEMENT(KEY_F11), NAME_ELEMENT(KEY_F12), + NAME_ELEMENT(KEY_RO), NAME_ELEMENT(KEY_KATAKANA), + NAME_ELEMENT(KEY_HIRAGANA), NAME_ELEMENT(KEY_HENKAN), + NAME_ELEMENT(KEY_KATAKANAHIRAGANA), NAME_ELEMENT(KEY_MUHENKAN), + NAME_ELEMENT(KEY_KPJPCOMMA), NAME_ELEMENT(KEY_KPENTER), + NAME_ELEMENT(KEY_RIGHTCTRL), NAME_ELEMENT(KEY_KPSLASH), + NAME_ELEMENT(KEY_SYSRQ), NAME_ELEMENT(KEY_RIGHTALT), + NAME_ELEMENT(KEY_LINEFEED), NAME_ELEMENT(KEY_HOME), + NAME_ELEMENT(KEY_UP), NAME_ELEMENT(KEY_PAGEUP), + NAME_ELEMENT(KEY_LEFT), NAME_ELEMENT(KEY_RIGHT), + NAME_ELEMENT(KEY_END), NAME_ELEMENT(KEY_DOWN), + NAME_ELEMENT(KEY_PAGEDOWN), NAME_ELEMENT(KEY_INSERT), + NAME_ELEMENT(KEY_DELETE), NAME_ELEMENT(KEY_MACRO), + NAME_ELEMENT(KEY_MUTE), NAME_ELEMENT(KEY_VOLUMEDOWN), + NAME_ELEMENT(KEY_VOLUMEUP), NAME_ELEMENT(KEY_POWER), + NAME_ELEMENT(KEY_KPEQUAL), NAME_ELEMENT(KEY_KPPLUSMINUS), + NAME_ELEMENT(KEY_PAUSE), NAME_ELEMENT(KEY_KPCOMMA), + NAME_ELEMENT(KEY_HANGUEL), NAME_ELEMENT(KEY_HANJA), + NAME_ELEMENT(KEY_YEN), NAME_ELEMENT(KEY_LEFTMETA), + NAME_ELEMENT(KEY_RIGHTMETA), NAME_ELEMENT(KEY_COMPOSE), + NAME_ELEMENT(KEY_STOP), NAME_ELEMENT(KEY_AGAIN), + NAME_ELEMENT(KEY_PROPS), NAME_ELEMENT(KEY_UNDO), + NAME_ELEMENT(KEY_FRONT), NAME_ELEMENT(KEY_COPY), + NAME_ELEMENT(KEY_OPEN), NAME_ELEMENT(KEY_PASTE), + NAME_ELEMENT(KEY_FIND), NAME_ELEMENT(KEY_CUT), + NAME_ELEMENT(KEY_HELP), NAME_ELEMENT(KEY_MENU), + NAME_ELEMENT(KEY_CALC), NAME_ELEMENT(KEY_SETUP), + NAME_ELEMENT(KEY_SLEEP), NAME_ELEMENT(KEY_WAKEUP), + NAME_ELEMENT(KEY_FILE), NAME_ELEMENT(KEY_SENDFILE), + NAME_ELEMENT(KEY_DELETEFILE), NAME_ELEMENT(KEY_XFER), + NAME_ELEMENT(KEY_PROG1), NAME_ELEMENT(KEY_PROG2), + NAME_ELEMENT(KEY_WWW), NAME_ELEMENT(KEY_MSDOS), + NAME_ELEMENT(KEY_COFFEE), NAME_ELEMENT(KEY_DIRECTION), + NAME_ELEMENT(KEY_CYCLEWINDOWS), NAME_ELEMENT(KEY_MAIL), + NAME_ELEMENT(KEY_BOOKMARKS), NAME_ELEMENT(KEY_COMPUTER), + NAME_ELEMENT(KEY_BACK), NAME_ELEMENT(KEY_FORWARD), + NAME_ELEMENT(KEY_CLOSECD), NAME_ELEMENT(KEY_EJECTCD), + NAME_ELEMENT(KEY_EJECTCLOSECD), NAME_ELEMENT(KEY_NEXTSONG), + NAME_ELEMENT(KEY_PLAYPAUSE), NAME_ELEMENT(KEY_PREVIOUSSONG), + NAME_ELEMENT(KEY_STOPCD), NAME_ELEMENT(KEY_RECORD), + NAME_ELEMENT(KEY_REWIND), NAME_ELEMENT(KEY_PHONE), + NAME_ELEMENT(KEY_ISO), NAME_ELEMENT(KEY_CONFIG), + NAME_ELEMENT(KEY_HOMEPAGE), NAME_ELEMENT(KEY_REFRESH), + NAME_ELEMENT(KEY_EXIT), NAME_ELEMENT(KEY_MOVE), + NAME_ELEMENT(KEY_EDIT), NAME_ELEMENT(KEY_SCROLLUP), + NAME_ELEMENT(KEY_SCROLLDOWN), NAME_ELEMENT(KEY_KPLEFTPAREN), + NAME_ELEMENT(KEY_KPRIGHTPAREN), NAME_ELEMENT(KEY_F13), + NAME_ELEMENT(KEY_F14), NAME_ELEMENT(KEY_F15), + NAME_ELEMENT(KEY_F16), NAME_ELEMENT(KEY_F17), + NAME_ELEMENT(KEY_F18), NAME_ELEMENT(KEY_F19), + NAME_ELEMENT(KEY_F20), NAME_ELEMENT(KEY_F21), + NAME_ELEMENT(KEY_F22), NAME_ELEMENT(KEY_F23), + NAME_ELEMENT(KEY_F24), NAME_ELEMENT(KEY_PLAYCD), + NAME_ELEMENT(KEY_PAUSECD), NAME_ELEMENT(KEY_PROG3), + NAME_ELEMENT(KEY_PROG4), NAME_ELEMENT(KEY_SUSPEND), + NAME_ELEMENT(KEY_CLOSE), NAME_ELEMENT(KEY_PLAY), + NAME_ELEMENT(KEY_FASTFORWARD), NAME_ELEMENT(KEY_BASSBOOST), + NAME_ELEMENT(KEY_PRINT), NAME_ELEMENT(KEY_HP), + NAME_ELEMENT(KEY_CAMERA), NAME_ELEMENT(KEY_SOUND), + NAME_ELEMENT(KEY_QUESTION), NAME_ELEMENT(KEY_EMAIL), + NAME_ELEMENT(KEY_CHAT), NAME_ELEMENT(KEY_SEARCH), + NAME_ELEMENT(KEY_CONNECT), NAME_ELEMENT(KEY_FINANCE), + NAME_ELEMENT(KEY_SPORT), NAME_ELEMENT(KEY_SHOP), + NAME_ELEMENT(KEY_ALTERASE), NAME_ELEMENT(KEY_CANCEL), + NAME_ELEMENT(KEY_BRIGHTNESSDOWN), NAME_ELEMENT(KEY_BRIGHTNESSUP), + NAME_ELEMENT(KEY_MEDIA), NAME_ELEMENT(KEY_UNKNOWN), + NAME_ELEMENT(KEY_OK), + NAME_ELEMENT(KEY_SELECT), NAME_ELEMENT(KEY_GOTO), + NAME_ELEMENT(KEY_CLEAR), NAME_ELEMENT(KEY_POWER2), + NAME_ELEMENT(KEY_OPTION), NAME_ELEMENT(KEY_INFO), + NAME_ELEMENT(KEY_TIME), NAME_ELEMENT(KEY_VENDOR), + NAME_ELEMENT(KEY_ARCHIVE), NAME_ELEMENT(KEY_PROGRAM), + NAME_ELEMENT(KEY_CHANNEL), NAME_ELEMENT(KEY_FAVORITES), + NAME_ELEMENT(KEY_EPG), NAME_ELEMENT(KEY_PVR), + NAME_ELEMENT(KEY_MHP), NAME_ELEMENT(KEY_LANGUAGE), + NAME_ELEMENT(KEY_TITLE), NAME_ELEMENT(KEY_SUBTITLE), + NAME_ELEMENT(KEY_ANGLE), NAME_ELEMENT(KEY_ZOOM), + NAME_ELEMENT(KEY_MODE), NAME_ELEMENT(KEY_KEYBOARD), + NAME_ELEMENT(KEY_SCREEN), NAME_ELEMENT(KEY_PC), + NAME_ELEMENT(KEY_TV), NAME_ELEMENT(KEY_TV2), + NAME_ELEMENT(KEY_VCR), NAME_ELEMENT(KEY_VCR2), + NAME_ELEMENT(KEY_SAT), NAME_ELEMENT(KEY_SAT2), + NAME_ELEMENT(KEY_CD), NAME_ELEMENT(KEY_TAPE), + NAME_ELEMENT(KEY_RADIO), NAME_ELEMENT(KEY_TUNER), + NAME_ELEMENT(KEY_PLAYER), NAME_ELEMENT(KEY_TEXT), + NAME_ELEMENT(KEY_DVD), NAME_ELEMENT(KEY_AUX), + NAME_ELEMENT(KEY_MP3), NAME_ELEMENT(KEY_AUDIO), + NAME_ELEMENT(KEY_VIDEO), NAME_ELEMENT(KEY_DIRECTORY), + NAME_ELEMENT(KEY_LIST), NAME_ELEMENT(KEY_MEMO), + NAME_ELEMENT(KEY_CALENDAR), NAME_ELEMENT(KEY_RED), + NAME_ELEMENT(KEY_GREEN), NAME_ELEMENT(KEY_YELLOW), + NAME_ELEMENT(KEY_BLUE), NAME_ELEMENT(KEY_CHANNELUP), + NAME_ELEMENT(KEY_CHANNELDOWN), NAME_ELEMENT(KEY_FIRST), + NAME_ELEMENT(KEY_LAST), NAME_ELEMENT(KEY_AB), + NAME_ELEMENT(KEY_NEXT), NAME_ELEMENT(KEY_RESTART), + NAME_ELEMENT(KEY_SLOW), NAME_ELEMENT(KEY_SHUFFLE), + NAME_ELEMENT(KEY_BREAK), NAME_ELEMENT(KEY_PREVIOUS), + NAME_ELEMENT(KEY_DIGITS), NAME_ELEMENT(KEY_TEEN), + NAME_ELEMENT(KEY_TWEN), NAME_ELEMENT(KEY_DEL_EOL), + NAME_ELEMENT(KEY_DEL_EOS), NAME_ELEMENT(KEY_INS_LINE), + NAME_ELEMENT(KEY_DEL_LINE), + NAME_ELEMENT(KEY_VIDEOPHONE), NAME_ELEMENT(KEY_GAMES), + NAME_ELEMENT(KEY_ZOOMIN), NAME_ELEMENT(KEY_ZOOMOUT), + NAME_ELEMENT(KEY_ZOOMRESET), NAME_ELEMENT(KEY_WORDPROCESSOR), + NAME_ELEMENT(KEY_EDITOR), NAME_ELEMENT(KEY_SPREADSHEET), + NAME_ELEMENT(KEY_GRAPHICSEDITOR), NAME_ELEMENT(KEY_PRESENTATION), + NAME_ELEMENT(KEY_DATABASE), NAME_ELEMENT(KEY_NEWS), + NAME_ELEMENT(KEY_VOICEMAIL), NAME_ELEMENT(KEY_ADDRESSBOOK), + NAME_ELEMENT(KEY_MESSENGER), NAME_ELEMENT(KEY_DISPLAYTOGGLE), + NAME_ELEMENT(KEY_SPELLCHECK), NAME_ELEMENT(KEY_LOGOFF), + NAME_ELEMENT(KEY_DOLLAR), NAME_ELEMENT(KEY_EURO), + NAME_ELEMENT(KEY_FRAMEBACK), NAME_ELEMENT(KEY_FRAMEFORWARD), + NAME_ELEMENT(KEY_CONTEXT_MENU), NAME_ELEMENT(KEY_MEDIA_REPEAT), + NAME_ELEMENT(KEY_DEL_EOL), NAME_ELEMENT(KEY_DEL_EOS), + NAME_ELEMENT(KEY_INS_LINE), NAME_ELEMENT(KEY_DEL_LINE), + NAME_ELEMENT(KEY_FN), NAME_ELEMENT(KEY_FN_ESC), + NAME_ELEMENT(KEY_FN_F1), NAME_ELEMENT(KEY_FN_F2), + NAME_ELEMENT(KEY_FN_F3), NAME_ELEMENT(KEY_FN_F4), + NAME_ELEMENT(KEY_FN_F5), NAME_ELEMENT(KEY_FN_F6), + NAME_ELEMENT(KEY_FN_F7), NAME_ELEMENT(KEY_FN_F8), + NAME_ELEMENT(KEY_FN_F9), NAME_ELEMENT(KEY_FN_F10), + NAME_ELEMENT(KEY_FN_F11), NAME_ELEMENT(KEY_FN_F12), + NAME_ELEMENT(KEY_FN_1), NAME_ELEMENT(KEY_FN_2), + NAME_ELEMENT(KEY_FN_D), NAME_ELEMENT(KEY_FN_E), + NAME_ELEMENT(KEY_FN_F), NAME_ELEMENT(KEY_FN_S), + NAME_ELEMENT(KEY_FN_B), + NAME_ELEMENT(KEY_BRL_DOT1), NAME_ELEMENT(KEY_BRL_DOT2), + NAME_ELEMENT(KEY_BRL_DOT3), NAME_ELEMENT(KEY_BRL_DOT4), + NAME_ELEMENT(KEY_BRL_DOT5), NAME_ELEMENT(KEY_BRL_DOT6), + NAME_ELEMENT(KEY_BRL_DOT7), NAME_ELEMENT(KEY_BRL_DOT8), + NAME_ELEMENT(KEY_BRL_DOT9), NAME_ELEMENT(KEY_BRL_DOT10), + NAME_ELEMENT(KEY_NUMERIC_0), NAME_ELEMENT(KEY_NUMERIC_1), + NAME_ELEMENT(KEY_NUMERIC_2), NAME_ELEMENT(KEY_NUMERIC_3), + NAME_ELEMENT(KEY_NUMERIC_4), NAME_ELEMENT(KEY_NUMERIC_5), + NAME_ELEMENT(KEY_NUMERIC_6), NAME_ELEMENT(KEY_NUMERIC_7), + NAME_ELEMENT(KEY_NUMERIC_8), NAME_ELEMENT(KEY_NUMERIC_9), + NAME_ELEMENT(KEY_NUMERIC_STAR), NAME_ELEMENT(KEY_NUMERIC_POUND), + NAME_ELEMENT(KEY_BATTERY), + NAME_ELEMENT(KEY_BLUETOOTH), NAME_ELEMENT(KEY_BRIGHTNESS_CYCLE), + NAME_ELEMENT(KEY_BRIGHTNESS_ZERO), NAME_ELEMENT(KEY_DASHBOARD), + NAME_ELEMENT(KEY_DISPLAY_OFF), NAME_ELEMENT(KEY_DOCUMENTS), + NAME_ELEMENT(KEY_FORWARDMAIL), NAME_ELEMENT(KEY_NEW), + NAME_ELEMENT(KEY_KBDILLUMDOWN), NAME_ELEMENT(KEY_KBDILLUMUP), + NAME_ELEMENT(KEY_KBDILLUMTOGGLE), NAME_ELEMENT(KEY_REDO), + NAME_ELEMENT(KEY_REPLY), NAME_ELEMENT(KEY_SAVE), + NAME_ELEMENT(KEY_SCALE), NAME_ELEMENT(KEY_SEND), + NAME_ELEMENT(KEY_SCREENLOCK), NAME_ELEMENT(KEY_SWITCHVIDEOMODE), + NAME_ELEMENT(KEY_UWB), NAME_ELEMENT(KEY_VIDEO_NEXT), + NAME_ELEMENT(KEY_VIDEO_PREV), NAME_ELEMENT(KEY_WIMAX), + NAME_ELEMENT(KEY_WLAN), +#ifdef KEY_RFKILL + NAME_ELEMENT(KEY_RFKILL), +#endif +#ifdef KEY_WPS_BUTTON + NAME_ELEMENT(KEY_WPS_BUTTON), +#endif +#ifdef KEY_TOUCHPAD_TOGGLE + NAME_ELEMENT(KEY_TOUCHPAD_TOGGLE), + NAME_ELEMENT(KEY_TOUCHPAD_ON), + NAME_ELEMENT(KEY_TOUCHPAD_OFF), +#endif + + NAME_ELEMENT(BTN_0), NAME_ELEMENT(BTN_1), + NAME_ELEMENT(BTN_2), NAME_ELEMENT(BTN_3), + NAME_ELEMENT(BTN_4), NAME_ELEMENT(BTN_5), + NAME_ELEMENT(BTN_6), NAME_ELEMENT(BTN_7), + NAME_ELEMENT(BTN_8), NAME_ELEMENT(BTN_9), + NAME_ELEMENT(BTN_LEFT), NAME_ELEMENT(BTN_RIGHT), + NAME_ELEMENT(BTN_MIDDLE), NAME_ELEMENT(BTN_SIDE), + NAME_ELEMENT(BTN_EXTRA), NAME_ELEMENT(BTN_FORWARD), + NAME_ELEMENT(BTN_BACK), NAME_ELEMENT(BTN_TASK), + NAME_ELEMENT(BTN_TRIGGER), NAME_ELEMENT(BTN_THUMB), + NAME_ELEMENT(BTN_THUMB2), NAME_ELEMENT(BTN_TOP), + NAME_ELEMENT(BTN_TOP2), NAME_ELEMENT(BTN_PINKIE), + NAME_ELEMENT(BTN_BASE), NAME_ELEMENT(BTN_BASE2), + NAME_ELEMENT(BTN_BASE3), NAME_ELEMENT(BTN_BASE4), + NAME_ELEMENT(BTN_BASE5), NAME_ELEMENT(BTN_BASE6), + NAME_ELEMENT(BTN_DEAD), NAME_ELEMENT(BTN_A), + NAME_ELEMENT(BTN_B), NAME_ELEMENT(BTN_C), + NAME_ELEMENT(BTN_X), NAME_ELEMENT(BTN_Y), + NAME_ELEMENT(BTN_Z), NAME_ELEMENT(BTN_TL), + NAME_ELEMENT(BTN_TR), NAME_ELEMENT(BTN_TL2), + NAME_ELEMENT(BTN_TR2), NAME_ELEMENT(BTN_SELECT), + NAME_ELEMENT(BTN_START), NAME_ELEMENT(BTN_MODE), + NAME_ELEMENT(BTN_THUMBL), NAME_ELEMENT(BTN_THUMBR), + NAME_ELEMENT(BTN_TOOL_PEN), NAME_ELEMENT(BTN_TOOL_RUBBER), + NAME_ELEMENT(BTN_TOOL_BRUSH), NAME_ELEMENT(BTN_TOOL_PENCIL), + NAME_ELEMENT(BTN_TOOL_AIRBRUSH), NAME_ELEMENT(BTN_TOOL_FINGER), + NAME_ELEMENT(BTN_TOOL_MOUSE), NAME_ELEMENT(BTN_TOOL_LENS), + NAME_ELEMENT(BTN_TOUCH), NAME_ELEMENT(BTN_STYLUS), + NAME_ELEMENT(BTN_STYLUS2), NAME_ELEMENT(BTN_TOOL_DOUBLETAP), + NAME_ELEMENT(BTN_TOOL_TRIPLETAP), NAME_ELEMENT(BTN_TOOL_QUADTAP), + NAME_ELEMENT(BTN_GEAR_DOWN), + NAME_ELEMENT(BTN_GEAR_UP), + +#ifdef BTN_TRIGGER_HAPPY + NAME_ELEMENT(BTN_TRIGGER_HAPPY1), NAME_ELEMENT(BTN_TRIGGER_HAPPY11), + NAME_ELEMENT(BTN_TRIGGER_HAPPY2), NAME_ELEMENT(BTN_TRIGGER_HAPPY12), + NAME_ELEMENT(BTN_TRIGGER_HAPPY3), NAME_ELEMENT(BTN_TRIGGER_HAPPY13), + NAME_ELEMENT(BTN_TRIGGER_HAPPY4), NAME_ELEMENT(BTN_TRIGGER_HAPPY14), + NAME_ELEMENT(BTN_TRIGGER_HAPPY5), NAME_ELEMENT(BTN_TRIGGER_HAPPY15), + NAME_ELEMENT(BTN_TRIGGER_HAPPY6), NAME_ELEMENT(BTN_TRIGGER_HAPPY16), + NAME_ELEMENT(BTN_TRIGGER_HAPPY7), NAME_ELEMENT(BTN_TRIGGER_HAPPY17), + NAME_ELEMENT(BTN_TRIGGER_HAPPY8), NAME_ELEMENT(BTN_TRIGGER_HAPPY18), + NAME_ELEMENT(BTN_TRIGGER_HAPPY9), NAME_ELEMENT(BTN_TRIGGER_HAPPY19), + NAME_ELEMENT(BTN_TRIGGER_HAPPY10), NAME_ELEMENT(BTN_TRIGGER_HAPPY20), + + NAME_ELEMENT(BTN_TRIGGER_HAPPY21), NAME_ELEMENT(BTN_TRIGGER_HAPPY31), + NAME_ELEMENT(BTN_TRIGGER_HAPPY22), NAME_ELEMENT(BTN_TRIGGER_HAPPY32), + NAME_ELEMENT(BTN_TRIGGER_HAPPY23), NAME_ELEMENT(BTN_TRIGGER_HAPPY33), + NAME_ELEMENT(BTN_TRIGGER_HAPPY24), NAME_ELEMENT(BTN_TRIGGER_HAPPY34), + NAME_ELEMENT(BTN_TRIGGER_HAPPY25), NAME_ELEMENT(BTN_TRIGGER_HAPPY35), + NAME_ELEMENT(BTN_TRIGGER_HAPPY26), NAME_ELEMENT(BTN_TRIGGER_HAPPY36), + NAME_ELEMENT(BTN_TRIGGER_HAPPY27), NAME_ELEMENT(BTN_TRIGGER_HAPPY37), + NAME_ELEMENT(BTN_TRIGGER_HAPPY28), NAME_ELEMENT(BTN_TRIGGER_HAPPY38), + NAME_ELEMENT(BTN_TRIGGER_HAPPY29), NAME_ELEMENT(BTN_TRIGGER_HAPPY39), + NAME_ELEMENT(BTN_TRIGGER_HAPPY30), NAME_ELEMENT(BTN_TRIGGER_HAPPY40), +#endif +#ifdef BTN_TOOL_QUINTTAP + NAME_ELEMENT(BTN_TOOL_QUINTTAP), +#endif +}; + +static const char * const absval[6] = { "Value", "Min ", "Max ", "Fuzz ", "Flat ", "Resolution "}; + +static const char * const relatives[REL_MAX + 1] = { + [0 ... REL_MAX] = NULL, + NAME_ELEMENT(REL_X), NAME_ELEMENT(REL_Y), + NAME_ELEMENT(REL_Z), NAME_ELEMENT(REL_RX), + NAME_ELEMENT(REL_RY), NAME_ELEMENT(REL_RZ), + NAME_ELEMENT(REL_HWHEEL), + NAME_ELEMENT(REL_DIAL), NAME_ELEMENT(REL_WHEEL), + NAME_ELEMENT(REL_MISC), +}; + +static const char * const absolutes[ABS_MAX + 1] = { + [0 ... ABS_MAX] = NULL, + NAME_ELEMENT(ABS_X), NAME_ELEMENT(ABS_Y), + NAME_ELEMENT(ABS_Z), NAME_ELEMENT(ABS_RX), + NAME_ELEMENT(ABS_RY), NAME_ELEMENT(ABS_RZ), + NAME_ELEMENT(ABS_THROTTLE), NAME_ELEMENT(ABS_RUDDER), + NAME_ELEMENT(ABS_WHEEL), NAME_ELEMENT(ABS_GAS), + NAME_ELEMENT(ABS_BRAKE), NAME_ELEMENT(ABS_HAT0X), + NAME_ELEMENT(ABS_HAT0Y), NAME_ELEMENT(ABS_HAT1X), + NAME_ELEMENT(ABS_HAT1Y), NAME_ELEMENT(ABS_HAT2X), + NAME_ELEMENT(ABS_HAT2Y), NAME_ELEMENT(ABS_HAT3X), + NAME_ELEMENT(ABS_HAT3Y), NAME_ELEMENT(ABS_PRESSURE), + NAME_ELEMENT(ABS_DISTANCE), NAME_ELEMENT(ABS_TILT_X), + NAME_ELEMENT(ABS_TILT_Y), NAME_ELEMENT(ABS_TOOL_WIDTH), + NAME_ELEMENT(ABS_VOLUME), NAME_ELEMENT(ABS_MISC), +#ifdef ABS_MT_BLOB_ID + NAME_ELEMENT(ABS_MT_TOUCH_MAJOR), + NAME_ELEMENT(ABS_MT_TOUCH_MINOR), + NAME_ELEMENT(ABS_MT_WIDTH_MAJOR), + NAME_ELEMENT(ABS_MT_WIDTH_MINOR), + NAME_ELEMENT(ABS_MT_ORIENTATION), + NAME_ELEMENT(ABS_MT_POSITION_X), + NAME_ELEMENT(ABS_MT_POSITION_Y), + NAME_ELEMENT(ABS_MT_TOOL_TYPE), + NAME_ELEMENT(ABS_MT_BLOB_ID), +#endif +#ifdef ABS_MT_TRACKING_ID + NAME_ELEMENT(ABS_MT_TRACKING_ID), +#endif +#ifdef ABS_MT_PRESSURE + NAME_ELEMENT(ABS_MT_PRESSURE), +#endif +#ifdef ABS_MT_SLOT + NAME_ELEMENT(ABS_MT_SLOT), +#endif + +}; + +static const char * const misc[MSC_MAX + 1] = { + [ 0 ... MSC_MAX] = NULL, + NAME_ELEMENT(MSC_SERIAL), NAME_ELEMENT(MSC_PULSELED), + NAME_ELEMENT(MSC_GESTURE), NAME_ELEMENT(MSC_RAW), + NAME_ELEMENT(MSC_SCAN), +}; + +static const char * const leds[LED_MAX + 1] = { + [0 ... LED_MAX] = NULL, + NAME_ELEMENT(LED_NUML), NAME_ELEMENT(LED_CAPSL), + NAME_ELEMENT(LED_SCROLLL), NAME_ELEMENT(LED_COMPOSE), + NAME_ELEMENT(LED_KANA), NAME_ELEMENT(LED_SLEEP), + NAME_ELEMENT(LED_SUSPEND), NAME_ELEMENT(LED_MUTE), + NAME_ELEMENT(LED_MISC), +}; + +static const char * const repeats[REP_MAX + 1] = { + [0 ... REP_MAX] = NULL, + NAME_ELEMENT(REP_DELAY), NAME_ELEMENT(REP_PERIOD) +}; + +static const char * const sounds[SND_MAX + 1] = { + [0 ... SND_MAX] = NULL, + NAME_ELEMENT(SND_CLICK), NAME_ELEMENT(SND_BELL), + NAME_ELEMENT(SND_TONE) +}; + +static const char * const syns[3] = { + NAME_ELEMENT(SYN_REPORT), + NAME_ELEMENT(SYN_CONFIG), +#ifdef SYN_MT_REPORT + NAME_ELEMENT(SYN_MT_REPORT) +#endif +}; + +static const char * const switches[SW_MAX + 1] = { + [0 ... SW_MAX] = NULL, + NAME_ELEMENT(SW_LID), + NAME_ELEMENT(SW_TABLET_MODE), + NAME_ELEMENT(SW_HEADPHONE_INSERT), + NAME_ELEMENT(SW_RFKILL_ALL), + NAME_ELEMENT(SW_MICROPHONE_INSERT), + NAME_ELEMENT(SW_DOCK), + NAME_ELEMENT(SW_LINEOUT_INSERT), + NAME_ELEMENT(SW_JACK_PHYSICAL_INSERT), +#ifdef SW_VIDEOOUT_INSERT + NAME_ELEMENT(SW_VIDEOOUT_INSERT), +#endif +#ifdef SW_CAMERA_LENS_COVER + NAME_ELEMENT(SW_CAMERA_LENS_COVER), + NAME_ELEMENT(SW_KEYPAD_SLIDE), + NAME_ELEMENT(SW_FRONT_PROXIMITY), +#endif +#ifdef SW_ROTATE_LOCK + NAME_ELEMENT(SW_ROTATE_LOCK), +#endif +}; + +static const char * const force[FF_MAX + 1] = { + [0 ... FF_MAX] = NULL, + NAME_ELEMENT(FF_RUMBLE), NAME_ELEMENT(FF_PERIODIC), + NAME_ELEMENT(FF_CONSTANT), NAME_ELEMENT(FF_SPRING), + NAME_ELEMENT(FF_FRICTION), NAME_ELEMENT(FF_DAMPER), + NAME_ELEMENT(FF_INERTIA), NAME_ELEMENT(FF_RAMP), + NAME_ELEMENT(FF_SQUARE), NAME_ELEMENT(FF_TRIANGLE), + NAME_ELEMENT(FF_SINE), NAME_ELEMENT(FF_SAW_UP), + NAME_ELEMENT(FF_SAW_DOWN), NAME_ELEMENT(FF_CUSTOM), + NAME_ELEMENT(FF_GAIN), NAME_ELEMENT(FF_AUTOCENTER), +}; + +static const char * const forcestatus[FF_STATUS_MAX + 1] = { + [0 ... FF_STATUS_MAX] = NULL, + NAME_ELEMENT(FF_STATUS_STOPPED), NAME_ELEMENT(FF_STATUS_PLAYING), +}; + +static const char * const * const names[EV_MAX + 1] = { + [0 ... EV_MAX] = NULL, + [EV_SYN] = events, [EV_KEY] = keys, + [EV_REL] = relatives, [EV_ABS] = absolutes, + [EV_MSC] = misc, [EV_LED] = leds, + [EV_SND] = sounds, [EV_REP] = repeats, + [EV_SW] = switches, + [EV_FF] = force, [EV_FF_STATUS] = forcestatus, +}; + +/** + * Convert a string to a specific key/snd/led/sw code. The string can either + * be the name of the key in question (e.g. "SW_DOCK") or the numerical + * value, either as decimal (e.g. "5") or as hex (e.g. "0x5"). + * + * @param mode The mode being queried (key, snd, led, sw) + * @param kstr The string to parse and convert + * + * @return The requested code's numerical value, or negative on error. + */ +static int get_keycode(const struct query_mode *query_mode, const char *kstr) +{ + if (isdigit(kstr[0])) { + unsigned long val; + errno = 0; + val = strtoul(kstr, NULL, 0); + if (errno) { + fprintf(stderr, "Could not interpret value %s\n", kstr); + return -1; + } + return (int) val; + } else { + const char * const *keynames = names[query_mode->event_type]; + int i; + + for (i = 0; i < query_mode->max; i++) { + const char *name = keynames[i]; + if (name && strcmp(name, kstr) == 0) + return i; + } + + return -1; + } +} + +/** + * Filter for the AutoDevProbe scandir on /dev/input. + * + * @param dir The current directory entry provided by scandir. + * + * @return Non-zero if the given directory entry starts with "event", or zero + * otherwise. + */ +static int is_event_device(const struct dirent *dir) { + return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0; +} + +/** + * Scans all /dev/input/event*, display them and ask the user which one to + * open. + * + * @return The event device file name of the device file selected. This + * string is allocated and must be freed by the caller. + */ +static char* scan_devices(void) +{ + struct dirent **namelist; + int i, ndev, devnum; + char *filename; + + ndev = scandir(DEV_INPUT_EVENT, &namelist, is_event_device, alphasort); + if (ndev <= 0) + return NULL; + + fprintf(stderr, "Available devices:\n"); + + for (i = 0; i < ndev; i++) + { + char fname[64]; + int fd = -1; + char name[256] = "???"; + + snprintf(fname, sizeof(fname), + "%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name); + fd = open(fname, O_RDONLY); + if (fd < 0) + continue; + ioctl(fd, EVIOCGNAME(sizeof(name)), name); + + fprintf(stderr, "%s: %s\n", fname, name); + close(fd); + free(namelist[i]); + } + + fprintf(stderr, "Select the device event number [0-%d]: ", ndev - 1); + scanf("%d", &devnum); + + if (devnum >= ndev || devnum < 0) + return NULL; + + asprintf(&filename, "%s/%s%d", + DEV_INPUT_EVENT, EVENT_DEV_NAME, + devnum); + + return filename; +} + +static int version(void) +{ +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "" +#endif + printf("%s %s\n", program_invocation_short_name, PACKAGE_VERSION); + return EXIT_SUCCESS; +} + + +/** + * Print usage information. + */ +static int usage(void) +{ + printf("USAGE:\n"); + printf(" Grab mode:\n"); + printf(" %s /dev/input/eventX\n", program_invocation_short_name); + printf("\n"); + return EXIT_FAILURE; +} + +/** + * Print additional information for absolute axes (min/max, current value, + * etc.). + * + * @param fd The file descriptor to the device. + * @param axis The axis identifier (e.g. ABS_X). + */ +static void print_absdata(int fd, int axis) +{ + int abs[6] = {0}; + int k; + + ioctl(fd, EVIOCGABS(axis), abs); + for (k = 0; k < 6; k++) + if ((k < 3) || abs[k]) + printf(" %s %6d\n", absval[k], abs[k]); +} + +/* Returns the min and max value for absolute axis + * + * @param fd is the file descriptor to the device + * @param axis The axis identifier + * @param minmax[] The array with results of minmax[0]=min minmax[1]=max + * + */ +static void return_absminmax(int fd, int axis, int minmax[]) +{ + int abs[6] = {0}; + int k; + + ioctl(fd, EVIOCGABS(axis), abs); + for (k = 0; k < 6; k++) { + if ((k < 3) || abs[k]) { + if (k == 1) { + minmax[0] = abs[k]; + } + else if (k == 2) { + minmax[1] = abs[k]; + } + } + } + return; +} + +/** + * Print static device information (no events). This information includes + * version numbers, device name and all bits supported by this device. + * + * @param fd The file descriptor to the device. + * @return 0 on success or 1 otherwise. + */ +static int print_device_info(int fd) +{ + int i, j; + int version; + unsigned short id[4]; + char name[256] = "Unknown"; + unsigned long bit[EV_MAX][NBITS(KEY_MAX)]; +#ifdef INPUT_PROP_SEMI_MT + unsigned long propbits[INPUT_PROP_MAX]; +#endif + + if (ioctl(fd, EVIOCGVERSION, &version)) { + perror("evtest: can't get version"); + return 1; + } + + printf("Input driver version is %d.%d.%d\n", + version >> 16, (version >> 8) & 0xff, version & 0xff); + + ioctl(fd, EVIOCGID, id); + printf("Input device ID: bus 0x%x vendor 0x%x product 0x%x version 0x%x\n", + id[ID_BUS], id[ID_VENDOR], id[ID_PRODUCT], id[ID_VERSION]); + + ioctl(fd, EVIOCGNAME(sizeof(name)), name); + printf("Input device name: \"%s\"\n", name); + + memset(bit, 0, sizeof(bit)); + ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]); + printf("Supported events:\n"); + + for (i = 0; i < EV_MAX; i++) + if (test_bit(i, bit[0])) { + printf(" Event type %d (%s)\n", i, events[i] ? events[i] : "?"); + if (!i) continue; + ioctl(fd, EVIOCGBIT(i, KEY_MAX), bit[i]); + for (j = 0; j < KEY_MAX; j++) + if (test_bit(j, bit[i])) { + printf(" Event code %d (%s)\n", j, names[i] ? (names[i][j] ? names[i][j] : "?") : "?"); + if (i == EV_ABS) + print_absdata(fd, j); + } + } + +#ifdef INPUT_PROP_SEMI_MT + memset(propbits, 0, sizeof(propbits)); + ioctl(fd, EVIOCGPROP(sizeof(propbits)), propbits); + printf("Properties:\n"); + for (i = 0; i < INPUT_PROP_MAX; i++) { + if (test_bit(i, propbits)) + printf(" Property type %d (%s)\n", i, props[i] ? props[i] : "?"); + } +#endif + + return 0; +} +/** + * Test if the device is a touchpad and if it supports absolute coord + * input the min and max of touchpad into xyminmax + * + * @param fd The file descriptor to the device. + * @param xyminmax is the array to hold touchpad min max for x and y + * @return 0 on success or 1 otherwise. + */ +static int detect_touchpad(int fd, int xyminmax[]) +{ + int i, j; + unsigned long bit[EV_MAX][NBITS(KEY_MAX)]; + + memset(bit, 0, sizeof(bit)); + ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]); + int axis_count = 0; + + int xminmax[2] = {0}; + int yminmax[2] = {0}; + + for (i = 0; i < EV_MAX; i++) + if (test_bit(i, bit[0])) { + if (!i) continue; + ioctl(fd, EVIOCGBIT(i, KEY_MAX), bit[i]); + for (j = 0; j < KEY_MAX; j++) + if (test_bit(j, bit[i])) { + if (i == EV_ABS) { + if (j == 0) { //ABS_X + return_absminmax(fd, j, xminmax); + } + else if (j == 1) { //ABS_Y + return_absminmax(fd, j, yminmax); + } + } + } + } + if ((xminmax[0] == xminmax[1]) || (yminmax[0] == yminmax[1])) + return 1; + for (int a=0; a<2; a++) + xyminmax[a]=xminmax[a]; + for (int b=0; b<2; b++) + xyminmax[b+2]=yminmax[b]; + return 0; +} + + +/** + * Process events and move pointer + * + * @param fd The file descriptor to the device. + * @param xyminmax is an array with 0:x-min 1:x-max 2:y-min 3:y-max + * @return 0 on success or 1 otherwise. + */ +static int process_events(int fd, int xyminmax[]) +{ + struct input_event ev[64]; + int i, rd; + Display *dpy = XOpenDisplay(0); + Screen *defscr = DefaultScreenOfDisplay(dpy); + int scr_width = WidthOfScreen(defscr); + int scr_height = HeightOfScreen(defscr); + int tarx = 0; + int tary = 0; + int tp_x_range = xyminmax[1]-xyminmax[0]; + int tp_y_range = xyminmax[3]-xyminmax[2]; + Window root_window; + root_window = XRootWindow(dpy, 0); + + while (1) { + rd = read(fd, ev, sizeof(struct input_event) * 64); + + if (rd < (int) sizeof(struct input_event)) { + printf("expected %d bytes, got %d\n", (int) sizeof(struct input_event), rd); + perror("\nevtest: error reading"); + return 1; + } + + for (i = 0; i < rd / sizeof(struct input_event); i++) { + if (ev[i].type == 3) { /*EV_ABS*/ + if (ev[i].code==0) {/*ABS_X*/ + tarx = (int) floor(((double)ev[i].value/(double)tp_x_range) * (double) scr_width); + } + else if (ev[i].code==1) {/*ABS_Y*/ + tary = (int) floor(((double)ev[i].value/(double)tp_y_range) * (double) scr_height); + } + } + else if (ev[i].type == 1) { /*EV_KEY*/ + if (ev[i].code==272 && ev[i].value==1) //BTN_LEFT + XTestFakeButtonEvent(dpy, 1, True, CurrentTime); + XTestFakeButtonEvent(dpy, 1, False, CurrentTime); + } + } + XWarpPointer(dpy, None, root_window, 0, 0, 0, 0, tarx, tary); + XSync(dpy, False); + } +} + +/** + * Grab and immediately ungrab the device. + * + * @param fd The file descriptor to the device. + * @return 0 if the grab was successful, or 1 otherwise. + */ +static int test_grab(int fd) +{ + int rc; + + rc = ioctl(fd, EVIOCGRAB, (void*)1); + + if (!rc) + ioctl(fd, EVIOCGRAB, (void*)0); + + return rc; +} + +/** + * Enter capture mode. The requested event device will be monitored, and any + * captured events will be decoded and printed on the console. + * + * @param device The device to monitor, or NULL if the user should be prompted. + * @return 0 on success, non-zero on error. + */ +static int do_capture(const char *device) +{ + int fd; + char *filename; + + if (!device) { + fprintf(stderr, "No device specified, trying to scan all of %s/%s*\n", + DEV_INPUT_EVENT, EVENT_DEV_NAME); + + if (getuid() != 0) + fprintf(stderr, "Not running as root, no devices may be available.\n"); + + filename = scan_devices(); + if (!filename) + return usage(); + } else + filename = strdup(device); + + if (!filename) + return EXIT_FAILURE; + + if ((fd = open(filename, O_RDONLY)) < 0) { + perror("evtest"); + if (errno == EACCES && getuid() != 0) + fprintf(stderr, "You do not have access to %s. Try " + "running as root instead.\n", + filename); + return EXIT_FAILURE; + } + + free(filename); + + if (!isatty(fileno(stdout))) + setbuf(stdout, NULL); + + if (print_device_info(fd)) + return EXIT_FAILURE; + int xyminmax[4] = {0}; + if (detect_touchpad(fd, xyminmax)) { + printf ("touchpad error\n"); + return EXIT_FAILURE; + } + + printf("Testing ... (interrupt to exit)\n"); + + if (test_grab(fd)) + { + printf("***********************************************\n"); + printf(" This device is grabbed by another process.\n"); + printf(" No events are available to evtest while the\n" + " other grab is active.\n"); + printf(" In most cases, this is caused by an X driver,\n" + " try VT-switching and re-run evtest again.\n"); + printf("***********************************************\n"); + } + + return process_events(fd, xyminmax); +} +static const struct option long_options[] = { + { "version", no_argument, NULL, MODE_VERSION }, + { 0, }, +}; + +int main (int argc, char **argv) +{ + const char *device = NULL; + const char *keyname; + const char *event_type; + enum evtest_mode mode = MODE_CAPTURE; + + while (1) { + int option_index = 0; + int c = getopt_long(argc, argv, "", long_options, &option_index); + if (c == -1) + break; + switch (c) { + case MODE_VERSION: + return version(); + default: + return usage(); + } + } + + if (optind < argc) + device = argv[optind++]; + + return do_capture(device); +} +/* vim: set noexpandtab tabstop=8 shiftwidth=8: */