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.
1296 lines
39 KiB
1296 lines
39 KiB
5 years ago
|
/*
|
||
|
* 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: */
|