diff --git a/Makefile b/Makefile index 6ff035a..93c3a06 100644 --- a/Makefile +++ b/Makefile @@ -18,14 +18,14 @@ VER := $(shell head -n 1 NEWS | cut -d : -f 1) DEBUG := -CFLAGS := -O2 -Wall $(DEBUG) +CFLAGS := -O3 -Wall $(DEBUG) CPPFLAGS := -DVERSION=\"$(VER)\" -DCONFIG=\"$(sysconfdir)/actkbd.conf\" - +#-D__float128="long double" all: actkbd -actkbd: actkbd.o mask.o config.o linux.o +actkbd: actkbd.o mask.o config.o linux.o inputtables.o actkbd.o : actkbd.h mask.o : actkbd.h diff --git a/README b/README index c4fe349..6b78618 100644 --- a/README +++ b/README @@ -20,13 +20,13 @@ Contents: 1. Introduction -actkbd is a simple daemon that binds actions to keyboard events. It recognises -key combinations and can handle press, repeat and release events. Currently it -only supports the linux-2.6 evdev interface, but the platform-specific code is -well-contained, so that support for additional platforms can be added with no or +actkbd is a simple daemon that binds actions to keyboard events. It recognises +key combinations and can handle press, repeat and release events. Currently it +only supports the linux-2.6 evdev interface, but the platform-specific code is +well-contained, so that support for additional platforms can be added with no or minimal changes to the rest of the code. -It uses a plain-text configuration file which contains all the bindings. Its +It uses a plain-text configuration file which contains all the bindings. Its file format has some prediction for command attributes, which allow the user to perform some common actions (e.g. eject the CD-ROM or change the volume) without having to call external commands. Currently, though, actkbd can only execute @@ -56,7 +56,7 @@ The following platforms will probably never be supported: * Linux 2.6.x -To run actkbd under Linux 2.6.x you need to have the event interface available. +To run actkbd under Linux 2.6.x you need to have the event interface available. In most cases, loading the `evdev' kernel module will be sufficient: # modprobe evdev @@ -90,38 +90,38 @@ A simple call to `make' is normally all you need to compile actkbd: $ make -To change the default location of the configuration file, you have to override -the sysconfdir Makefile variable. You can also override the CFLAGS variable to -provide optimisation flags e.t.c. The DEBUG variable can be used to enable +To change the default location of the configuration file, you have to override +the sysconfdir Makefile variable. You can also override the CFLAGS variable to +provide optimisation flags e.t.c. The DEBUG variable can be used to enable debugging - if you are using gcc, setting DEBUG to "-g" would probably do. 3.2. Installation -First verify with `make -n install' the installation paths. By default, the -installation prefix is /usr/local and the actkbd daemon binary is installed in -$(prefix)/sbin. A configuration placeholder is placed in $(sysconfdir), which by -default is /etc. You can set the prefix, sbindir and sysconfdir variables to -override these defaults. Then run `make install' as root to perform the actual +First verify with `make -n install' the installation paths. By default, the +installation prefix is /usr/local and the actkbd daemon binary is installed in +$(prefix)/sbin. A configuration placeholder is placed in $(sysconfdir), which by +default is /etc. You can set the prefix, sbindir and sysconfdir variables to +override these defaults. Then run `make install' as root to perform the actual installation: # make install -Bear in mind that currently the location of the configuration file must be -explicitly specified (-c) in the actkbd command line options if the default +Bear in mind that currently the location of the configuration file must be +explicitly specified (-c) in the actkbd command line options if the default ($(sysconfdir)/actkbd.conf) location is not valid. 3.3. Configuration -The default configuration file resides in $(sysconfdir)/actkbd.conf. It is a -plain-text file with each line being an entry. A proper entry has the following +The default configuration file resides in $(sysconfdir)/actkbd.conf. It is a +plain-text file with each line being an entry. A proper entry has the following format: ::: -The field is a series of numeric keycodes, separated by the `+' -character. `actkbd -n -s' can be used to find out any keycodes you need, as it +The field is a series of numeric keycodes, separated by the `+' +character. `actkbd -n -s' can be used to find out any keycodes you need, as it will report all key presses without executing any commands. The string field is a comma or whitespace separated list of the @@ -136,14 +136,14 @@ attribute actions are executed in the listed order. If no attribute has been specified actkbd falls back on to calling system(). The field is the executed command that will be passed to system(). -Note that in order to have non-blocking behaviour, you have to append the `&' +Note that in order to have non-blocking behaviour, you have to append the `&' character to the command, so that /bin/sh will execute it in the background. Also keep in mind that the listed command attributes can affect the way the command is executed, if at all. Currently system() is the only interpretter for commands, but in the future there may be command attributes that use the contents of this field differently, e.g. to set a sound mixer. -Lines starting with '#' are considered comments. Invalid lines are silently +Lines starting with '#' are considered comments. Invalid lines are silently ignored, unless a high enough verbosity level has been specified. Note that when actkbd searches for an entry to execute, only the first matching @@ -287,41 +287,41 @@ NOTE: You will have to use some other way to find what LED codes your keyboard 3.4. Running -Run `actkbd --help' to see the various command line options. actkbd is normally -able to auto-detect your keyboard device, therefore you do not need to specify -it. For the most common case - a daemon with the default configuration file in +Run `actkbd --help' to see the various command line options. actkbd is normally +able to auto-detect your keyboard device, therefore you do not need to specify +it. For the most common case - a daemon with the default configuration file in $(sysconfdir) - the following command should suffice: # actkbd -D -q -Note that sending the HUP signal (kill -HUP) to actkbd will cause it to reload +Note that sending the HUP signal (kill -HUP) to actkbd will cause it to reload its configuration file. 4. Internals -The most interesting/messy part of actkbd is the code that keeps track of which -keys are pressed each moment. It uses a bitmask with one bit for each available -key. When press/repeat events are received, the corresponding bit is set and it -becomes unset when a release event is received for that key. To match key events -with the corresponding actions, each valid configuration file entry has its key -field transformed to a bitmask. After that, whenever a new event is received, -the status bitmask is matched against all configuration entry bitmasks and the +The most interesting/messy part of actkbd is the code that keeps track of which +keys are pressed each moment. It uses a bitmask with one bit for each available +key. When press/repeat events are received, the corresponding bit is set and it +becomes unset when a release event is received for that key. To match key events +with the corresponding actions, each valid configuration file entry has its key +field transformed to a bitmask. After that, whenever a new event is received, +the status bitmask is matched against all configuration entry bitmasks and the first one to match (if any) is used and the corresponding command is executed. -Please note that the platform specific code is contained in .c (.e.g. -linux.c). This file implements a generic interface to keyboard events, hiding -each system's intricacies from the rest of code. It is also the file that has to +Please note that the platform specific code is contained in .c (.e.g. +linux.c). This file implements a generic interface to keyboard events, hiding +each system's intricacies from the rest of code. It is also the file that has to be written/ported to add support for a new platform. -For any additional details the best documentation is probalby the source code +For any additional details the best documentation is probalby the source code itself. 5. License -actkbd is released under the GNU General Public License version 2. The full text -of the license can be found in the COPYING file that should be included in the +actkbd is released under the GNU General Public License version 2. The full text +of the license can be found in the COPYING file that should be included in the actkbd distribution. diff --git a/actkbd.c b/actkbd.c index 0d71eaa..4702c04 100644 --- a/actkbd.c +++ b/actkbd.c @@ -17,6 +17,18 @@ int verbose = 0; /* Daemon mode */ int detach = 0; +/* Unix util mode */ +int showkey = 0; + +/* Keyboard polling mode */ +int kpoll = 0; + +/* Numeric scancode flag. */ +int num = 0; + +/* Tickrate for polling mode */ +int tickrate = 60; + /* Console message suppression */ int quiet = 0; @@ -47,19 +59,32 @@ static int usage() { "actkbd Version %s\n" "Usage: actkbd [options]\n" " Options are as follows:\n" - " -c, --config Specify the configuration file to use\n" - " -D, --daemon Launch in daemon mode\n" - " -d, --device Specify the device to use\n" - " -h, --help Show this help text\n" - " -n, --noexec Do not execute any commands\n" - " -p, --pidfile Use a file to store the PID\n" - " -q, --quiet Suppress all console messages\n" - " -v[level]\n" - " --verbose=[level] Specify the verbosity level (0-9)\n" - " -V, --version Show version information\n" - " -x, --showexec Report executed commands\n" - " -s, --showkey Report key presses\n" - " -l, --syslog Use the syslog facilities for logging\n" + " -c, --config Specify the configuration file to use\n" + " -D, --daemon Launch in daemon mode\n" + " -d, --device Specify the device to use\n" + " -h, --help Show this help text\n" + " -N, --numeric Display numeric key codes, instead\n" + " of the names of key codes.\n" + " -n, --noexec Do not execute any commands\n" + " -P, --poll Enable keyboard polling mode.\n" + " -p, --pidfile Use a file to store the PID\n" + " -q, --quiet Suppress all console messages\n" + " -v[level]\n" + " --verbose=[level] Specify the verbosity level (0-9)\n" + " -V, --version Show version information\n" + " -x, --showexec Report executed commands\n" + " -t[delay]\n" + " --tickrate=[delay] Set tickrate\n" + " (in ticks per second) for polling mode.\n" + " -s, --showkey Output key presses to stdout\n" + " (Output is designed to\n" + " be easily parsable.\n" + " Useful for shell\n" + " scripts, and other\n" + " general purpose use cases).\n" + "\n" + "\n" + " -l, --syslog Use the syslog facilities for logging\n" , VERSION); return OK; @@ -151,23 +176,27 @@ static int ext_exec(char *cmd, int noexec, int showexec) { int main(int argc, char **argv) { - int ret, key, type; + int ret, key, type, value; + struct timeval time; key_cmd *cmd; /* Options */ - int help = 0, noexec = 0, version = 0, showexec = 0, showkey = 0; + int help = 0, noexec = 0, version = 0, showexec = 0; struct option options[] = { { "config", required_argument, 0, 'c' }, { "daemon", no_argument, 0, 'D' }, { "device", required_argument, 0, 'd' }, { "help", no_argument, 0, 'h' }, + { "numeric", no_argument, 0, 'N' }, { "noexec", no_argument, 0, 'n' }, + { "poll", no_argument, 0, 'P' }, { "pidfile", required_argument, 0, 'p' }, { "quiet", no_argument, 0, 'q' }, { "verbose", optional_argument, 0, 'v' }, { "version", no_argument, 0, 'V' }, { "showexec", no_argument, 0, 'x' }, + { "tickrate", optional_argument, 0, 't' }, { "showkey", no_argument, 0, 's' }, { "syslog", no_argument, 0, 'l' }, { 0, 0, 0, 0 } @@ -176,7 +205,7 @@ int main(int argc, char **argv) { while (1) { int c, option_index = 0; - c = getopt_long (argc, argv, "c:Dd:hp:qnv::Vxsl", options, &option_index); + c = getopt_long (argc, argv, "c:Dd:hPp:qNnt::v::Vxsl", options, &option_index); if (c == -1) break; @@ -203,9 +232,15 @@ int main(int argc, char **argv) { case 'h': help = 1; break; + case 'N': + num = 1; + break; case 'n': noexec = 1; break; + case 'P': + kpoll = 1; + break; case 'p': if (optarg) { pidfile = strdup(optarg); @@ -234,7 +269,18 @@ int main(int argc, char **argv) { case 'x': showexec = 1; break; + case 't': + if (optarg) { + tickrate = atoi(optarg); + if (tickrate <= -1) + tickrate = 0; + } else { + tickrate = 60; + } + case 's': + detach = 0; + noexec = 1; showkey = 1; break; case 'l': @@ -290,10 +336,6 @@ int main(int argc, char **argv) { if ((ret = open_dev()) != OK) return ret; - /* Verbosity levels over 2 make showkey redundant */ - if (verbose > 2) - showkey = 0; - if (detach) { switch (daemon(0, 0)) { @@ -314,21 +356,14 @@ int main(int argc, char **argv) { signal(SIGHUP, on_hup); signal(SIGTERM, on_term); - while (get_key(&key, &type) == OK) { + while (get_key(&key, &type, &value, &time, tickrate, kpoll, num) == OK) { int tmp, exec_ok = 0, norel = 0; if ((type & (KEY | REP)) != 0) set_key_bit(key, 1); - if (verbose > 2) { - lprintf("Event: "); - lprint_key_mask(); - lprintf(":%s\n", (type == KEY)?"key":((type == REP)?"rep":"rel")); - } - if ((type == KEY) && showkey) { - lprintf("Keys: "); - lprint_key_mask(); - lprintf("\n"); + if (showkey) { + printkeys(time, key, value); } ret = match_key(type, &cmd); @@ -451,3 +486,36 @@ int lprintf(const char *fmt, ...) { return ret; } + +/* Key printing function */ +void printkeys(struct timeval time, int key, int value) { + int printable = 0, plus = 0, gbg = 0, nums = 0; + char *keys = malloc(sizeof(char)*2048 + 1); + print_key_mask(keys, 1); + for (int i = 0; i < strlen(keys); ++i) { + if (isdigit(keys[i])) + ++nums; + else if (keys[i] == '+') + plus = 1; + else + gbg = 1; + + } + printable = ((nums || plus) && !gbg) ? 1 : 0; + if(printable) { + printf("%lu.%06lu %s %i\n", time.tv_sec, time.tv_usec, keys, value); + fflush(stdout); + } + free(keys); +} + +/* Formatted string concatenation function */ +void strfcat(char *src, char *fmt, ...) { + char buf[2048]; + va_list args; + va_start(args,fmt); + vsprintf(buf, fmt, args); + va_end(args); + + strcat(src, buf); +} diff --git a/actkbd.h b/actkbd.h index 835ca59..28b5b03 100644 --- a/actkbd.h +++ b/actkbd.h @@ -23,11 +23,16 @@ #include #include #include +#include +#include +#include #include #define UNUSED 0 +/* Convert macro name into string */ +#define MACSTR(tok) #tok /* Event types */ #define INVALID 0 @@ -47,6 +52,9 @@ extern int verbose; /* Maximum number of keys */ extern int maxkey; +/* Unix util mode */ +extern int showkey; + /* Device grab state */ extern int grabbed; @@ -60,6 +68,12 @@ extern char *config; /* Logging function */ int lprintf(const char *fmt, ...); +/* Key printing function */ +void printkeys(struct timeval time, int key, int value); + +/* Formatted string concatenation function */ +void strfcat(char *src, char *fmt, ...); + /* Device initialisation */ int init_dev(); @@ -76,7 +90,7 @@ int grab_dev(); int ungrab_dev(); /* Keyboard event receiver function */ -int get_key(int *key, int *type); +int get_key(int *key, int *type, int *value, struct timeval *time, int tickrate, int poll, int num); /* Send an event to the input layer */ int snd_key(int key, int type); @@ -84,6 +98,8 @@ int snd_key(int key, int type); /* Set a keyboard LED */ int set_led(int led, int on); +/* Convert keycode value, to a string with the keycodes name. */ +extern const char *keycodetostr(int type, int code, int numeric); /* Key mask handling */ int get_masksize(); @@ -99,8 +115,10 @@ void clear_key_mask(); int set_key_bit(int bit, int val); int get_key_bit(int bit); int cmp_key_mask(unsigned char *mask0, unsigned int attr); -int lprint_key_mask_delim(char c); +int lprint_key_mask_delim(); +int sprint_key_mask_delim(unsigned char *c, char d, char *str, int numeric); int lprint_key_mask(); +int print_key_mask(char *str, int numeric); unsigned char *get_key_mask(); /* The ignored key mask */ diff --git a/inputtables.c b/inputtables.c new file mode 100644 index 0000000..b8c53de --- /dev/null +++ b/inputtables.c @@ -0,0 +1,723 @@ +/* + * Get a keycodes macro name, from the value of the macro. + * + * Platform: GNU/Linux + * Author: mr b0nk 500 + * + * Notes: Why would you turn a keyboard daemon, into a Unix utility? + * Created: September 2, 2019 @ 10:47PM + */ + +#include +#include +#include + +#define ELEMENT(NAME) [NAME] = #NAME + +static const char *evnames[EV_CNT] = { + [EV_SYN] = "SYN", + [EV_KEY] = "KEY", + [EV_REL] = "REL", + [EV_ABS] = "ABS", + [EV_MSC] = "MSC", + [EV_SW] = "SW", + [EV_LED] = "LED", + [EV_SND] = "SND", + [EV_REP] = "REP", + [EV_FF] = "FF", + [EV_PWR] = "PWR", +}; + +#ifndef SYN_CNT +#define SYN_CNT 4 +#endif +static const char *synnames[SYN_CNT] = { + ELEMENT(SYN_REPORT), + ELEMENT(SYN_CONFIG), + ELEMENT(SYN_MT_REPORT), + ELEMENT(SYN_DROPPED), +}; + +static const char *keynames[KEY_CNT] = { + ELEMENT(KEY_RESERVED), + ELEMENT(KEY_ESC), + ELEMENT(KEY_1), + ELEMENT(KEY_2), + ELEMENT(KEY_3), + ELEMENT(KEY_4), + ELEMENT(KEY_5), + ELEMENT(KEY_6), + ELEMENT(KEY_7), + ELEMENT(KEY_8), + ELEMENT(KEY_9), + ELEMENT(KEY_0), + ELEMENT(KEY_MINUS), + ELEMENT(KEY_EQUAL), + ELEMENT(KEY_BACKSPACE), + ELEMENT(KEY_TAB), + ELEMENT(KEY_Q), + ELEMENT(KEY_W), + ELEMENT(KEY_E), + ELEMENT(KEY_R), + ELEMENT(KEY_T), + ELEMENT(KEY_Y), + ELEMENT(KEY_U), + ELEMENT(KEY_I), + ELEMENT(KEY_O), + ELEMENT(KEY_P), + ELEMENT(KEY_LEFTBRACE), + ELEMENT(KEY_RIGHTBRACE), + ELEMENT(KEY_ENTER), + ELEMENT(KEY_LEFTCTRL), + ELEMENT(KEY_A), + ELEMENT(KEY_S), + ELEMENT(KEY_D), + ELEMENT(KEY_F), + ELEMENT(KEY_G), + ELEMENT(KEY_H), + ELEMENT(KEY_J), + ELEMENT(KEY_K), + ELEMENT(KEY_L), + ELEMENT(KEY_SEMICOLON), + ELEMENT(KEY_APOSTROPHE), + ELEMENT(KEY_GRAVE), + ELEMENT(KEY_LEFTSHIFT), + ELEMENT(KEY_BACKSLASH), + ELEMENT(KEY_Z), + ELEMENT(KEY_X), + ELEMENT(KEY_C), + ELEMENT(KEY_V), + ELEMENT(KEY_B), + ELEMENT(KEY_N), + ELEMENT(KEY_M), + ELEMENT(KEY_COMMA), + ELEMENT(KEY_DOT), + ELEMENT(KEY_SLASH), + ELEMENT(KEY_RIGHTSHIFT), + ELEMENT(KEY_KPASTERISK), + ELEMENT(KEY_LEFTALT), + ELEMENT(KEY_SPACE), + ELEMENT(KEY_CAPSLOCK), + ELEMENT(KEY_F1), + ELEMENT(KEY_F2), + ELEMENT(KEY_F3), + ELEMENT(KEY_F4), + ELEMENT(KEY_F5), + ELEMENT(KEY_F6), + ELEMENT(KEY_F7), + ELEMENT(KEY_F8), + ELEMENT(KEY_F9), + ELEMENT(KEY_F10), + ELEMENT(KEY_NUMLOCK), + ELEMENT(KEY_SCROLLLOCK), + ELEMENT(KEY_KP7), + ELEMENT(KEY_KP8), + ELEMENT(KEY_KP9), + ELEMENT(KEY_KPMINUS), + ELEMENT(KEY_KP4), + ELEMENT(KEY_KP5), + ELEMENT(KEY_KP6), + ELEMENT(KEY_KPPLUS), + ELEMENT(KEY_KP1), + ELEMENT(KEY_KP2), + ELEMENT(KEY_KP3), + ELEMENT(KEY_KP0), + ELEMENT(KEY_KPDOT), + + ELEMENT(KEY_ZENKAKUHANKAKU), + ELEMENT(KEY_102ND), + ELEMENT(KEY_F11), + ELEMENT(KEY_F12), + ELEMENT(KEY_RO), + ELEMENT(KEY_KATAKANA), + ELEMENT(KEY_HIRAGANA), + ELEMENT(KEY_HENKAN), + ELEMENT(KEY_KATAKANAHIRAGANA), + ELEMENT(KEY_MUHENKAN), + ELEMENT(KEY_KPJPCOMMA), + ELEMENT(KEY_KPENTER), + ELEMENT(KEY_RIGHTCTRL), + ELEMENT(KEY_KPSLASH), + ELEMENT(KEY_SYSRQ), + ELEMENT(KEY_RIGHTALT), + ELEMENT(KEY_LINEFEED), + ELEMENT(KEY_HOME), + ELEMENT(KEY_UP), + ELEMENT(KEY_PAGEUP), + ELEMENT(KEY_LEFT), + ELEMENT(KEY_RIGHT), + ELEMENT(KEY_END), + ELEMENT(KEY_DOWN), + ELEMENT(KEY_PAGEDOWN), + ELEMENT(KEY_INSERT), + ELEMENT(KEY_DELETE), + ELEMENT(KEY_MACRO), + ELEMENT(KEY_MUTE), + ELEMENT(KEY_VOLUMEDOWN), + ELEMENT(KEY_VOLUMEUP), + ELEMENT(KEY_POWER), + ELEMENT(KEY_KPEQUAL), + ELEMENT(KEY_KPPLUSMINUS), + ELEMENT(KEY_PAUSE), + ELEMENT(KEY_SCALE), + + ELEMENT(KEY_KPCOMMA), + ELEMENT(KEY_HANGEUL), + ELEMENT(KEY_HANGUEL), + ELEMENT(KEY_HANJA), + ELEMENT(KEY_YEN), + ELEMENT(KEY_LEFTMETA), + ELEMENT(KEY_RIGHTMETA), + ELEMENT(KEY_COMPOSE), + + ELEMENT(KEY_STOP), + ELEMENT(KEY_AGAIN), + ELEMENT(KEY_PROPS), + ELEMENT(KEY_UNDO), + ELEMENT(KEY_FRONT), + ELEMENT(KEY_COPY), + ELEMENT(KEY_OPEN), + ELEMENT(KEY_PASTE), + ELEMENT(KEY_FIND), + ELEMENT(KEY_CUT), + ELEMENT(KEY_HELP), + ELEMENT(KEY_MENU), + ELEMENT(KEY_CALC), + ELEMENT(KEY_SETUP), + ELEMENT(KEY_SLEEP), + ELEMENT(KEY_WAKEUP), + ELEMENT(KEY_FILE), + ELEMENT(KEY_SENDFILE), + ELEMENT(KEY_DELETEFILE), + ELEMENT(KEY_XFER), + ELEMENT(KEY_PROG1), + ELEMENT(KEY_PROG2), + ELEMENT(KEY_WWW), + ELEMENT(KEY_MSDOS), + ELEMENT(KEY_COFFEE), + ELEMENT(KEY_SCREENLOCK), + ELEMENT(KEY_DIRECTION), + ELEMENT(KEY_CYCLEWINDOWS), + ELEMENT(KEY_MAIL), + ELEMENT(KEY_BOOKMARKS), + ELEMENT(KEY_COMPUTER), + ELEMENT(KEY_BACK), + ELEMENT(KEY_FORWARD), + ELEMENT(KEY_CLOSECD), + ELEMENT(KEY_EJECTCD), + ELEMENT(KEY_EJECTCLOSECD), + ELEMENT(KEY_NEXTSONG), + ELEMENT(KEY_PLAYPAUSE), + ELEMENT(KEY_PREVIOUSSONG), + ELEMENT(KEY_STOPCD), + ELEMENT(KEY_RECORD), + ELEMENT(KEY_REWIND), + ELEMENT(KEY_PHONE), + ELEMENT(KEY_ISO), + ELEMENT(KEY_CONFIG), + ELEMENT(KEY_HOMEPAGE), + ELEMENT(KEY_REFRESH), + ELEMENT(KEY_EXIT), + ELEMENT(KEY_MOVE), + ELEMENT(KEY_EDIT), + ELEMENT(KEY_SCROLLUP), + ELEMENT(KEY_SCROLLDOWN), + ELEMENT(KEY_KPLEFTPAREN), + ELEMENT(KEY_KPRIGHTPAREN), + ELEMENT(KEY_NEW), + ELEMENT(KEY_REDO), + + ELEMENT(KEY_F13), + ELEMENT(KEY_F14), + ELEMENT(KEY_F15), + ELEMENT(KEY_F16), + ELEMENT(KEY_F17), + ELEMENT(KEY_F18), + ELEMENT(KEY_F19), + ELEMENT(KEY_F20), + ELEMENT(KEY_F21), + ELEMENT(KEY_F22), + ELEMENT(KEY_F23), + ELEMENT(KEY_F24), + + ELEMENT(KEY_PLAYCD), + ELEMENT(KEY_PAUSECD), + ELEMENT(KEY_PROG3), + ELEMENT(KEY_PROG4), + ELEMENT(KEY_DASHBOARD), + ELEMENT(KEY_SUSPEND), + ELEMENT(KEY_CLOSE), + ELEMENT(KEY_PLAY), + ELEMENT(KEY_FASTFORWARD), + ELEMENT(KEY_BASSBOOST), + ELEMENT(KEY_PRINT), + ELEMENT(KEY_HP), + ELEMENT(KEY_CAMERA), + ELEMENT(KEY_SOUND), + ELEMENT(KEY_QUESTION), + ELEMENT(KEY_EMAIL), + ELEMENT(KEY_CHAT), + ELEMENT(KEY_SEARCH), + ELEMENT(KEY_CONNECT), + ELEMENT(KEY_FINANCE), + ELEMENT(KEY_SPORT), + ELEMENT(KEY_SHOP), + ELEMENT(KEY_ALTERASE), + ELEMENT(KEY_CANCEL), + ELEMENT(KEY_BRIGHTNESSDOWN), + ELEMENT(KEY_BRIGHTNESSUP), + ELEMENT(KEY_MEDIA), + + ELEMENT(KEY_SWITCHVIDEOMODE), + + ELEMENT(KEY_KBDILLUMTOGGLE), + ELEMENT(KEY_KBDILLUMDOWN), + ELEMENT(KEY_KBDILLUMUP), + + ELEMENT(KEY_SEND), + ELEMENT(KEY_REPLY), + ELEMENT(KEY_FORWARDMAIL), + ELEMENT(KEY_SAVE), + ELEMENT(KEY_DOCUMENTS), + + ELEMENT(KEY_BATTERY), + + ELEMENT(KEY_BLUETOOTH), + ELEMENT(KEY_WLAN), + ELEMENT(KEY_UWB), + + ELEMENT(KEY_UNKNOWN), + + ELEMENT(KEY_VIDEO_NEXT), + ELEMENT(KEY_VIDEO_PREV), + ELEMENT(KEY_BRIGHTNESS_CYCLE), + ELEMENT(KEY_BRIGHTNESS_ZERO), + ELEMENT(KEY_DISPLAY_OFF), + + ELEMENT(KEY_WIMAX), + ELEMENT(KEY_RFKILL), + + ELEMENT(KEY_MICMUTE), + + ELEMENT(BTN_MISC), + ELEMENT(BTN_0), + ELEMENT(BTN_1), + ELEMENT(BTN_2), + ELEMENT(BTN_3), + ELEMENT(BTN_4), + ELEMENT(BTN_5), + ELEMENT(BTN_6), + ELEMENT(BTN_7), + ELEMENT(BTN_8), + ELEMENT(BTN_9), + + ELEMENT(BTN_MOUSE), + ELEMENT(BTN_LEFT), + ELEMENT(BTN_RIGHT), + ELEMENT(BTN_MIDDLE), + ELEMENT(BTN_SIDE), + ELEMENT(BTN_EXTRA), + ELEMENT(BTN_FORWARD), + ELEMENT(BTN_BACK), + ELEMENT(BTN_TASK), + + ELEMENT(BTN_JOYSTICK), + ELEMENT(BTN_TRIGGER), + ELEMENT(BTN_THUMB), + ELEMENT(BTN_THUMB2), + ELEMENT(BTN_TOP), + ELEMENT(BTN_TOP2), + ELEMENT(BTN_PINKIE), + ELEMENT(BTN_BASE), + ELEMENT(BTN_BASE2), + ELEMENT(BTN_BASE3), + ELEMENT(BTN_BASE4), + ELEMENT(BTN_BASE5), + ELEMENT(BTN_BASE6), + ELEMENT(BTN_DEAD), + + ELEMENT(BTN_GAMEPAD), + ELEMENT(BTN_A), + ELEMENT(BTN_B), + ELEMENT(BTN_C), + ELEMENT(BTN_X), + ELEMENT(BTN_Y), + ELEMENT(BTN_Z), + ELEMENT(BTN_TL), + ELEMENT(BTN_TR), + ELEMENT(BTN_TL2), + ELEMENT(BTN_TR2), + ELEMENT(BTN_SELECT), + ELEMENT(BTN_START), + ELEMENT(BTN_MODE), + ELEMENT(BTN_THUMBL), + ELEMENT(BTN_THUMBR), + + ELEMENT(BTN_DIGI), + ELEMENT(BTN_TOOL_PEN), + ELEMENT(BTN_TOOL_RUBBER), + ELEMENT(BTN_TOOL_BRUSH), + ELEMENT(BTN_TOOL_PENCIL), + ELEMENT(BTN_TOOL_AIRBRUSH), + ELEMENT(BTN_TOOL_FINGER), + ELEMENT(BTN_TOOL_MOUSE), + ELEMENT(BTN_TOOL_LENS), + ELEMENT(BTN_TOOL_QUINTTAP), + ELEMENT(BTN_TOUCH), + ELEMENT(BTN_STYLUS), + ELEMENT(BTN_STYLUS2), + ELEMENT(BTN_TOOL_DOUBLETAP), + ELEMENT(BTN_TOOL_TRIPLETAP), + ELEMENT(BTN_TOOL_QUADTAP), + + ELEMENT(BTN_WHEEL), + ELEMENT(BTN_GEAR_DOWN), + ELEMENT(BTN_GEAR_UP), + + ELEMENT(KEY_OK), + ELEMENT(KEY_SELECT), + ELEMENT(KEY_GOTO), + ELEMENT(KEY_CLEAR), + ELEMENT(KEY_POWER2), + ELEMENT(KEY_OPTION), + ELEMENT(KEY_INFO), + ELEMENT(KEY_TIME), + ELEMENT(KEY_VENDOR), + ELEMENT(KEY_ARCHIVE), + ELEMENT(KEY_PROGRAM), + ELEMENT(KEY_CHANNEL), + ELEMENT(KEY_FAVORITES), + ELEMENT(KEY_EPG), + ELEMENT(KEY_PVR), + ELEMENT(KEY_MHP), + ELEMENT(KEY_LANGUAGE), + ELEMENT(KEY_TITLE), + ELEMENT(KEY_SUBTITLE), + ELEMENT(KEY_ANGLE), + ELEMENT(KEY_ZOOM), + ELEMENT(KEY_MODE), + ELEMENT(KEY_KEYBOARD), + ELEMENT(KEY_SCREEN), + ELEMENT(KEY_PC), + ELEMENT(KEY_TV), + ELEMENT(KEY_TV2), + ELEMENT(KEY_VCR), + ELEMENT(KEY_VCR2), + ELEMENT(KEY_SAT), + ELEMENT(KEY_SAT2), + ELEMENT(KEY_CD), + ELEMENT(KEY_TAPE), + ELEMENT(KEY_RADIO), + ELEMENT(KEY_TUNER), + ELEMENT(KEY_PLAYER), + ELEMENT(KEY_TEXT), + ELEMENT(KEY_DVD), + ELEMENT(KEY_AUX), + ELEMENT(KEY_MP3), + ELEMENT(KEY_AUDIO), + ELEMENT(KEY_VIDEO), + ELEMENT(KEY_DIRECTORY), + ELEMENT(KEY_LIST), + ELEMENT(KEY_MEMO), + ELEMENT(KEY_CALENDAR), + ELEMENT(KEY_RED), + ELEMENT(KEY_GREEN), + ELEMENT(KEY_YELLOW), + ELEMENT(KEY_BLUE), + ELEMENT(KEY_CHANNELUP), + ELEMENT(KEY_CHANNELDOWN), + ELEMENT(KEY_FIRST), + ELEMENT(KEY_LAST), + ELEMENT(KEY_AB), + ELEMENT(KEY_NEXT), + ELEMENT(KEY_RESTART), + ELEMENT(KEY_SLOW), + ELEMENT(KEY_SHUFFLE), + ELEMENT(KEY_BREAK), + ELEMENT(KEY_PREVIOUS), + ELEMENT(KEY_DIGITS), + ELEMENT(KEY_TEEN), + ELEMENT(KEY_TWEN), + ELEMENT(KEY_VIDEOPHONE), + ELEMENT(KEY_GAMES), + ELEMENT(KEY_ZOOMIN), + ELEMENT(KEY_ZOOMOUT), + ELEMENT(KEY_ZOOMRESET), + ELEMENT(KEY_WORDPROCESSOR), + ELEMENT(KEY_EDITOR), + ELEMENT(KEY_SPREADSHEET), + ELEMENT(KEY_GRAPHICSEDITOR), + ELEMENT(KEY_PRESENTATION), + ELEMENT(KEY_DATABASE), + ELEMENT(KEY_NEWS), + ELEMENT(KEY_VOICEMAIL), + ELEMENT(KEY_ADDRESSBOOK), + ELEMENT(KEY_MESSENGER), + ELEMENT(KEY_DISPLAYTOGGLE), + ELEMENT(KEY_SPELLCHECK), + ELEMENT(KEY_LOGOFF), + + ELEMENT(KEY_DOLLAR), + ELEMENT(KEY_EURO), + + ELEMENT(KEY_FRAMEBACK), + ELEMENT(KEY_FRAMEFORWARD), + ELEMENT(KEY_CONTEXT_MENU), + ELEMENT(KEY_MEDIA_REPEAT), + ELEMENT(KEY_10CHANNELSUP), + ELEMENT(KEY_10CHANNELSDOWN), + ELEMENT(KEY_IMAGES), + + ELEMENT(KEY_DEL_EOL), + ELEMENT(KEY_DEL_EOS), + ELEMENT(KEY_INS_LINE), + ELEMENT(KEY_DEL_LINE), + + ELEMENT(KEY_FN), + ELEMENT(KEY_FN_ESC), + ELEMENT(KEY_FN_F1), + ELEMENT(KEY_FN_F2), + ELEMENT(KEY_FN_F3), + ELEMENT(KEY_FN_F4), + ELEMENT(KEY_FN_F5), + ELEMENT(KEY_FN_F6), + ELEMENT(KEY_FN_F7), + ELEMENT(KEY_FN_F8), + ELEMENT(KEY_FN_F9), + ELEMENT(KEY_FN_F10), + ELEMENT(KEY_FN_F11), + ELEMENT(KEY_FN_F12), + ELEMENT(KEY_FN_1), + ELEMENT(KEY_FN_2), + ELEMENT(KEY_FN_D), + ELEMENT(KEY_FN_E), + ELEMENT(KEY_FN_F), + ELEMENT(KEY_FN_S), + ELEMENT(KEY_FN_B), + + ELEMENT(KEY_BRL_DOT1), + ELEMENT(KEY_BRL_DOT2), + ELEMENT(KEY_BRL_DOT3), + ELEMENT(KEY_BRL_DOT4), + ELEMENT(KEY_BRL_DOT5), + ELEMENT(KEY_BRL_DOT6), + ELEMENT(KEY_BRL_DOT7), + ELEMENT(KEY_BRL_DOT8), + ELEMENT(KEY_BRL_DOT9), + ELEMENT(KEY_BRL_DOT10), + + ELEMENT(KEY_NUMERIC_0), + ELEMENT(KEY_NUMERIC_1), + ELEMENT(KEY_NUMERIC_2), + ELEMENT(KEY_NUMERIC_3), + ELEMENT(KEY_NUMERIC_4), + ELEMENT(KEY_NUMERIC_5), + ELEMENT(KEY_NUMERIC_6), + ELEMENT(KEY_NUMERIC_7), + ELEMENT(KEY_NUMERIC_8), + ELEMENT(KEY_NUMERIC_9), + ELEMENT(KEY_NUMERIC_STAR), + ELEMENT(KEY_NUMERIC_POUND), + + ELEMENT(KEY_CAMERA_FOCUS), + ELEMENT(KEY_WPS_BUTTON), + + ELEMENT(KEY_TOUCHPAD_TOGGLE), + ELEMENT(KEY_TOUCHPAD_ON), + ELEMENT(KEY_TOUCHPAD_OFF), + + ELEMENT(KEY_CAMERA_ZOOMIN), + ELEMENT(KEY_CAMERA_ZOOMOUT), + ELEMENT(KEY_CAMERA_UP), + ELEMENT(KEY_CAMERA_DOWN), + ELEMENT(KEY_CAMERA_LEFT), + ELEMENT(KEY_CAMERA_RIGHT), + + ELEMENT(BTN_TRIGGER_HAPPY), + ELEMENT(BTN_TRIGGER_HAPPY1), + ELEMENT(BTN_TRIGGER_HAPPY2), + ELEMENT(BTN_TRIGGER_HAPPY3), + ELEMENT(BTN_TRIGGER_HAPPY4), + ELEMENT(BTN_TRIGGER_HAPPY5), + ELEMENT(BTN_TRIGGER_HAPPY6), + ELEMENT(BTN_TRIGGER_HAPPY7), + ELEMENT(BTN_TRIGGER_HAPPY8), + ELEMENT(BTN_TRIGGER_HAPPY9), + ELEMENT(BTN_TRIGGER_HAPPY10), + ELEMENT(BTN_TRIGGER_HAPPY11), + ELEMENT(BTN_TRIGGER_HAPPY12), + ELEMENT(BTN_TRIGGER_HAPPY13), + ELEMENT(BTN_TRIGGER_HAPPY14), + ELEMENT(BTN_TRIGGER_HAPPY15), + ELEMENT(BTN_TRIGGER_HAPPY16), + ELEMENT(BTN_TRIGGER_HAPPY17), + ELEMENT(BTN_TRIGGER_HAPPY18), + ELEMENT(BTN_TRIGGER_HAPPY19), + ELEMENT(BTN_TRIGGER_HAPPY20), + ELEMENT(BTN_TRIGGER_HAPPY21), + ELEMENT(BTN_TRIGGER_HAPPY22), + ELEMENT(BTN_TRIGGER_HAPPY23), + ELEMENT(BTN_TRIGGER_HAPPY24), + ELEMENT(BTN_TRIGGER_HAPPY25), + ELEMENT(BTN_TRIGGER_HAPPY26), + ELEMENT(BTN_TRIGGER_HAPPY27), + ELEMENT(BTN_TRIGGER_HAPPY28), + ELEMENT(BTN_TRIGGER_HAPPY29), + ELEMENT(BTN_TRIGGER_HAPPY30), + ELEMENT(BTN_TRIGGER_HAPPY31), + ELEMENT(BTN_TRIGGER_HAPPY32), + ELEMENT(BTN_TRIGGER_HAPPY33), + ELEMENT(BTN_TRIGGER_HAPPY34), + ELEMENT(BTN_TRIGGER_HAPPY35), + ELEMENT(BTN_TRIGGER_HAPPY36), + ELEMENT(BTN_TRIGGER_HAPPY37), + ELEMENT(BTN_TRIGGER_HAPPY38), + ELEMENT(BTN_TRIGGER_HAPPY39), + ELEMENT(BTN_TRIGGER_HAPPY40), +}; + +static const char *relnames[REL_CNT] = { + ELEMENT(REL_X), + ELEMENT(REL_Y), + ELEMENT(REL_Z), + ELEMENT(REL_RX), + ELEMENT(REL_RY), + ELEMENT(REL_RZ), + ELEMENT(REL_HWHEEL), + ELEMENT(REL_DIAL), + ELEMENT(REL_WHEEL), + ELEMENT(REL_MISC), +}; + +static const char *absnames[ABS_CNT] = { + ELEMENT(ABS_X), + ELEMENT(ABS_Y), + ELEMENT(ABS_Z), + ELEMENT(ABS_RX), + ELEMENT(ABS_RY), + ELEMENT(ABS_RZ), + ELEMENT(ABS_THROTTLE), + ELEMENT(ABS_RUDDER), + ELEMENT(ABS_WHEEL), + ELEMENT(ABS_GAS), + ELEMENT(ABS_BRAKE), + ELEMENT(ABS_HAT0X), + ELEMENT(ABS_HAT0Y), + ELEMENT(ABS_HAT1X), + ELEMENT(ABS_HAT1Y), + ELEMENT(ABS_HAT2X), + ELEMENT(ABS_HAT2Y), + ELEMENT(ABS_HAT3X), + ELEMENT(ABS_HAT3Y), + ELEMENT(ABS_PRESSURE), + ELEMENT(ABS_DISTANCE), + ELEMENT(ABS_TILT_X), + ELEMENT(ABS_TILT_Y), + ELEMENT(ABS_TOOL_WIDTH), + + ELEMENT(ABS_VOLUME), + + ELEMENT(ABS_MISC), + + ELEMENT(ABS_MT_SLOT), + ELEMENT(ABS_MT_TOUCH_MAJOR), + ELEMENT(ABS_MT_TOUCH_MINOR), + ELEMENT(ABS_MT_WIDTH_MAJOR), + ELEMENT(ABS_MT_WIDTH_MINOR), + ELEMENT(ABS_MT_ORIENTATION), + ELEMENT(ABS_MT_POSITION_X), + ELEMENT(ABS_MT_POSITION_Y), + ELEMENT(ABS_MT_TOOL_TYPE), + ELEMENT(ABS_MT_BLOB_ID), + ELEMENT(ABS_MT_TRACKING_ID), + ELEMENT(ABS_MT_PRESSURE), + ELEMENT(ABS_MT_DISTANCE), +}; + +static const char *swnames[SW_CNT] = { + ELEMENT(SW_LID), + ELEMENT(SW_TABLET_MODE), + ELEMENT(SW_HEADPHONE_INSERT), + [SW_RFKILL_ALL] = "SW_RFKILL", + ELEMENT(SW_MICROPHONE_INSERT), + ELEMENT(SW_DOCK), + ELEMENT(SW_LINEOUT_INSERT), + ELEMENT(SW_JACK_PHYSICAL_INSERT), + ELEMENT(SW_VIDEOOUT_INSERT), + ELEMENT(SW_CAMERA_LENS_COVER), + ELEMENT(SW_KEYPAD_SLIDE), + ELEMENT(SW_FRONT_PROXIMITY), + ELEMENT(SW_ROTATE_LOCK), + ELEMENT(SW_LINEIN_INSERT), +}; + +static const char *mscnames[MSC_CNT] = { + ELEMENT(MSC_SERIAL), + ELEMENT(MSC_PULSELED), + ELEMENT(MSC_GESTURE), + ELEMENT(MSC_RAW), + ELEMENT(MSC_SCAN), +}; + +static const char *lednames[LED_CNT] = { + ELEMENT(LED_NUML), + ELEMENT(LED_CAPSL), + ELEMENT(LED_SCROLLL), + ELEMENT(LED_COMPOSE), + ELEMENT(LED_KANA), + ELEMENT(LED_SLEEP), + ELEMENT(LED_SUSPEND), + ELEMENT(LED_MUTE), + ELEMENT(LED_MISC), + ELEMENT(LED_MAIL), + ELEMENT(LED_CHARGING), +}; + +static const char *repnames[REP_CNT] = { + ELEMENT(REP_DELAY), + ELEMENT(REP_PERIOD), +}; + +static const char *sndnames[SND_CNT] = { + ELEMENT(SND_CLICK), + ELEMENT(SND_BELL), + ELEMENT(SND_TONE), +}; + +static const char **typetables[EV_CNT] = { + [EV_SYN] = synnames, + [EV_KEY] = keynames, + [EV_REL] = relnames, + [EV_ABS] = absnames, + [EV_SW] = swnames, + [EV_MSC] = mscnames, + [EV_LED] = lednames, + [EV_REP] = repnames, + [EV_SND] = sndnames, +}; + +#define SIZE(x) (sizeof(x)/sizeof((x)[0])) +static int typemax[EV_CNT] = { + [EV_SYN] = SIZE(synnames), + [EV_KEY] = SIZE(keynames), + [EV_REL] = SIZE(relnames), + [EV_ABS] = SIZE(absnames), + [EV_SW] = SIZE(swnames), + [EV_MSC] = SIZE(mscnames), + [EV_LED] = SIZE(lednames), + [EV_REP] = SIZE(repnames), + [EV_SND] = SIZE(sndnames), +}; + +/* Convert keycode value, to a string with the keycodes name. */ +const char *keycodetostr(int type, int code, int numeric) { + static char buf[32]; + if (type >= EV_CNT) { + sprintf(buf, "#%u:%u", type, code); + return buf; + } + sprintf(buf, "%s_%u", evnames[type], code); + if (numeric || code >= typemax[type]) + return buf; + return (typetables[type])[code] ?: buf; +} diff --git a/linux.c b/linux.c index 51e3529..18f1a85 100644 --- a/linux.c +++ b/linux.c @@ -15,6 +15,7 @@ #include +#define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8))) #define PROCFS "/proc/" #define HANDLERS "bus/input/handlers" #define DEVICES "bus/input/devices" @@ -27,13 +28,20 @@ static char devnode[32]; /* The device file pointer */ static FILE *dev; +/* The device file decriptor */ +static int devfd; + int init_dev() { FILE *fp = NULL; - int ret; - unsigned int u0, u1; + int ret = -1; + unsigned int u0 = 0, u1 = 0; regex_t preg; regmatch_t pmatch[4]; + /*for (int r; r<4; r++) { + pmatch[r].rm_so=0; + pmatch[r].rm_eo=0; + }*/ maxkey = KEY_MAX; @@ -66,16 +74,52 @@ int init_dev() { /* Compile the regular expression and scan for it */ ret = -1; - regcomp(&preg, "^H: Handlers=(.* )?kbd (.* )?event([0-9]+)", REG_EXTENDED); + regcomp(&preg, "^H: Handlers=(.* )?kbd (.* )?event([0-9]+)? leds", REG_EXTENDED); do { char l[128] = ""; void *str = fgets(l, 128, fp); if (str == NULL) break; ret = regexec(&preg, l, 4, pmatch, 0); + /*printf("ret: %i\nu0: %u\n", ret, u0); + printf( + "pmatch[0].rm_so: %li, pmatch[0].rm_eo: %li\n" + "pmatch[1].rm_so: %li, pmatch[1].rm_eo: %li\n" + "pmatch[2].rm_so: %li, pmatch[2].rm_eo: %li\n" + "pmatch[3].rm_so: %li, pmatch[3].rm_eo: %li\n" + "pmatch[4].rm_so: %li, pmatch[4].rm_eo: %li\n" + "pmatch[5].rm_so: %li, pmatch[5].rm_eo: %li\n" + "pmatch[6].rm_so: %li, pmatch[6].rm_eo: %li\n" + "pmatch[7].rm_so: %li, pmatch[7].rm_eo: %li\n" + , pmatch[0].rm_so, pmatch[0].rm_eo + , pmatch[1].rm_so, pmatch[1].rm_eo + , pmatch[2].rm_so, pmatch[2].rm_eo + , pmatch[3].rm_so, pmatch[3].rm_eo); + , pmatch[4].rm_so, pmatch[4].rm_eo + , pmatch[5].rm_so, pmatch[5].rm_eo + , pmatch[6].rm_so, pmatch[6].rm_eo + , pmatch[7].rm_so, pmatch[7].rm_eo);*/ if (ret == 0) { l[pmatch[3].rm_eo] = '\0'; - ret = sscanf(l + pmatch[3].rm_so, "%u", &u0); + ret = sscanf((l+pmatch[3].rm_so), "%u", &u0); + /*printf("ret: %i\nu0: %u\nl+pmatch[3].rm_so: %s\n", ret, u0, l+pmatch[3].rm_so); + printf( + "pmatch[0].rm_so: %li, pmatch[0].rm_eo: %li\n" + "pmatch[1].rm_so: %li, pmatch[1].rm_eo: %li\n" + "pmatch[2].rm_so: %li, pmatch[2].rm_eo: %li\n" + "pmatch[3].rm_so: %li, pmatch[3].rm_eo: %li\n" + "pmatch[4].rm_so: %li, pmatch[4].rm_eo: %li\n" + "pmatch[5].rm_so: %li, pmatch[5].rm_eo: %li\n" + "pmatch[6].rm_so: %li, pmatch[6].rm_eo: %li\n" + "pmatch[7].rm_so: %li, pmatch[7].rm_eo: %li\n" + , pmatch[0].rm_so, pmatch[0].rm_eo + , pmatch[1].rm_so, pmatch[1].rm_eo + , pmatch[2].rm_so, pmatch[2].rm_eo + , pmatch[3].rm_so, pmatch[3].rm_eo); + , pmatch[4].rm_so, pmatch[4].rm_eo + , pmatch[5].rm_so, pmatch[5].rm_eo + , pmatch[6].rm_so, pmatch[6].rm_eo + , pmatch[7].rm_so, pmatch[7].rm_eo);*/ } else { ret = -1; } @@ -99,7 +143,8 @@ int init_dev() { int open_dev() { dev = fopen(device, "a+"); - if (dev == NULL) { + devfd = open(device, O_RDONLY); + if (dev == NULL || devfd == -1) { lprintf("Error: could not open %s: %s\n", device, strerror(errno)); return DEVFAIL; } @@ -109,6 +154,7 @@ int open_dev() { int close_dev() { fclose(dev); + close(devfd); return OK; } @@ -124,7 +170,7 @@ int grab_dev() { grabbed = 1; else lprintf("Error: could not grab %s: %s\n", device, strerror(errno)); - + return ret; } @@ -140,47 +186,79 @@ int ungrab_dev() { grabbed = 0; else lprintf("Error: could not ungrab %s: %s\n", device, strerror(errno)); - + return ret; } -int get_key(int *key, int *type) { +int get_key(int *key, int *type, int *value, struct timeval *time, int tickrate, int poll, int num) { struct input_event ev; - int ret; - - do { - ret = fread(&ev, sizeof(ev), 1, dev); - if (ret < 1) { - lprintf("Error: failed to read event from %s: %s", device, strerror(errno)); - return READERR; + int ret, ticks = 0, keydown = 0; + /* Poll for keypresses */ + if(poll) { + if (!ticks) + printf("Tickrate: %i\n", tickrate); + while (1) { + printf("%i ", ticks++); + u_int8_t key_b[KEY_MAX/8 + 1]; + memset(key_b, 0, sizeof(key_b)); + ioctl(devfd, EVIOCGKEY(sizeof(key_b)), key_b); + int keycount = 0; + for (int yalv = 0; yalv < KEY_MAX; yalv++) { + if (test_bit(yalv, key_b)) { + ++keycount; + /* the bit is set in the key state */ + if (keycount > 1) + (!num) ? printf("+%s", keycodetostr(EV_KEY, yalv, 0)) : printf("+%i", yalv); + else if (keycount == 1) { + (!num) ? printf("%s", keycodetostr(EV_KEY, yalv, 0)) : printf("%i", yalv); + } + } + keydown = keycount ? 1 : 0; + } + if (!keydown) + printf("%s %i", (!num) ? "KEY_NONE" : "0", keydown); + else + printf(" %i", keydown); + printf("\n"); + fflush(stdout); + float tickdely = (float)1/tickrate; + usleep((useconds_t)(tickdely*1000000)); + } + /* Wait for an input event */ + } else { + do { + ret = fread(&ev, sizeof(ev), 1, dev); + if (ret < 1) { + lprintf("Error: failed to read event from %s: %s", device, strerror(errno)); + return READERR; + } + } while (ev.type != EV_KEY); + *key = ev.code; + *time = ev.time; + *value = ev.value; + switch (ev.value) { + case 0: + *type = REL; + break; + case 1: + *type = KEY; + break; + case 2: + *type = REP; + break; + default: + *type = KEY; } - } while (ev.type != EV_KEY); - - *key = ev.code; - switch (ev.value) { - case 0: - *type = REL; - break; - case 1: - *type = KEY; - break; - case 2: - *type = REP; - break; - default: + if (*key > KEY_MAX) *type = INVALID; - } - - if (*key > KEY_MAX) - *type = INVALID; - if (*type == INVALID) { - lprintf("Error: invalid event read from %s: code = %u, value = %u", device, ev.code, ev.value); - return EVERR; + if (*type == INVALID) { + lprintf("Error: invalid event read from %s: code = %u, value = %u", device, ev.code, ev.value); + return EVERR; + } } - return OK; } diff --git a/mask.c b/mask.c index e81801d..7fa4757 100644 --- a/mask.c +++ b/mask.c @@ -141,11 +141,37 @@ static int lprint_mask_delim(unsigned char *mask, char d) { } return OK; } +/* Print a key mask to a string */ +static int sprint_mask_delim(unsigned char *mask, char d, char *str, int numeric) { + int i = 0, c = 0; + + if (mask == NULL) { + lprintf("Error: attempt to dereference NULL mask pointer\n"); + return INTERR; + } + + for (i = 0; i <= maxkey; ++i) { + if (get_bit(mask, i)) { + ++c; + if (c > 1) + strfcat(str,"%c%i", d, i/*keycodetostr(1, i, numeric*)*/); + else + sprintf(str,"%i", i/*keycodetostr(1, i, numeric)*/); + } + } + + return OK; +} + int lprint_mask(unsigned char *mask) { return lprint_mask_delim(mask, '+'); } +int sprint_mask(unsigned char *mask, char *str, int numeric) { + return sprint_mask_delim(mask, '+', str, numeric); +} + /* Use a A+B+N... string to initialise a key mask */ int strmask(unsigned char **mask, char *keys) { @@ -221,8 +247,8 @@ int lprint_key_mask_delim(char d) { } #endif -int lprint_key_mask() { - return lprint_mask(mask); +int print_key_mask(char *str, int numeric) { + return sprint_mask(mask, str, numeric); }