Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
78 changes: 39 additions & 39 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:

<keys>:<event type>:<attributes>:<command>

The <keys> 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 <keys> 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 <event type> string field is a comma or whitespace separated list of the
Expand All @@ -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 <command> 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
Expand Down Expand Up @@ -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 <platform>.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 <platform>.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.


Expand Down
128 changes: 98 additions & 30 deletions actkbd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -47,19 +59,32 @@ static int usage() {
"actkbd Version %s\n"
"Usage: actkbd [options]\n"
" Options are as follows:\n"
" -c, --config <file> Specify the configuration file to use\n"
" -D, --daemon Launch in daemon mode\n"
" -d, --device <device> Specify the device to use\n"
" -h, --help Show this help text\n"
" -n, --noexec Do not execute any commands\n"
" -p, --pidfile <file> 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 <file> Specify the configuration file to use\n"
" -D, --daemon Launch in daemon mode\n"
" -d, --device <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 <file> 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;
Expand Down Expand Up @@ -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 }
Expand All @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -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))
{
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}
Loading