HotKey Daemon, simple hotkey daemon that woks using the evdev interface
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
hkd/tests/evtest.c

1295 lines
39 KiB

/*
* 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 <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#define _GNU_SOURCE /* for asprintf */
#include <stdio.h>
#include <stdint.h>
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <linux/version.h>
#include <linux/input.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <getopt.h>
#include <ctype.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.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 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;
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
};
#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
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_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 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
#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
};
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;
char *filename;
int max_device = 0;
ndev = scandir(DEV_INPUT_EVENT, &namelist, is_event_device, versionsort);
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);
sscanf(namelist[i]->d_name, "event%d", &devnum);
if (devnum > max_device)
max_device = devnum;
free(namelist[i]);
}
fprintf(stderr, "Select the device event number [0-%d]: ", max_device);
scanf("%d", &devnum);
if (devnum > max_device || 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 "<version undefined>"
#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 <type> <value>\n",
program_invocation_short_name);
printf("\n");
printf("<type> is one of: EV_KEY, EV_SW, EV_LED, EV_SND\n");
printf("<value> 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
/**
* 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)];
#ifdef INPUT_PROP_SEMI_MT
unsigned int prop;
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 (type = 0; type < EV_MAX; type++) {
if (test_bit(type, bit[0]) && type != EV_REP) {
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])) {
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: */