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