/* * Copyright (c) 1999-2000 Vojtech Pavlik * Copyright (c) 2009-2011 Red Hat, Inc */ /** * @file * Event device test program * * evtest prints the capabilities on the kernel devices in /dev/input/eventX * and their events. Its primary purpose is for kernel or X driver * debugging. * * See INSTALL for installation details or manually compile with * gcc -o evtest evtest.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 #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_MAX #define SYN_MAX 3 #define SYN_CNT (SYN_MAX + 1) #endif #ifndef SYN_MT_REPORT #define SYN_MT_REPORT 2 #endif #ifndef SYN_DROPPED #define SYN_DROPPED 3 #endif #define NAME_ELEMENT(element) [element] = #element enum evtest_mode { MODE_CAPTURE, MODE_QUERY, 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) }, }; static int grab_flag = 0; static volatile sig_atomic_t stop = 0; #ifndef program_invocation_short_name static char* program_invocation_short_name = "evtest"; #endif static void interrupt_handler(int sig) { stop = 1; } /** * 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), }; static const int maxval[EV_MAX + 1] = { [0 ... EV_MAX] = -1, [EV_SYN] = SYN_MAX, [EV_KEY] = KEY_MAX, [EV_REL] = REL_MAX, [EV_ABS] = ABS_MAX, [EV_MSC] = MSC_MAX, [EV_SW] = SW_MAX, [EV_LED] = LED_MAX, [EV_SND] = SND_MAX, [EV_REP] = REP_MAX, [EV_FF] = FF_MAX, [EV_FF_STATUS] = FF_STATUS_MAX, }; #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), #ifdef INPUT_PROP_TOPBUTTONPAD NAME_ELEMENT(INPUT_PROP_TOPBUTTONPAD), #endif #ifdef INPUT_PROP_POINTING_STICK NAME_ELEMENT(INPUT_PROP_POINTING_STICK), #endif #ifdef INPUT_PROP_ACCELEROMETER NAME_ELEMENT(INPUT_PROP_ACCELEROMETER), #endif }; #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), #ifdef KEY_SPELLCHECK NAME_ELEMENT(KEY_SPELLCHECK), #endif #ifdef KEY_LOGOFF NAME_ELEMENT(KEY_LOGOFF), #endif #ifdef KEY_DOLLAR NAME_ELEMENT(KEY_DOLLAR), #endif #ifdef KEY_EURO NAME_ELEMENT(KEY_EURO), #endif #ifdef KEY_FRAMEBACK NAME_ELEMENT(KEY_FRAMEBACK), #endif #ifdef KEY_FRAMEFORWARD NAME_ELEMENT(KEY_FRAMEFORWARD), #endif #ifdef KEY_CONTEXT_MENU NAME_ELEMENT(KEY_CONTEXT_MENU), #endif #ifdef KEY_MEDIA_REPEAT NAME_ELEMENT(KEY_MEDIA_REPEAT), #endif #ifdef KEY_10CHANNELSUP NAME_ELEMENT(KEY_10CHANNELSUP), #endif #ifdef KEY_10CHANNELSDOWN NAME_ELEMENT(KEY_10CHANNELSDOWN), #endif #ifdef KEY_IMAGES NAME_ELEMENT(KEY_IMAGES), #endif 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), #ifdef KEY_NUMERIC_0 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), #endif #ifdef KEY_NUMERIC_11 NAME_ELEMENT(KEY_NUMERIC_11), NAME_ELEMENT(KEY_NUMERIC_12), #endif NAME_ELEMENT(KEY_BATTERY), NAME_ELEMENT(KEY_BLUETOOTH), NAME_ELEMENT(KEY_BRIGHTNESS_CYCLE), NAME_ELEMENT(KEY_BRIGHTNESS_ZERO), #ifdef KEY_DASHBOARD NAME_ELEMENT(KEY_DASHBOARD), #endif 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), #ifdef KEY_SCALE NAME_ELEMENT(KEY_SCALE), #endif NAME_ELEMENT(KEY_SEND), NAME_ELEMENT(KEY_SCREENLOCK), NAME_ELEMENT(KEY_SWITCHVIDEOMODE), #ifdef KEY_UWB NAME_ELEMENT(KEY_UWB), #endif #ifdef KEY_VIDEO_NEXT NAME_ELEMENT(KEY_VIDEO_NEXT), #endif #ifdef KEY_VIDEO_PREV NAME_ELEMENT(KEY_VIDEO_PREV), #endif #ifdef KEY_WIMAX NAME_ELEMENT(KEY_WIMAX), #endif #ifdef KEY_WLAN NAME_ELEMENT(KEY_WLAN), #endif #ifdef KEY_RFKILL NAME_ELEMENT(KEY_RFKILL), #endif #ifdef KEY_MICMUTE NAME_ELEMENT(KEY_MICMUTE), #endif #ifdef KEY_CAMERA_FOCUS NAME_ELEMENT(KEY_CAMERA_FOCUS), #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 #ifdef KEY_CAMERA_ZOOMIN NAME_ELEMENT(KEY_CAMERA_ZOOMIN), NAME_ELEMENT(KEY_CAMERA_ZOOMOUT), NAME_ELEMENT(KEY_CAMERA_UP), NAME_ELEMENT(KEY_CAMERA_DOWN), NAME_ELEMENT(KEY_CAMERA_LEFT), NAME_ELEMENT(KEY_CAMERA_RIGHT), #endif #ifdef KEY_ATTENDANT_ON NAME_ELEMENT(KEY_ATTENDANT_ON), NAME_ELEMENT(KEY_ATTENDANT_OFF), NAME_ELEMENT(KEY_ATTENDANT_TOGGLE), NAME_ELEMENT(KEY_LIGHTS_TOGGLE), #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_C), #ifdef BTN_SOUTH NAME_ELEMENT(BTN_SOUTH), NAME_ELEMENT(BTN_EAST), NAME_ELEMENT(BTN_NORTH), NAME_ELEMENT(BTN_WEST), #else NAME_ELEMENT(BTN_A), NAME_ELEMENT(BTN_B), NAME_ELEMENT(BTN_X), NAME_ELEMENT(BTN_Y), #endif 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), #ifdef BTN_TOOL_QUADTAP NAME_ELEMENT(BTN_TOOL_QUADTAP), #endif NAME_ELEMENT(BTN_GEAR_DOWN), NAME_ELEMENT(BTN_GEAR_UP), #ifdef BTN_DPAD_UP NAME_ELEMENT(BTN_DPAD_UP), NAME_ELEMENT(BTN_DPAD_DOWN), NAME_ELEMENT(BTN_DPAD_LEFT), NAME_ELEMENT(BTN_DPAD_RIGHT), #endif #ifdef KEY_ALS_TOGGLE NAME_ELEMENT(KEY_ALS_TOGGLE), #endif #ifdef KEY_BUTTONCONFIG NAME_ELEMENT(KEY_BUTTONCONFIG), #endif #ifdef KEY_TASKMANAGER NAME_ELEMENT(KEY_TASKMANAGER), #endif #ifdef KEY_JOURNAL NAME_ELEMENT(KEY_JOURNAL), #endif #ifdef KEY_CONTROLPANEL NAME_ELEMENT(KEY_CONTROLPANEL), #endif #ifdef KEY_APPSELECT NAME_ELEMENT(KEY_APPSELECT), #endif #ifdef KEY_SCREENSAVER NAME_ELEMENT(KEY_SCREENSAVER), #endif #ifdef KEY_VOICECOMMAND NAME_ELEMENT(KEY_VOICECOMMAND), #endif #ifdef KEY_ASSISTANT NAME_ELEMENT(KEY_ASSISTANT), #endif #ifdef KEY_BRIGHTNESS_MIN NAME_ELEMENT(KEY_BRIGHTNESS_MIN), #endif #ifdef KEY_BRIGHTNESS_MAX NAME_ELEMENT(KEY_BRIGHTNESS_MAX), #endif #ifdef KEY_KBDINPUTASSIST_PREV NAME_ELEMENT(KEY_KBDINPUTASSIST_PREV), #endif #ifdef KEY_KBDINPUTASSIST_NEXT NAME_ELEMENT(KEY_KBDINPUTASSIST_NEXT), #endif #ifdef KEY_KBDINPUTASSIST_PREVGROUP NAME_ELEMENT(KEY_KBDINPUTASSIST_PREVGROUP), #endif #ifdef KEY_KBDINPUTASSIST_NEXTGROUP NAME_ELEMENT(KEY_KBDINPUTASSIST_NEXTGROUP), #endif #ifdef KEY_KBDINPUTASSIST_ACCEPT NAME_ELEMENT(KEY_KBDINPUTASSIST_ACCEPT), #endif #ifdef KEY_KBDINPUTASSIST_CANCEL NAME_ELEMENT(KEY_KBDINPUTASSIST_CANCEL), #endif #ifdef KEY_RIGHT_UP NAME_ELEMENT(KEY_RIGHT_UP), NAME_ELEMENT(KEY_RIGHT_DOWN), NAME_ELEMENT(KEY_LEFT_UP), NAME_ELEMENT(KEY_LEFT_DOWN), #endif #ifdef KEY_ROOT_MENU NAME_ELEMENT(KEY_ROOT_MENU), NAME_ELEMENT(KEY_MEDIA_TOP_MENU), NAME_ELEMENT(KEY_AUDIO_DESC), NAME_ELEMENT(KEY_3D_MODE), NAME_ELEMENT(KEY_NEXT_FAVORITE), NAME_ELEMENT(KEY_STOP_RECORD), NAME_ELEMENT(KEY_PAUSE_RECORD), NAME_ELEMENT(KEY_VOD), NAME_ELEMENT(KEY_UNMUTE), NAME_ELEMENT(KEY_FASTREVERSE), NAME_ELEMENT(KEY_SLOWREVERSE), #endif #ifdef KEY_DATA NAME_ELEMENT(KEY_DATA), #endif #ifdef KEY_ONSCREEN_KEYBOARD NAME_ELEMENT(KEY_ONSCREEN_KEYBOARD), #endif #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), #ifdef REL_WHEEL_HI_RES NAME_ELEMENT(REL_WHEEL_HI_RES), NAME_ELEMENT(REL_HWHEEL_HI_RES), #endif }; 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 #ifdef ABS_MT_TOOL_X NAME_ELEMENT(ABS_MT_TOOL_X), NAME_ELEMENT(ABS_MT_TOOL_Y), NAME_ELEMENT(ABS_MT_DISTANCE), #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), #ifdef MSC_TIMESTAMP NAME_ELEMENT(MSC_TIMESTAMP), #endif }; 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), #ifdef LED_MAIL NAME_ELEMENT(LED_MAIL), #endif #ifdef LED_CHARGING NAME_ELEMENT(LED_CHARGING), #endif }; 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[SYN_MAX + 1] = { [0 ... SYN_MAX] = NULL, NAME_ELEMENT(SYN_REPORT), NAME_ELEMENT(SYN_CONFIG), NAME_ELEMENT(SYN_MT_REPORT), NAME_ELEMENT(SYN_DROPPED) }; 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), #ifdef SW_RFKILL_ALL NAME_ELEMENT(SW_RFKILL_ALL), #endif #ifdef SW_MICROPHONE_INSERT NAME_ELEMENT(SW_MICROPHONE_INSERT), #endif #ifdef SW_DOCK NAME_ELEMENT(SW_DOCK), #endif #ifdef SW_LINEOUT_INSERT NAME_ELEMENT(SW_LINEOUT_INSERT), #endif #ifdef SW_JACK_PHYSICAL_INSERT NAME_ELEMENT(SW_JACK_PHYSICAL_INSERT), #endif #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 #ifdef SW_LINEIN_INSERT NAME_ELEMENT(SW_LINEIN_INSERT), #endif #ifdef SW_MUTE_DEVICE NAME_ELEMENT(SW_MUTE_DEVICE), #endif #ifdef SW_PEN_INSERTED NAME_ELEMENT(SW_PEN_INSERTED), #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] = syns, [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, match; char *filename; int max_device = 0; 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); match = sscanf(namelist[i]->d_name, "event%d", &devnum); if (match >= 1 && devnum > max_device) max_device = devnum; free(namelist[i]); } fprintf(stderr, "Select the device event number [0-%d]: ", max_device); match = scanf("%d", &devnum); if (match < 1 || devnum > max_device || devnum < 0) return NULL; if (asprintf(&filename, "%s/%s%d", DEV_INPUT_EVENT, EVENT_DEV_NAME, devnum) < 0) return NULL; 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(" Capture mode:\n"); printf(" %s [--grab] /dev/input/eventX\n", program_invocation_short_name); printf(" --grab grab the device for exclusive access\n"); printf("\n"); printf(" Query mode: (check exit code)\n"); printf(" %s --query /dev/input/eventX \n", program_invocation_short_name); printf("\n"); printf(" is one of: EV_KEY, EV_SW, EV_LED, EV_SND\n"); printf(" can either be a numerical value, or the textual name of the\n"); printf("key/switch/LED/sound being queried (e.g. SW_DOCK).\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]); } static void print_repdata(int fd) { int i; unsigned int rep[2]; ioctl(fd, EVIOCGREP, rep); for (i = 0; i <= REP_MAX; i++) { printf(" Repeat code %d (%s)\n", i, names[EV_REP] ? (names[EV_REP][i] ? names[EV_REP][i] : "?") : "?"); printf(" Value %6d\n", rep[i]); } } static inline const char* typename(unsigned int type) { return (type <= EV_MAX && events[type]) ? events[type] : "?"; } static inline const char* codename(unsigned int type, unsigned int code) { return (type <= EV_MAX && code <= maxval[type] && names[type] && names[type][code]) ? names[type][code] : "?"; } #ifdef INPUT_PROP_SEMI_MT static inline const char* propname(unsigned int prop) { return (prop <= INPUT_PROP_MAX && props[prop]) ? props[prop] : "?"; } #endif static int get_state(int fd, unsigned int type, unsigned long *array, size_t size) { int rc; switch(type) { case EV_LED: rc = ioctl(fd, EVIOCGLED(size), array); break; case EV_SND: rc = ioctl(fd, EVIOCGSND(size), array); break; case EV_SW: rc = ioctl(fd, EVIOCGSW(size), array); break; case EV_KEY: /* intentionally not printing the value for EV_KEY, let the * repeat handle this */ default: return 1; } if (rc == -1) return 1; return 0; } /** * 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) { unsigned int type, code; int version; unsigned short id[4]; char name[256] = "Unknown"; unsigned long bit[EV_MAX][NBITS(KEY_MAX)]; unsigned long state[KEY_CNT] = {0}; #ifdef INPUT_PROP_SEMI_MT unsigned int prop; unsigned long propbits[INPUT_PROP_MAX]; #endif int stateval; int have_state; 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 (type = 0; type < EV_MAX; type++) { if (test_bit(type, bit[0]) && type != EV_REP) { have_state = (get_state(fd, type, state, sizeof(state)) == 0); printf(" Event type %d (%s)\n", type, typename(type)); if (type == EV_SYN) continue; ioctl(fd, EVIOCGBIT(type, KEY_MAX), bit[type]); for (code = 0; code < KEY_MAX; code++) if (test_bit(code, bit[type])) { if (have_state) { stateval = test_bit(code, state); printf(" Event code %d (%s) state %d\n", code, codename(type, code), stateval); } else { printf(" Event code %d (%s)\n", code, codename(type, code)); } if (type == EV_ABS) print_absdata(fd, code); } } } if (test_bit(EV_REP, bit[0])) { printf("Key repeat handling:\n"); printf(" Repeat type %d (%s)\n", EV_REP, events[EV_REP] ? events[EV_REP] : "?"); print_repdata(fd); } #ifdef INPUT_PROP_SEMI_MT memset(propbits, 0, sizeof(propbits)); ioctl(fd, EVIOCGPROP(sizeof(propbits)), propbits); printf("Properties:\n"); for (prop = 0; prop < INPUT_PROP_MAX; prop++) { if (test_bit(prop, propbits)) printf(" Property type %d (%s)\n", prop, propname(prop)); } #endif return 0; } /** * Print device events as they come in. * * @param fd The file descriptor to the device. * @return 0 on success or 1 otherwise. */ static int print_events(int fd) { struct input_event ev[64]; int i, rd; fd_set rdfs; FD_ZERO(&rdfs); FD_SET(fd, &rdfs); while (!stop) { select(fd + 1, &rdfs, NULL, NULL, NULL); if (stop) break; rd = read(fd, ev, sizeof(ev)); 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++) { unsigned int type, code; type = ev[i].type; code = ev[i].code; printf("Event: time %ld.%06ld, ", ev[i].time.tv_sec, ev[i].time.tv_usec); if (type == EV_SYN) { if (code == SYN_MT_REPORT) printf("++++++++++++++ %s ++++++++++++\n", codename(type, code)); else if (code == SYN_DROPPED) printf(">>>>>>>>>>>>>> %s <<<<<<<<<<<<\n", codename(type, code)); else printf("-------------- %s ------------\n", codename(type, code)); } else { printf("type %d (%s), code %d (%s), ", type, typename(type), code, codename(type, code)); if (type == EV_MSC && (code == MSC_RAW || code == MSC_SCAN)) printf("value %02x\n", ev[i].value); else printf("value %d\n", ev[i].value); } } } ioctl(fd, EVIOCGRAB, (void*)0); return EXIT_SUCCESS; } /** * 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 grab_flag) { int rc; rc = ioctl(fd, EVIOCGRAB, (void*)1); if (rc == 0 && !grab_flag) 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 grab_flag) { int fd; char *filename = NULL; 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); goto error; } if (!isatty(fileno(stdout))) setbuf(stdout, NULL); if (print_device_info(fd)) goto error; printf("Testing ... (interrupt to exit)\n"); if (test_grab(fd, grab_flag)) { 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(" Run the following command to see processes with\n" " an open fd on this device\n" " \"fuser -v %s\"\n", filename); printf("***********************************************\n"); } signal(SIGINT, interrupt_handler); signal(SIGTERM, interrupt_handler); free(filename); return print_events(fd); error: free(filename); return EXIT_FAILURE; } /** * Perform a one-shot state query on a specific device. The query can be of * any known mode, on any valid keycode. * * @param device Path to the evdev device node that should be queried. * @param query_mode The event type that is being queried (e.g. key, switch) * @param keycode The code of the key/switch/sound/LED to be queried * @return 0 if the state bit is unset, 10 if the state bit is set, 1 on error. */ static int query_device(const char *device, const struct query_mode *query_mode, int keycode) { int fd; int r; unsigned long state[NBITS(query_mode->max)]; fd = open(device, O_RDONLY); if (fd < 0) { perror("open"); return EXIT_FAILURE; } memset(state, 0, sizeof(state)); r = ioctl(fd, query_mode->rq, state); close(fd); if (r == -1) { perror("ioctl"); return EXIT_FAILURE; } if (test_bit(keycode, state)) return 10; /* different from EXIT_FAILURE */ else return 0; } /** * Enter query mode. The requested event device will be queried for the state * of a particular switch/key/sound/LED. * * @param device The device to query. * @param mode The mode (event type) that is to be queried (snd, sw, key, led) * @param keycode The key code to query the state of. * @return 0 if the state bit is unset, 10 if the state bit is set. */ static int do_query(const char *device, const char *event_type, const char *keyname) { const struct query_mode *query_mode; int keycode; if (!device) { fprintf(stderr, "Device argument is required for query.\n"); return usage(); } query_mode = find_query_mode(event_type); if (!query_mode) { fprintf(stderr, "Unrecognised event type: %s\n", event_type); return usage(); } keycode = get_keycode(query_mode, keyname); if (keycode < 0) { fprintf(stderr, "Unrecognised key name: %s\n", keyname); return usage(); } else if (keycode > query_mode->max) { fprintf(stderr, "Key %d is out of bounds.\n", keycode); return EXIT_FAILURE; } return query_device(device, query_mode, keycode); } static const struct option long_options[] = { { "grab", no_argument, &grab_flag, 1 }, { "query", no_argument, NULL, MODE_QUERY }, { "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 0: break; case MODE_QUERY: mode = c; break; case MODE_VERSION: return version(); default: return usage(); } } if (optind < argc) device = argv[optind++]; if (mode == MODE_CAPTURE) return do_capture(device, grab_flag); if ((argc - optind) < 2) { fprintf(stderr, "Query mode requires device, type and key parameters\n"); return usage(); } event_type = argv[optind++]; keyname = argv[optind++]; return do_query(device, event_type, keyname); } /* vim: set noexpandtab tabstop=8 shiftwidth=8: */