diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2009-11-11 09:36:02 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2009-11-11 09:36:02 +1000 |
commit | 19b55e98b3857c14b155fe758fc7540253df1763 (patch) | |
tree | 56f37e93bb835aadffa74a7631093d488e48db11 | |
parent | 2cffe44236858c7192370773e4c87ef5e834c6fb (diff) | |
parent | c8d297bda084651124ed0935f17a87f20fbee6b1 (diff) |
Merge branch 'evtest-capture'
-rw-r--r-- | Makefile.am | 12 | ||||
-rw-r--r-- | configure.ac | 12 | ||||
-rw-r--r-- | evtest-capture.c | 906 | ||||
-rw-r--r-- | evtest-create-device.xsl | 212 |
4 files changed, 1140 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am index f9c000b..478df10 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,13 @@ + bin_PROGRAMS = evtest -evtest_SOURCES = evtest.c + +if HAVE_LIBXML +bin_PROGRAMS += evtest-capture +AM_CFLAGS = $(XML_CFLAGS) + +evtest_capture_LDADD = $(XML_LIBS) +endif + man1_MANS = evtest.man -EXTRA_DIST = $(man1_MANS) +EXTRA_DIST = $(man1_MANS) evtest-generate-device.xsl diff --git a/configure.ac b/configure.ac index f8647d7..32d521b 100644 --- a/configure.ac +++ b/configure.ac @@ -6,4 +6,16 @@ AM_CONFIG_HEADER(config.h) AC_PROG_CC AC_PROG_INSTALL +PKG_CHECK_MODULES(XML, libxml-2.0, [HAVE_LIBXML=yes], [HAVE_LIBXML=no]) +if test x$HAVE_LIBXML = "xno"; then + AC_MSG_WARN([libxml headers not available. Cannot build evtest-capture.]) +fi +AM_CONDITIONAL(HAVE_LIBXML, [test "x$HAVE_LIBXML" = "xyes"]) + +AC_PATH_PROG(XSLTPROC, [xsltproc]) +AM_CONDITIONAL([HAVE_XSLTPROC], [test "x$XSLTPROC" != "x"]) +if test "x$XSLTPROC" = "x"; then + AC_MSG_WARN([xsltproc not found, needed to generate devices.]) +fi + AC_OUTPUT([Makefile]) diff --git a/evtest-capture.c b/evtest-capture.c new file mode 100644 index 0000000..0f68494 --- /dev/null +++ b/evtest-capture.c @@ -0,0 +1,906 @@ +/* + * Copyright (c) 2009 Red Hat, Inc. + * + * Event device capture program. + */ + +/* + * 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 <linux/input.h> + +#include <stdint.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <signal.h> +#include <dirent.h> + +#include <libxml/encoding.h> +#include <libxml/xmlwriter.h> + +#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(x)) +#define LONG(x) ((x)/BITS_PER_LONG) +#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1) +#define MY_ENCODING "ISO-8859-1" + +/* libxml api is annoying. 'sanitize' it with macros */ +#define call(func) \ + rc = (func); \ + if (rc < 0) \ + goto error; +#define start(...) call(xmlTextWriterStartElement(writer, __VA_ARGS__)) +#define end(dummy) call(xmlTextWriterEndElement(writer)) +#define format(...) call(xmlTextWriterWriteFormatElement(writer, __VA_ARGS__)) +#define attr(...) call(xmlTextWriterWriteAttribute(writer, __VA_ARGS__)) + +static int stop = 0; + +const char *keys[KEY_MAX + 1] = { + [KEY_RESERVED] = "KEY_RESERVED", + [KEY_ESC] = "KEY_ESC", + [KEY_1] = "KEY_1", + [KEY_2] = "KEY_2", + [KEY_3] = "KEY_3", + [KEY_4] = "KEY_4", + [KEY_5] = "KEY_5", + [KEY_6] = "KEY_6", + [KEY_7] = "KEY_7", + [KEY_8] = "KEY_8", + [KEY_9] = "KEY_9", + [KEY_0] = "KEY_0", + [KEY_MINUS] = "KEY_MINUS", + [KEY_EQUAL] = "KEY_EQUAL", + [KEY_BACKSPACE] = "KEY_BACKSPACE", + [KEY_TAB] = "KEY_TAB", + [KEY_Q] = "KEY_Q", + [KEY_W] = "KEY_W", + [KEY_E] = "KEY_E", + [KEY_R] = "KEY_R", + [KEY_T] = "KEY_T", + [KEY_Y] = "KEY_Y", + [KEY_U] = "KEY_U", + [KEY_I] = "KEY_I", + [KEY_O] = "KEY_O", + [KEY_P] = "KEY_P", + [KEY_LEFTBRACE] = "KEY_LEFTBRACE", + [KEY_RIGHTBRACE] = "KEY_RIGHTBRACE", + [KEY_ENTER] = "KEY_ENTER", + [KEY_LEFTCTRL] = "KEY_LEFTCTRL", + [KEY_A] = "KEY_A", + [KEY_S] = "KEY_S", + [KEY_D] = "KEY_D", + [KEY_F] = "KEY_F", + [KEY_G] = "KEY_G", + [KEY_H] = "KEY_H", + [KEY_J] = "KEY_J", + [KEY_K] = "KEY_K", + [KEY_L] = "KEY_L", + [KEY_SEMICOLON] = "KEY_SEMICOLON", + [KEY_APOSTROPHE] = "KEY_APOSTROPHE", + [KEY_GRAVE] = "KEY_GRAVE", + [KEY_LEFTSHIFT] = "KEY_LEFTSHIFT", + [KEY_BACKSLASH] = "KEY_BACKSLASH", + [KEY_Z] = "KEY_Z", + [KEY_X] = "KEY_X", + [KEY_C] = "KEY_C", + [KEY_V] = "KEY_V", + [KEY_B] = "KEY_B", + [KEY_N] = "KEY_N", + [KEY_M] = "KEY_M", + [KEY_COMMA] = "KEY_COMMA", + [KEY_DOT] = "KEY_DOT", + [KEY_SLASH] = "KEY_SLASH", + [KEY_RIGHTSHIFT] = "KEY_RIGHTSHIFT", + [KEY_KPASTERISK] = "KEY_KPASTERISK", + [KEY_LEFTALT] = "KEY_LEFTALT", + [KEY_SPACE] = "KEY_SPACE", + [KEY_CAPSLOCK] = "KEY_CAPSLOCK", + [KEY_F1] = "KEY_F1", + [KEY_F2] = "KEY_F2", + [KEY_F3] = "KEY_F3", + [KEY_F4] = "KEY_F4", + [KEY_F5] = "KEY_F5", + [KEY_F6] = "KEY_F6", + [KEY_F7] = "KEY_F7", + [KEY_F8] = "KEY_F8", + [KEY_F9] = "KEY_F9", + [KEY_F10] = "KEY_F10", + [KEY_NUMLOCK] = "KEY_NUMLOCK", + [KEY_SCROLLLOCK] = "KEY_SCROLLLOCK", + [KEY_KP7] = "KEY_KP7", + [KEY_KP8] = "KEY_KP8", + [KEY_KP9] = "KEY_KP9", + [KEY_KPMINUS] = "KEY_KPMINUS", + [KEY_KP4] = "KEY_KP4", + [KEY_KP5] = "KEY_KP5", + [KEY_KP6] = "KEY_KP6", + [KEY_KPPLUS] = "KEY_KPPLUS", + [KEY_KP1] = "KEY_KP1", + [KEY_KP2] = "KEY_KP2", + [KEY_KP3] = "KEY_KP3", + [KEY_KP0] = "KEY_KP0", + [KEY_KPDOT] = "KEY_KPDOT", + + [KEY_ZENKAKUHANKAKU] = "KEY_ZENKAKUHANKAKU", + [KEY_102ND] = "KEY_102ND", + [KEY_F11] = "KEY_F11", + [KEY_F12] = "KEY_F12", + [KEY_RO] = "KEY_RO", + [KEY_KATAKANA] = "KEY_KATAKANA", + [KEY_HIRAGANA] = "KEY_HIRAGANA", + [KEY_HENKAN] = "KEY_HENKAN", + [KEY_KATAKANAHIRAGANA] = "KEY_KATAKANAHIRAGANA", + [KEY_MUHENKAN] = "KEY_MUHENKAN", + [KEY_KPJPCOMMA] = "KEY_KPJPCOMMA", + [KEY_KPENTER] = "KEY_KPENTER", + [KEY_RIGHTCTRL] = "KEY_RIGHTCTRL", + [KEY_KPSLASH] = "KEY_KPSLASH", + [KEY_SYSRQ] = "KEY_SYSRQ", + [KEY_RIGHTALT] = "KEY_RIGHTALT", + [KEY_LINEFEED] = "KEY_LINEFEED", + [KEY_HOME] = "KEY_HOME", + [KEY_UP] = "KEY_UP", + [KEY_PAGEUP] = "KEY_PAGEUP", + [KEY_LEFT] = "KEY_LEFT", + [KEY_RIGHT] = "KEY_RIGHT", + [KEY_END] = "KEY_END", + [KEY_DOWN] = "KEY_DOWN", + [KEY_PAGEDOWN] = "KEY_PAGEDOWN", + [KEY_INSERT] = "KEY_INSERT", + [KEY_DELETE] = "KEY_DELETE", + [KEY_MACRO] = "KEY_MACRO", + [KEY_MUTE] = "KEY_MUTE", + [KEY_VOLUMEDOWN] = "KEY_VOLUMEDOWN", + [KEY_VOLUMEUP] = "KEY_VOLUMEUP", + [KEY_POWER] = "KEY_POWER", + [KEY_KPEQUAL] = "KEY_KPEQUAL", + [KEY_KPPLUSMINUS] = "KEY_KPPLUSMINUS", + [KEY_PAUSE] = "KEY_PAUSE", + [KEY_SCALE] = "KEY_SCALE", + + [KEY_KPCOMMA] = "KEY_KPCOMMA", + [KEY_HANGEUL] = "KEY_HANGEUL", + [KEY_HANGUEL] = "KEY_HANGUEL", + [KEY_HANJA] = "KEY_HANJA", + [KEY_YEN] = "KEY_YEN", + [KEY_LEFTMETA] = "KEY_LEFTMETA", + [KEY_RIGHTMETA] = "KEY_RIGHTMETA", + [KEY_COMPOSE] = "KEY_COMPOSE", + + [KEY_STOP] = "KEY_STOP", + [KEY_AGAIN] = "KEY_AGAIN", + [KEY_PROPS] = "KEY_PROPS", + [KEY_UNDO] = "KEY_UNDO", + [KEY_FRONT] = "KEY_FRONT", + [KEY_COPY] = "KEY_COPY", + [KEY_OPEN] = "KEY_OPEN", + [KEY_PASTE] = "KEY_PASTE", + [KEY_FIND] = "KEY_FIND", + [KEY_CUT] = "KEY_CUT", + [KEY_HELP] = "KEY_HELP", + [KEY_MENU] = "KEY_MENU", + [KEY_CALC] = "KEY_CALC", + [KEY_SETUP] = "KEY_SETUP", + [KEY_SLEEP] = "KEY_SLEEP", + [KEY_WAKEUP] = "KEY_WAKEUP", + [KEY_FILE] = "KEY_FILE", + [KEY_SENDFILE] = "KEY_SENDFILE", + [KEY_DELETEFILE] = "KEY_DELETEFILE", + [KEY_XFER] = "KEY_XFER", + [KEY_PROG1] = "KEY_PROG1", + [KEY_PROG2] = "KEY_PROG2", + [KEY_WWW] = "KEY_WWW", + [KEY_MSDOS] = "KEY_MSDOS", + [KEY_COFFEE] = "KEY_COFFEE", + [KEY_SCREENLOCK] = "KEY_SCREENLOCK", + [KEY_DIRECTION] = "KEY_DIRECTION", + [KEY_CYCLEWINDOWS] = "KEY_CYCLEWINDOWS", + [KEY_MAIL] = "KEY_MAIL", + [KEY_BOOKMARKS] = "KEY_BOOKMARKS", + [KEY_COMPUTER] = "KEY_COMPUTER", + [KEY_BACK] = "KEY_BACK", + [KEY_FORWARD] = "KEY_FORWARD", + [KEY_CLOSECD] = "KEY_CLOSECD", + [KEY_EJECTCD] = "KEY_EJECTCD", + [KEY_EJECTCLOSECD] = "KEY_EJECTCLOSECD", + [KEY_NEXTSONG] = "KEY_NEXTSONG", + [KEY_PLAYPAUSE] = "KEY_PLAYPAUSE", + [KEY_PREVIOUSSONG] = "KEY_PREVIOUSSONG", + [KEY_STOPCD] = "KEY_STOPCD", + [KEY_RECORD] = "KEY_RECORD", + [KEY_REWIND] = "KEY_REWIND", + [KEY_PHONE] = "KEY_PHONE", + [KEY_ISO] = "KEY_ISO", + [KEY_CONFIG] = "KEY_CONFIG", + [KEY_HOMEPAGE] = "KEY_HOMEPAGE", + [KEY_REFRESH] = "KEY_REFRESH", + [KEY_EXIT] = "KEY_EXIT", + [KEY_MOVE] = "KEY_MOVE", + [KEY_EDIT] = "KEY_EDIT", + [KEY_SCROLLUP] = "KEY_SCROLLUP", + [KEY_SCROLLDOWN] = "KEY_SCROLLDOWN", + [KEY_KPLEFTPAREN] = "KEY_KPLEFTPAREN", + [KEY_KPRIGHTPAREN] = "KEY_KPRIGHTPAREN", + [KEY_NEW] = "KEY_NEW", + [KEY_REDO] = "KEY_REDO", + + [KEY_F13] = "KEY_F13", + [KEY_F14] = "KEY_F14", + [KEY_F15] = "KEY_F15", + [KEY_F16] = "KEY_F16", + [KEY_F17] = "KEY_F17", + [KEY_F18] = "KEY_F18", + [KEY_F19] = "KEY_F19", + [KEY_F20] = "KEY_F20", + [KEY_F21] = "KEY_F21", + [KEY_F22] = "KEY_F22", + [KEY_F23] = "KEY_F23", + [KEY_F24] = "KEY_F24", + + [KEY_PLAYCD] = "KEY_PLAYCD", + [KEY_PAUSECD] = "KEY_PAUSECD", + [KEY_PROG3] = "KEY_PROG3", + [KEY_PROG4] = "KEY_PROG4", + [KEY_DASHBOARD] = "KEY_DASHBOARD", + [KEY_SUSPEND] = "KEY_SUSPEND", + [KEY_CLOSE] = "KEY_CLOSE", + [KEY_PLAY] = "KEY_PLAY", + [KEY_FASTFORWARD] = "KEY_FASTFORWARD", + [KEY_BASSBOOST] = "KEY_BASSBOOST", + [KEY_PRINT] = "KEY_PRINT", + [KEY_HP] = "KEY_HP", + [KEY_CAMERA] = "KEY_CAMERA", + [KEY_SOUND] = "KEY_SOUND", + [KEY_QUESTION] = "KEY_QUESTION", + [KEY_EMAIL] = "KEY_EMAIL", + [KEY_CHAT] = "KEY_CHAT", + [KEY_SEARCH] = "KEY_SEARCH", + [KEY_CONNECT] = "KEY_CONNECT", + [KEY_FINANCE] = "KEY_FINANCE", + [KEY_SPORT] = "KEY_SPORT", + [KEY_SHOP] = "KEY_SHOP", + [KEY_ALTERASE] = "KEY_ALTERASE", + [KEY_CANCEL] = "KEY_CANCEL", + [KEY_BRIGHTNESSDOWN] = "KEY_BRIGHTNESSDOWN", + [KEY_BRIGHTNESSUP] = "KEY_BRIGHTNESSUP", + [KEY_MEDIA] = "KEY_MEDIA", + + [KEY_SWITCHVIDEOMODE] = "KEY_SWITCHVIDEOMODE", + [KEY_KBDILLUMTOGGLE] = "KEY_KBDILLUMTOGGLE", + [KEY_KBDILLUMDOWN] = "KEY_KBDILLUMDOWN", + [KEY_KBDILLUMUP] = "KEY_KBDILLUMUP", + + [KEY_SEND] = "KEY_SEND", + [KEY_REPLY] = "KEY_REPLY", + [KEY_FORWARDMAIL] = "KEY_FORWARDMAIL", + [KEY_SAVE] = "KEY_SAVE", + [KEY_DOCUMENTS] = "KEY_DOCUMENTS", + + [KEY_BATTERY] = "KEY_BATTERY", + + [KEY_BLUETOOTH] = "KEY_BLUETOOTH", + [KEY_WLAN] = "KEY_WLAN", + [KEY_UWB] = "KEY_UWB", + + [KEY_UNKNOWN] = "KEY_UNKNOWN", + + [KEY_VIDEO_NEXT] = "KEY_VIDEO_NEXT", + [KEY_VIDEO_PREV] = "KEY_VIDEO_PREV", + [KEY_BRIGHTNESS_CYCLE] = "KEY_BRIGHTNESS_CYCLE", + [KEY_BRIGHTNESS_ZERO] = "KEY_BRIGHTNESS_ZERO", + [KEY_DISPLAY_OFF] = "KEY_DISPLAY_OFF", + + [KEY_WIMAX] = "KEY_WIMAX", + + [BTN_0] = "BTN_0", + [BTN_1] = "BTN_1", + + [BTN_2] = "BTN_2", + [BTN_3] = "BTN_3", + + [BTN_4] = "BTN_4", + [BTN_5] = "BTN_5", + + [BTN_6] = "BTN_6", + [BTN_7] = "BTN_7", + + [BTN_8] = "BTN_8", + [BTN_9] = "BTN_9", + + [BTN_LEFT] = "BTN_LEFT", + [BTN_RIGHT] = "BTN_RIGHT", + + [BTN_MIDDLE] = "BTN_MIDDLE", + [BTN_SIDE] = "BTN_SIDE", + + [BTN_EXTRA] = "BTN_EXTRA", + [BTN_FORWARD] = "BTN_FORWARD", + + [BTN_BACK] = "BTN_BACK", + [BTN_TASK] = "BTN_TASK", + + [BTN_TRIGGER] = "BTN_TRIGGER", + [BTN_THUMB] = "BTN_THUMB", + + [BTN_THUMB2] = "BTN_THUMB2", + [BTN_TOP] = "BTN_TOP", + + [BTN_TOP2] = "BTN_TOP2", + [BTN_PINKIE] = "BTN_PINKIE", + + [BTN_BASE] = "BTN_BASE", + [BTN_BASE2] = "BTN_BASE2", + + [BTN_BASE3] = "BTN_BASE3", + [BTN_BASE4] = "BTN_BASE4", + + [BTN_BASE5] = "BTN_BASE5", + [BTN_BASE6] = "BTN_BASE6", + + [BTN_DEAD] = "BTN_DEAD", + [BTN_A] = "BTN_A", + + [BTN_B] = "BTN_B", + [BTN_C] = "BTN_C", + + [BTN_X] = "BTN_X", + [BTN_Y] = "BTN_Y", + + [BTN_Z] = "BTN_Z", + [BTN_TL] = "BTN_TL", + + [BTN_TR] = "BTN_TR", + [BTN_TL2] = "BTN_TL2", + + [BTN_TR2] = "BTN_TR2", + [BTN_SELECT] = "BTN_SELECT", + + [BTN_START] = "BTN_START", + [BTN_MODE] = "BTN_MODE", + + [BTN_THUMBL] = "BTN_THUMBL", + [BTN_THUMBR] = "BTN_THUMBR", + + [BTN_TOOL_PEN] = "BTN_TOOL_PEN", + [BTN_TOOL_RUBBER] = "BTN_TOOL_RUBBER", + + [BTN_TOOL_BRUSH] = "BTN_TOOL_BRUSH", + [BTN_TOOL_PENCIL] = "BTN_TOOL_PENCIL", + + [BTN_TOOL_AIRBRUSH] = "BTN_TOOL_AIRBRUSH", + [BTN_TOOL_FINGER] = "BTN_TOOL_FINGER", + + [BTN_TOOL_MOUSE] = "BTN_TOOL_MOUSE", + [BTN_TOOL_LENS] = "BTN_TOOL_LENS", + + [BTN_TOUCH] = "BTN_TOUCH", + [BTN_STYLUS] = "BTN_STYLUS", + + [BTN_STYLUS2] = "BTN_STYLUS2", + [BTN_TOOL_DOUBLETAP] = "BTN_TOOL_DOUBLETAP", + + [BTN_TOOL_TRIPLETAP] = "BTN_TOOL_TRIPLETAP", + [BTN_GEAR_DOWN] = "BTN_GEAR_DOWN", + + [BTN_GEAR_UP] = "BTN_GEAR_UP", + [KEY_OK] = "KEY_OK", + + [KEY_SELECT] = "KEY_SELECT", + [KEY_GOTO] = "KEY_GOTO", + + [KEY_CLEAR] = "KEY_CLEAR", + [KEY_POWER2] = "KEY_POWER2", + + [KEY_OPTION] = "KEY_OPTION", + [KEY_INFO] = "KEY_INFO", + + [KEY_TIME] = "KEY_TIME", + [KEY_VENDOR] = "KEY_VENDOR", + + [KEY_ARCHIVE] = "KEY_ARCHIVE", + [KEY_PROGRAM] = "KEY_PROGRAM", + + [KEY_CHANNEL] = "KEY_CHANNEL", + [KEY_FAVORITES] = "KEY_FAVORITES", + + [KEY_EPG] = "KEY_EPG", + [KEY_PVR] = "KEY_PVR", + + [KEY_MHP] = "KEY_MHP", + [KEY_LANGUAGE] = "KEY_LANGUAGE", + + [KEY_TITLE] = "KEY_TITLE", + [KEY_SUBTITLE] = "KEY_SUBTITLE", + + [KEY_ANGLE] = "KEY_ANGLE", + [KEY_ZOOM] = "KEY_ZOOM", + + [KEY_MODE] = "KEY_MODE", + [KEY_KEYBOARD] = "KEY_KEYBOARD", + + [KEY_SCREEN] = "KEY_SCREEN", + [KEY_PC] = "KEY_PC", + + [KEY_TV] = "KEY_TV", + [KEY_TV2] = "KEY_TV2", + + [KEY_VCR] = "KEY_VCR", + [KEY_VCR2] = "KEY_VCR2", + + [KEY_SAT] = "KEY_SAT", + [KEY_SAT2] = "KEY_SAT2", + + [KEY_CD] = "KEY_CD", + [KEY_TAPE] = "KEY_TAPE", + + [KEY_RADIO] = "KEY_RADIO", + [KEY_TUNER] = "KEY_TUNER", + + [KEY_PLAYER] = "KEY_PLAYER", + [KEY_TEXT] = "KEY_TEXT", + + [KEY_DVD] = "KEY_DVD", + [KEY_AUX] = "KEY_AUX", + + [KEY_MP3] = "KEY_MP3", + [KEY_AUDIO] = "KEY_AUDIO", + + [KEY_VIDEO] = "KEY_VIDEO", + [KEY_DIRECTORY] = "KEY_DIRECTORY", + + [KEY_LIST] = "KEY_LIST", + [KEY_MEMO] = "KEY_MEMO", + + [KEY_CALENDAR] = "KEY_CALENDAR", + [KEY_RED] = "KEY_RED", + + [KEY_GREEN] = "KEY_GREEN", + [KEY_YELLOW] = "KEY_YELLOW", + + [KEY_BLUE] = "KEY_BLUE", + [KEY_CHANNELUP] = "KEY_CHANNELUP", + + [KEY_CHANNELDOWN] = "KEY_CHANNELDOWN", + [KEY_FIRST] = "KEY_FIRST", + + [KEY_LAST] = "KEY_LAST", + [KEY_AB] = "KEY_AB", + + [KEY_NEXT] = "KEY_NEXT", + [KEY_RESTART] = "KEY_RESTART", + + [KEY_SLOW] = "KEY_SLOW", + [KEY_SHUFFLE] = "KEY_SHUFFLE", + + [KEY_BREAK] = "KEY_BREAK", + [KEY_PREVIOUS] = "KEY_PREVIOUS", + + [KEY_DIGITS] = "KEY_DIGITS", + [KEY_TEEN] = "KEY_TEEN", + + [KEY_TWEN] = "KEY_TWEN", + [KEY_DEL_EOL] = "KEY_DEL_EOL", + + [KEY_DEL_EOS] = "KEY_DEL_EOS", + [KEY_INS_LINE] = "KEY_INS_LINE", + + [KEY_DEL_LINE] = "KEY_DEL_LINE", +}; + +const char *events[EV_MAX + 1] = { + [0 ... EV_MAX] = NULL, + [EV_SYN] = "EV_SYN", + [EV_KEY] = "EV_KEY", + [EV_REL] = "EV_REL", + [EV_ABS] = "EV_ABS", + [EV_MSC] = "EV_MSC", + [EV_SW] = "EV_SW", + [EV_LED] = "EV_LED", + [EV_SND] = "EV_SND", + [EV_REP] = "EV_REP", + [EV_FF] = "EV_FF", + [EV_PWR] = "EV_PWR", + [EV_FF_STATUS] = "EV_FF_STATUS", +}; + +const char *relatives[REL_MAX + 1] = { + [0 ... REL_MAX] = NULL, + [REL_X] = "REL_X", + [REL_Y] = "REL_Y", + [REL_Z] = "REL_Z", + [REL_HWHEEL] = "REL_HWHEEL", + [REL_DIAL] = "REL_DIAL", + [REL_WHEEL] = "REL_WHEEL", + [REL_MISC] = "REL_MISC", +}; + +const char *absolutes[ABS_MAX + 1] = { + [0 ... ABS_MAX] = NULL, + [ABS_X] = "ABS_X", + [ABS_Y] = "ABS_Y", + [ABS_Z] = "ABS_Z", + [ABS_RX] = "ABS_RX", + [ABS_RY] = "ABS_RY", + [ABS_RZ] = "ABS_RZ", + [ABS_THROTTLE] = "ABS_THROTTLE", + [ABS_RUDDER] = "ABS_RUDDER", + [ABS_WHEEL] = "ABS_WHEEL", + [ABS_GAS] = "ABS_GAS", + [ABS_BRAKE] = "ABS_BRAKE", + [ABS_HAT0X] = "ABS_HAT0X", + [ABS_HAT0Y] = "ABS_HAT0Y", + [ABS_HAT1X] = "ABS_HAT1X", + [ABS_HAT1Y] = "ABS_HAT1Y", + [ABS_HAT2X] = "ABS_HAT2X", + [ABS_HAT2Y] = "ABS_HAT2Y", + [ABS_HAT3X] = "ABS_HAT3X", + [ABS_HAT3Y] = "ABS_HAT3Y", + [ABS_PRESSURE] = "ABS_PRESSURE", + [ABS_DISTANCE] = "ABS_DISTANCE", + [ABS_TILT_X] = "ABS_TILT_X", + [ABS_TILT_Y] = "ABS_TILT_Y", + [ABS_TOOL_WIDTH] = "ABS_TOOL_WIDTH", + [ABS_VOLUME] = "ABS_VOLUME", + [ABS_MISC] = "ABS_MISC", + [ABS_MT_TOUCH_MAJOR] = "ABS_MT_TOUCH_MAJOR", + [ABS_MT_TOUCH_MINOR] = "ABS_MT_TOUCH_MINOR", + [ABS_MT_WIDTH_MAJOR] = "ABS_MT_WIDTH_MAJOR", + [ABS_MT_WIDTH_MINOR] = "ABS_MT_WIDTH_MINOR", + [ABS_MT_ORIENTATION] = "ABS_MT_ORIENTATION", + [ABS_MT_POSITION_X] = "ABS_MT_POSITION_X", + [ABS_MT_POSITION_Y] = "ABS_MT_POSITION_Y", + [ABS_MT_TOOL_TYPE] = "ABS_MT_TOOL_TYPE", + [ABS_MT_BLOB_ID] = "ABS_MT_BLOB_ID", + [ABS_MT_TRACKING_ID] = "ABS_MT_TRACKING_ID", +}; + +const char *misc[MSC_MAX + 1] = { + [ 0 ... MSC_MAX] = NULL, + [MSC_SERIAL] = "MSC_SERIAL", + [MSC_PULSELED] = "MSC_PULSELED", + [MSC_GESTURE] = "MSC_GESTURE", + [MSC_RAW] = "MSC_RAW", + [MSC_SCAN] = "MSC_SCAN", +}; + +const char *leds[LED_MAX + 1] = { + [0 ... LED_MAX] = NULL, + [LED_NUML] = "LED_NUML", + [LED_CAPSL] = "LED_CAPSL", + [LED_SCROLLL] = "LED_SCROLLL", + [LED_COMPOSE] = "LED_COMPOSE", + [LED_KANA] = "LED_KANA", + [LED_SLEEP] = "LED_SLEEP", + [LED_SUSPEND] = "LED_SUSPEND", + [LED_MUTE] = "LED_MUTE", + [LED_MISC] = "LED_MISC", + +}; + +const char *repeats[REP_MAX + 1] = { + [0 ... REP_MAX] = NULL, + [REP_DELAY] = "REP_DELAY", + [REP_PERIOD] = "REP_PERIOD" +}; + +const char *sounds[SND_MAX + 1] = { + [0 ... SND_MAX] = NULL, + [SND_CLICK] = "SND_CLICK", + [SND_BELL] = "SND_BELL", + [SND_TONE] = "SND_TONE" +}; + +const char **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, +}; + +char *absval[6] = { "abs-value", + "abs-min", + "abs-max", + "abs-fuzz", + "abs-flat", + "abs-resolution" +}; + +static int print_capabilities(int fd, xmlTextWriterPtr writer) +{ + + int rc, i; + unsigned long bit[EV_MAX][NBITS(KEY_MAX)]; + unsigned int abs[6]; + char buffer[64]; + + memset(bit, 0, sizeof(bit)); + call(ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0])); + + for (i = 0; i < EV_MAX; i++) + { + if (test_bit(i, bit[0])) + { + int j; + start(BAD_CAST "event-type"); + sprintf(buffer, "%s", events[i]); + attr(BAD_CAST "type", BAD_CAST buffer); + if (!i) + { + end(); + continue; + } + ioctl(fd, EVIOCGBIT(i, KEY_MAX), bit[i]); + for (j = 0; j < KEY_MAX; j++) + { + if (test_bit(j, bit[i])) + { + start(BAD_CAST "code"); + sprintf(buffer, "%s", (names[i] && names[i][j]) ? names[i][j] : "?"); + attr(BAD_CAST "value", BAD_CAST + buffer) + + if (i == EV_ABS) { + int k; + ioctl(fd, EVIOCGABS(j), abs); + for (k = 0; k < sizeof(abs)/sizeof(abs[0]); k++) + { + sprintf(buffer, "%d", abs[k]); + attr(BAD_CAST + absval[k], + BAD_CAST + buffer); + } + /*format(BAD_CAST + * absval[k], + * "%d", + * abs[k]);*/ + } + end("code"); + } + } + end("event-type"); + } + } + + return 0; +error: + return -1; +} + +static int print_info(int fd, xmlTextWriterPtr writer) +{ + unsigned short id[4]; + char name[256] = "---"; + char buffer[64]; + int rc; + + call(ioctl(fd, EVIOCGID, id)); + call(ioctl(fd, EVIOCGNAME(sizeof(name)), name)); + + start(BAD_CAST "info"); + start(BAD_CAST "id"); + sprintf(buffer, "%#x", id[ID_BUS]); + attr(BAD_CAST "bus", BAD_CAST buffer); + sprintf(buffer, "%#x", id[ID_VENDOR]); + attr(BAD_CAST "vendor", BAD_CAST buffer); + sprintf(buffer, "%#x", id[ID_PRODUCT]); + attr(BAD_CAST "product", BAD_CAST buffer); + sprintf(buffer, "%#x", id[ID_VERSION]); + attr(BAD_CAST "version", BAD_CAST buffer); + xmlTextWriterWriteFormatString(writer, "%s", name); + end("id"); + call(print_capabilities(fd, writer)); + end("info"); + + printf("Capturing device '%s'.\n", name); + + return 0; +error: + return -1; +} + +static int init_xml(xmlTextWriterPtr *writer, const char *outfile) +{ + LIBXML_TEST_VERSION + + *writer = xmlNewTextWriterFilename(outfile, 0); + if (!*writer) + return -1; + + xmlTextWriterSetIndent(*writer, 1); + xmlTextWriterSetIndentString(*writer, BAD_CAST " "); + return xmlTextWriterStartDocument(*writer, NULL, MY_ENCODING, NULL); +} + +static void fini_xml(xmlTextWriterPtr writer) +{ + xmlTextWriterEndDocument(writer); + xmlCleanupParser(); +} + +static void sig_handler(int signal) +{ + stop = 1; + printf("Stopping.\n"); + return; +} + +static int print_events(int fd, xmlTextWriterPtr writer) +{ + int rc; + struct input_event ev; + start(BAD_CAST "events"); + char buffer[64]; + + struct sigaction sigact = { + .sa_handler = sig_handler, + }; + + sigemptyset(&sigact.sa_mask); + sigact.sa_flags = 0; + sigaction(SIGINT, &sigact, &sigact); + + + printf("Press Ctrl+C to stop.\n"); + while(!stop) + { + rc = read(fd, &ev, sizeof(struct input_event)); + if (rc < sizeof(ev)) + goto error; + + start(BAD_CAST "event"); + sprintf(buffer, "%ld", ev.time.tv_sec); + attr(BAD_CAST "sec", BAD_CAST buffer); + sprintf(buffer, "%ld", ev.time.tv_usec); + attr(BAD_CAST "usec", BAD_CAST buffer); + sprintf(buffer, "%s", (events[ev.type]) ? events[ev.type] : "?"); + attr(BAD_CAST "type", BAD_CAST buffer); + sprintf(buffer, "%s", (names[ev.type] && names[ev.type][ev.code]) ? names[ev.type][ev.code] : "?"); + attr(BAD_CAST "code", BAD_CAST buffer); + sprintf(buffer, "%d", ev.value); + attr(BAD_CAST "value", BAD_CAST buffer); + end("event"); + } + + sigaction(SIGINT, &sigact, &sigact); + + end("events"); + return 0; +error: + sigaction(SIGINT, &sigact, &sigact); + perror("Read error: \n"); + return -1; +} + + +#define DEV_INPUT_EVENT "/dev/input" +#define EVENT_DEV_NAME "event" + + +/* filter for the AutoDevProbe scandir on /dev/input */ +static int EventDevOnly(const struct dirent *dir) { + return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0; +} + +/* Scans all /dev/input/event* and returns the number of the one to open */ +static int scan_devices(void) +{ + struct dirent **namelist; + int i, ndev, devnum; + + ndev = scandir(DEV_INPUT_EVENT, &namelist, EventDevOnly, alphasort); + if (ndev <= 0) + return -1; + + printf("Available devices:\n"); + + for (i = 0; i < ndev; i++) + { + char fname[64]; + int fd = -1; + char name[256] = "???"; + + sprintf(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); + + printf("%s: %s\n", fname, name); + close(fd); + free(namelist[i]); + } + + printf("Select the device event number [0-%d]: ", ndev - 1); + scanf("%d", &devnum); + + if (devnum >= ndev || devnum < 0) + return -1; + + return devnum; +} + +static void usage(void) +{ + printf("Usage: evtest-capture /dev/input/eventX [evtest-capture.xml]\n"); + printf("Where X = input device number and\n"); + printf("outfile.xml is the output file. Default: evtest-capture.xml\n\n"); +} + +int main(int argc, char **argv) +{ + int fd = 0; + int rc; + char *outfile = "evtest-capture.xml"; + char infile[64]; + + xmlTextWriterPtr writer = NULL; + + if (argc < 2) { + int dev; + + if (getuid() != 0) + printf("Not running as root, no devices may be available.\n"); + + dev = scan_devices(); + if (dev == -1) + { + usage(); + return 1; + } + + sprintf(infile, "%s/%s%d", DEV_INPUT_EVENT, EVENT_DEV_NAME, dev); + } else + strcpy(infile, argv[1]); + + if ((fd = open(infile, O_RDONLY)) < 0) + goto error; + + if (argc >= 3) + outfile = argv[2]; + + printf("Writing to '%s'\n", outfile); + + init_xml(&writer, outfile); + + start(BAD_CAST "evtest-capture"); + + call(print_info(fd, writer)); + call(print_events(fd, writer)); + + end("evtest-capture"); + fini_xml(writer); + return 0; + +error: + if (writer) + xmlTextWriterEndDocument(writer); + xmlCleanupParser(); + perror("Failed with error"); + return 1; +} + +/* vim: set noexpandtab shiftwidth=8: */ diff --git a/evtest-create-device.xsl b/evtest-create-device.xsl new file mode 100644 index 0000000..8f9d83d --- /dev/null +++ b/evtest-create-device.xsl @@ -0,0 +1,212 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + Copyright (c) 2009 Red Hat, Inc. + + 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 + --> + +<!-- use this file with xsltproc evtest-replace.xml <input.xml> + where <input.xml> is the xml file generated by evtest-capture. + --> + +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <xsl:output method="text" indent="yes" encoding="UTF-8"/> + + + <xsl:template match="/evtest-capture"> + <![CDATA[ +/* + Copyright (c) 2009 Red Hat, Inc. + + 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 <stdio.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <linux/input.h> +#include <linux/uinput.h> +#include <dlfcn.h> + +static int fd = -1; + +static void send_event(int fd, int type, int code, int value, int sec, int usec); + +static int setup(struct uinput_user_dev *dev, int fd) +{ +]]> +<xsl:apply-templates select="info/id"/> +<xsl:apply-templates select="info/event-type"/> +<![CDATA[ + + return 0; +error: + perror("ioctl failed."); + return -1; +} + +static int run(int fd) +{ +]]> +<xsl:apply-templates select="events"/> +<![CDATA[ + return 0; +} + +static int init_uinput() +{ + struct uinput_user_dev dev; + + fd = open("/dev/input/uinput", O_RDWR); + if (fd < 0) + goto error; + + memset(&dev, 0, sizeof(dev)); + setup(&dev, fd); + + if (write(fd, &dev, sizeof(dev)) < sizeof(dev)) + goto error; + if (ioctl(fd, UI_DEV_CREATE, NULL) == -1) goto error; + + return 0; + +error: + fprintf(stderr, "Error: %s\n", strerror(errno)); + + if (fd != -1) + close(fd); + + return -1; +} + +static void cleanup_uinput(void) +{ + if (fd == -1) + return; + + ioctl(fd, UI_DEV_DESTROY, NULL); + close(fd); + fd = -1; +} + +static void send_event(int fd, int type, int code, int value, int sec, int usec) +{ + static int sec_offset = -1; + static long last_time = -1; + long newtime; + struct input_event event; + + event.type = type; + event.code = code; + event.value = value; + + if (sec_offset == -1) + sec_offset = sec; + + sec -= sec_offset; + newtime = sec * 1000000 + usec; + + if (last_time > 0) + usleep(newtime - last_time); + + if (write(fd, &event, sizeof(event)) < sizeof(event)) + perror("Send event failed."); + + last_time = newtime; +} + +int main (int argc, char **argv) +{ + if (init_uinput() < 0) { + fprintf(stderr, + "Failed to initialize /dev/input/uinput. Exiting.\n"); + return -1; + } + + printf("Device created. Press CTRL+C to terminate.\n"); + run(fd); + + cleanup_uinput(); + + return 0; +} +]]> + </xsl:template> + + <!-- Setup the required uinput bits to make the device look real + The funky comments at the start of the lines are just to improve + the output indenting. + --> + <xsl:template match="event-type"> + if (ioctl(fd, UI_SET_EVBIT, <xsl:value-of select="@type"/>) == -1) goto error; +<!-- --><xsl:for-each select="code"> + <xsl:choose> + <xsl:when test="../@type = 'EV_KEY'"> + if (ioctl(fd, UI_SET_KEYBIT, <xsl:value-of select="@value"/>) == -1) goto error; +<!-- --></xsl:when> + <xsl:when test="../@type = 'EV_REL'"> + if (ioctl(fd, UI_SET_RELBIT, <xsl:value-of select="@value"/>) == -1) goto error; +<!-- --></xsl:when> + <xsl:when test="../@type = 'EV_MSC'"> + if (ioctl(fd, UI_SET_MSCBIT, <xsl:value-of select="@value"/>) == -1) goto error; +<!-- --></xsl:when> + <xsl:when test="../@type = 'EV_ABS'"> + if (ioctl(fd, UI_SET_ABSBIT, <xsl:value-of select="@value"/>) == -1) goto error; + else { + int idx = <xsl:value-of select="@value"/>; + dev->absmin[idx] = <xsl:value-of select="@abs-min"/>; + dev->absmax[idx] = <xsl:value-of select="@abs-max"/>; + dev->absfuzz[idx] = <xsl:value-of select="@abs-fuzz"/>; + dev->absflat[idx] = <xsl:value-of select="@abs-flat"/>; + + if (dev->absmin[idx] == dev->absmax[idx]) + dev->absmax[idx]++; + } +<!-- --></xsl:when> + </xsl:choose> + </xsl:for-each> + </xsl:template> + + <xsl:template match="id"> + strcpy(dev->name, "<xsl:value-of select="."/>"); + dev->id.bustype = <xsl:value-of select="@bus"/>; + dev->id.vendor = <xsl:value-of select="@vendor"/>; + dev->id.product = <xsl:value-of select="@product"/>; + dev->id.version = <xsl:value-of select="@version"/>; + </xsl:template> + + <!-- code replaying the events --> + <xsl:template match="events"> + <xsl:for-each select="event"> + send_event(fd, <xsl:value-of select="@type"/>, <xsl:value-of select="@code"/>, <xsl:value-of select="@value"/>, <xsl:value-of select="@sec"/>, <xsl:value-of select="@usec"/>);</xsl:for-each> + </xsl:template> + +</xsl:stylesheet> + |