inputlirc-23/0000700000175100001440000000000012111433375012202 5ustar guususersinputlirc-23/ChangeLog0000600000175100001440000001334012111433375013757 0ustar guususerscommit 95e620a7f245cca550b20c9da66fba38125b0790 Author: Guus Sliepen Date: Thu Feb 21 15:58:18 2013 +0100 Honour $CPPFLAGS and $LDFLAGS. commit 81a9275a8345c934ec0b3e6424562520a7b71cd4 Author: Guus Sliepen Date: Tue Oct 2 13:09:35 2012 +0200 Query type of input event device, and only accept those that send EV_KEY events. commit 2c683d7153ceb1ee11be497b70001d79ab62b04f Author: Guus Sliepen Date: Tue Oct 2 13:08:40 2012 +0200 Don't add input event devices to the list that cannot be read. This fixes a crash caused by FD_SET() not liking a negative file descriptor. So also added a check right before FD_SET() just in case. commit 3de9078edb670481d06968935062efb2a5a46285 Author: Guus Sliepen Date: Tue Oct 2 13:05:03 2012 +0200 Send log messages to stderr when not detached. commit 4d6c054dab4d3ab80a00db69f8cce4b89bf75caa Author: Guus Sliepen Date: Thu May 19 21:40:04 2011 +0200 Apply patch from Piotr Dlugosz making inputlircd robust against disappearing event devices. Date: Sun, 10 Apr 2011 17:15:44 +0200 From: Piotr Subject: Patch to make inputlircd crash proof I have the DVB card which sometimes crashes unfortunately. This card I'm using also for the remote control. When it crashes, the inputlirc goes down. It is not a problem to restart inputlirc but then I have to restart also other applications. I made small changes to the code: - Do not exit if there is a problem reading event device, just remember it was disconnected. - Every 30 secs when there is no activity try to reopen disconnected device (done via select timeout). commit 0b3c3318ae4cbb04ce199d21dccaa4c01a475325 Author: Guus Sliepen Date: Thu May 19 21:23:04 2011 +0200 The lircd socket has moved to /var/run/lirc/lircd. commit 5ba6206fa936fc558a19e76a82d7150620aca60c Author: Guus Sliepen Date: Mon Nov 1 14:02:24 2010 +0100 Apply patch from Oliver Tscherwitschke fixing repeat flag. This prevents inputlirc from setting the repeat flag when different keys are pressed shortly after each other. commit ac6b3c967e75be478afd191a5268df34ab5e6bc0 Author: Guus Sliepen Date: Sun Jan 24 15:54:40 2010 +0100 Allow selecting input event devices by symbolic name. The -n option can be used to match devices by name. It allows wildcard patterns to be used. commit 59a20817200a59b585967ad8d04b38dc3576ab28 Author: Guus Sliepen Date: Wed Jul 29 13:02:31 2009 +0000 Apply slightly modified patch from David Härdeman adding a translation table. This allows keys to be given a different name, for example if one has an existing LIRC setup and one doesn't want to change all the client configurations. commit f9961a607ef50a5eabdc1f667dbb8a5fcdf08470 Author: Guus Sliepen Date: Sat Jun 27 13:50:13 2009 +0000 Reverse the order of initialisation of KEY_NAME[]. This ensures keys which have more than one name to be reported as the first name found in input.h, instead of as one of their aliases. This fixes KEY_MUTE being reported as KEY_MIN_INTERESTING. Thanks to David Härdeman for spotting. commit 02feeef291df56fbdfd21904878156c91e8cb8fb Author: Guus Sliepen Date: Thu Sep 25 16:02:00 2008 +0000 Strip comments from names.h, sometimes they are not properly terminated. commit 16cbcf0672fe0a02951e91830f9c3a5450b7f0de Author: Guus Sliepen Date: Thu Sep 25 16:01:37 2008 +0000 Apply patch from Ben Lings adding support for modifiers and repetition. commit 6fdb6225746bbaf711e62b2decfae76235d40818 Author: Guus Sliepen Date: Thu Apr 27 19:11:35 2006 +0000 Allow input devices to be grabbed for exclusive access (patch from Ian Campbell). Also remove input.h and use /usr/include/linux/input.h directly. commit 71f57409885ff775eaa766990fccc3d84d6acb66 Author: Guus Sliepen Date: Fri Feb 24 20:01:19 2006 +0000 Fix typo in manpage. commit 1b938b5b3a0fa870c5fb8d3e8f59fff264a53018 Author: Guus Sliepen Date: Fri Feb 24 20:01:07 2006 +0000 Fix removal of clients. commit 2a7f159a05366f26723e33397209b64cbbb7db57 Author: Guus Sliepen Date: Mon Feb 6 21:53:57 2006 +0000 Fixed adding elements to linked lists. commit 7d22428d38bd82463d60059dbee033fe215c330b Author: Guus Sliepen Date: Mon Feb 6 21:53:35 2006 +0000 Missing $SHAREDIR, default PREFIX is /usr/local. commit c0462e4af98ac403943a7059285df25277a6e7e4 Author: Guus Sliepen Date: Mon Feb 6 19:11:37 2006 +0000 Parse options: minimum keycode to send, userid to change to, unix socket name to create, whether to daemonize or not. commit 3369c69fbbc7f3a570446db941944ea7032dd8f5 Author: Guus Sliepen Date: Mon Feb 6 17:13:36 2006 +0000 Filter keycodes < 128. commit 9aa0afa411a41e9e4df8487337d7a9d3d821d556 Author: Guus Sliepen Date: Mon Feb 6 16:53:05 2006 +0000 Better version, read from multiple event devices, write to multiple clients. Manpage added. commit 457dc42732cfac6d3794c75c2114127e01d63490 Author: Guus Sliepen Date: Mon Feb 6 15:44:27 2006 +0000 License notification. commit 787712ec2af218d3b5d281753ad24a5be9fed0b1 Author: Guus Sliepen Date: Mon Feb 6 15:38:20 2006 +0000 First somewhat working version. commit 1eedf5eb5debcf2712a422e67c55b021d2db4bd7 Author: Guus Sliepen Date: Mon Feb 6 15:13:23 2006 +0000 Default repository layout. inputlirc-23/Makefile0000600000175100001440000000266312111433224013644 0ustar guususers# inputlircd -- zeroconf LIRC daemon that reads from /dev/input/event devices # Copyright (C) 2006-2013 Guus Sliepen # # This program is free software; you can redistribute it and/or modify it # under the terms of version 2 of the GNU General Public License as published # by the Free Software Foundation. # # 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA SBIN = inputlircd MAN8 = inputlircd.8 CC ?= gcc CFLAGS ?= -Wall -g -O2 -pipe PREFIX ?= /usr/local INSTALL ?= install SBINDIR ?= $(PREFIX)/sbin SHAREDIR ?= $(PREFIX)/share MANDIR ?= $(SHAREDIR)/man all: $(SBIN) names.h: /usr/include/linux/input.h gennames ./gennames $< > $@ inputlircd: inputlircd.c /usr/include/linux/input.h names.h $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $< install: install-sbin install-man install-sbin: $(SBIN) mkdir -p $(DESTDIR)$(SBINDIR) $(INSTALL) $(SBIN) $(DESTDIR)$(SBINDIR)/ install-man: $(MAN1) $(MAN5) $(MAN8) mkdir -p $(DESTDIR)$(MANDIR)/man8/ $(INSTALL) -m 644 $(MAN8) $(DESTDIR)$(MANDIR)/man8/ clean: rm -f $(SBIN) names.h inputlirc-23/gennames0000700000175100001440000000230312111433224013714 0ustar guususers#!/bin/sh # inputlircd -- zeroconf LIRC daemon that reads from /dev/input/event devices # Copyright (C) 2006-2009 Guus Sliepen # # This program is free software; you can redistribute it and/or modify it # under the terms of version 2 of the GNU General Public License as published # by the Free Software Foundation. # # 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA TYPES="KEY BTN" for type in $TYPES; do grep "^#define ${type}_" < $1 | sed 's/\/\*.*//g' done grep "^#define EV_KEY" < $1 | sed 's/\/\*.*//g' grep "^#define KEY_MAX" < $1 | sed 's/\/\*.*//g' echo "static const char *KEY_NAME[KEY_MAX] = {" for type in $TYPES; do awk " /EV_VERSION/ { next }; /_MAX/ { next }; /#define ${type}_/ { printf(\"\t[ %-16s ] = \\\"%s\\\",\n\", \$2, \$2); } " < $1 | tac done echo "};" inputlirc-23/inputlircd.80000600000175100001440000000700612111433224014446 0ustar guususers.Dd Mon, 06 Feb 2006 17:42:25 +0100 .Dt INPUTLIRCD 8 .Sh NAME .Nm inputlircd .Nd zeroconf LIRC daemon using input event devices .Sh SYNOPSIS .Nm .Op Fl d Ar socket .Op Fl f .Op Fl c .Op Fl r Ar repeat-rate .Op Fl m Ar keycode .Op Fl n Ar device name .Op Fl u Ar username .Ar device .Op Ar device Li ... .Sh DESCRIPTION .Nm is a small LIRC daemon that reads from .Pa /dev/input/event Ns X devices and sends the received keycodes to connecting LIRC clients. .Nm needs no configuration, it uses the standardised names for the keycodes as used by the kernel. Many USB remote controls that present HID devices, as well as multimedia keyboards should work out of the box. .Pp .Nm expects a list of input event devices as commandline parameters. It will only read events from those devices. .Sh OPTIONS .Bl -tag -width flag .It Fl d Ar socket Location of the UNIX socket to which LIRC clients can connect. The default is .Pa /var/run/lirc/lircd . .It Fl f Run in the foreground. .It Fl c Capture modifier keys. This causes the CTRL, SHIFT, ALT and META keys to be treated as modifer keys that, when used in combination with another keys, change the LIRC event from that key rather than being sent as their own LIRC events. .It Fl r Ar repeat-rate Set the repeat rate (in milliseconds) of the remote control. The default is 0. Repeated keys that arrive less than .Ar repeat-rate milliseconds apart will be flagged as as repeat LIRC events. .It Fl g Grab the input device(s). This gives .Nm exclusive access to the input devices and stops events from propagating any further. .It Fl m Ar keycode Minimum keycode to send to LIRC clients. Keycodes lower than this number are filtered out. The default is 88, this filters out the alphanumeric section and the keypad section of normal keyboards, but allows all extended keys. The rationale is that clients should not be able to grab normal keypresses, this could be a security risk. .It Fl n Ar device name Name of an input device to read events from. This scans all available input event devices, and if the symbolic name of an event device matches .Ar device name , adds it to the list of devices to read from. The .Ar device name can contain wildcard patterns, see .Xr glob 7 . To get a list of available devices and their names, cat .Pa /proc/bus/input/devices or use .Xr lsinput 8 . .It Fl u Ar username Set user and group id to that of .Ar username after opening the devices and UNIX socket as root. The default is nobody. .It Fl t Ar path Provides the path to a file containing a mapping between input event key names and the commands which should be reported via lirc. The files should contain lines of the form .Pa KEY_FOO = bar . This is useful for backward compatibility. The default is not to use a translation table. .It Ar device One or more input event devices. If you want to use .Nm to process multimedia keys on the keyboard, then .Pa /dev/input/event0 is the most likely choice. If you have other input devices, such as USB remote controllers that act like a HID device, then you probably need one of the other event devices present. See .Pa /proc/bus/input/devices for a list of available input devices. If unsure, you can add all available input event devices. .El .Sh FILES .Bl -tag -width indent .It Pa /var/run/lirc/lircd Default location of the UNIX socket to which LIRC clients can connect. .It Pa /dev/input/event Ns X The kernel input layer's event device files. .It Pa /proc/bus/input/devices List of all input devices. .El .Sh SEE ALSO .Xr irw 1 , .Xr input-events 8 , .Xr setkeycodes 8 , .Pa /usr/include/linux/input.h . inputlirc-23/inputlircd.c0000600000175100001440000002576712111433224014537 0ustar guususers/* inputlircd -- zeroconf LIRC daemon that reads from /dev/input/event devices Copyright (C) 2006-2013 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "names.h" typedef struct evdev { char *name; int fd; struct evdev *next; } evdev_t; static evdev_t *evdevs = NULL; typedef struct client { int fd; struct client *next; } client_t; static client_t *clients = NULL; static int sockfd; static bool grab = false; static int key_min = 88; static char *device = "/var/run/lirc/lircd"; static bool capture_modifiers = false; static bool meta = false; static bool alt = false; static bool shift = false; static bool ctrl = false; static long repeat_time = 0L; static struct timeval previous_input; static struct timeval evdev_timeout; static struct input_event previous_event; static int repeat = 0; static void *xalloc(size_t size) { void *buf = malloc(size); if(!buf) { fprintf(stderr, "Could not allocate %zd bytes with malloc(): %s\n", size, strerror(errno)); exit(EX_OSERR); } memset(buf, 0, size); return buf; } static void parse_translation_table(const char *path) { FILE *table; char *line = NULL; size_t line_size = 0; char event_name[100]; char lirc_name[100]; unsigned int i; if(!path) return; table = fopen(path, "r"); if(!table) { fprintf(stderr, "Could not open translation table %s: %s\n", path, strerror(errno)); return; } while(getline(&line, &line_size, table) >= 0) { if (sscanf(line, " %99s = %99s ", event_name, lirc_name) != 2) continue; event_name[99] = '\0'; lirc_name[99] = '\0'; if(strlen(event_name) < 1 || strlen(lirc_name) < 1) continue; if(!(i = strtoul(event_name, NULL, 0))) { for(i = 0; i < KEY_MAX; i++) { if (!KEY_NAME[i]) continue; if(!strcmp(event_name, KEY_NAME[i])) break; } } if(i >= KEY_MAX) continue; KEY_NAME[i] = strdup(lirc_name); if(!KEY_NAME[i]) { fprintf(stderr, "strdup failure: %s\n", strerror(errno)); exit(EX_OSERR); } } fclose(table); free(line); } static int open_evdev(char *name) { int fd; fd = open(name, O_RDONLY); if(fd < 0) { syslog(LOG_ERR, "Could not open %s: %s\n", name, strerror(errno)); return -1; } char bits = 0; if(ioctl(fd, EVIOCGBIT(0, sizeof bits), &bits) < 0) { close(fd); syslog(LOG_ERR, "Could not read supported event types from %s: %s\n", name, strerror(errno)); return -1; } if(!(bits & 2)) { close(fd); syslog(LOG_ERR, "%s does not support EV_KEY events\n", name); return -1; } if(grab) { if(ioctl(fd, EVIOCGRAB, 1) < 0) { close(fd); syslog(LOG_ERR, "Failed to grab %s: %s\n", name, strerror(errno)); return -1; } } return fd; } static void rescan_evdevs(fd_set *permset) { evdev_t *evdev; int fd; for(evdev = evdevs; evdev; evdev = evdev->next) { if(evdev->fd == -999) { syslog(LOG_INFO, "Reading device: %s", evdev->name); fd = open_evdev(evdev->name); if(fd >= 0) { evdev->fd = fd; FD_SET(evdev->fd, permset); syslog(LOG_INFO, "Success!"); } } } } static void add_evdev(char *name) { int fd; evdev_t *newdev; fd = open_evdev(name); if(fd < 0) return; newdev = xalloc(sizeof *newdev); newdev->fd = fd; newdev->name = strdup(name); newdev->next = evdevs; evdevs = newdev; } static void add_named(char *pattern) { int i, result, fd; char name[32]; glob_t g; result = glob("/dev/input/event*", GLOB_NOSORT, NULL, &g); if(result == GLOB_NOMATCH) { fprintf(stderr, "No event devices found!\n"); return; } else if(result) { fprintf(stderr, "Could not read /dev/input/event*: %s\n", strerror(errno)); return; } for(i = 0; i < g.gl_pathc; i++) { fd = open(g.gl_pathv[i], O_RDONLY); if(fd < 0) { fprintf(stderr, "Could not open %s: %s\n", g.gl_pathv[i], strerror(errno)); continue; } result = ioctl(fd, EVIOCGNAME(sizeof(name)), name); close(fd); if(result < 0) { fprintf(stderr, "Could not read name of event device %s: %s\n", g.gl_pathv[i], strerror(errno)); continue; } name[(sizeof name) -1] = 0; if(!fnmatch(pattern, name, FNM_CASEFOLD)) add_evdev(g.gl_pathv[i]); } globfree(&g); } static void add_unixsocket(void) { struct sockaddr_un sa = {0}; sockfd = socket(AF_UNIX, SOCK_STREAM, 0); if(sockfd < 0) { fprintf(stderr, "Unable to create an AF_UNIX socket: %s\n", strerror(errno)); exit(EX_OSERR); } sa.sun_family = AF_UNIX; strncpy(sa.sun_path, device, sizeof sa.sun_path - 1); unlink(device); if(bind(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) { fprintf(stderr, "Unable to bind AF_UNIX socket to %s: %s\n", device, strerror(errno)); exit(EX_OSERR); } chmod(device, 0666); if(listen(sockfd, 3) < 0) { fprintf(stderr, "Unable to listen on AF_UNIX socket: %s\n", strerror(errno)); exit(EX_OSERR); } } static void processnewclient(void) { client_t *newclient = xalloc(sizeof *newclient); newclient->fd = accept(sockfd, NULL, NULL); if(newclient->fd < 0) { free(newclient); if(errno == ECONNABORTED || errno == EINTR) return; syslog(LOG_ERR, "Error during accept(): %s\n", strerror(errno)); exit(EX_OSERR); } int flags = fcntl(newclient->fd, F_GETFL); fcntl(newclient->fd, F_SETFL, flags | O_NONBLOCK); newclient->next = clients; clients = newclient; } static long time_elapsed(struct timeval *last, struct timeval *current) { long seconds = current->tv_sec - last->tv_sec; return 1000000 * seconds + current->tv_usec - last->tv_usec; } static void processevent(evdev_t *evdev, fd_set *permset) { struct input_event event; char message[1000]; int len; client_t *client, *prev, *next; if(read(evdev->fd, &event, sizeof event) != sizeof event) { syslog(LOG_ERR, "Error processing event from %s: %s\n", evdev->name, strerror(errno)); FD_CLR(evdev->fd, permset); close(evdev->fd); evdev->fd = -999; return; } if(event.type != EV_KEY) return; if(event.code > KEY_MAX || event.code < key_min) return; if(capture_modifiers) { if(event.code == KEY_LEFTCTRL || event.code == KEY_RIGHTCTRL) { ctrl = !!event.value; return; } if(event.code == KEY_LEFTSHIFT || event.code == KEY_RIGHTSHIFT) { shift = !!event.value; return; } if(event.code == KEY_LEFTALT || event.code == KEY_RIGHTALT) { alt = !!event.value; return; } if(event.code == KEY_LEFTMETA || event.code == KEY_RIGHTMETA) { meta = !!event.value; return; } } if(!event.value) return; struct timeval current; gettimeofday(¤t, NULL); if(event.code == previous_event.code && time_elapsed(&previous_input, ¤t) < repeat_time) repeat++; else repeat = 0; if(KEY_NAME[event.code]) len = snprintf(message, sizeof message, "%x %x %s%s%s%s%s %s\n", event.code, repeat, ctrl ? "CTRL_" : "", shift ? "SHIFT_" : "", alt ? "ALT_" : "", meta ? "META_" : "", KEY_NAME[event.code], evdev->name); else len = snprintf(message, sizeof message, "%x %x KEY_CODE_%d %s\n", event.code, repeat, event.code, evdev->name); previous_input = current; previous_event = event; for(client = clients; client; client = client->next) { if(write(client->fd, message, len) != len) { close(client->fd); client->fd = -1; } } for(prev = NULL, client = clients; client; client = next) { next = client->next; if(client->fd < 0) { if(prev) prev->next = client->next; else clients = client->next; free(client); } else { prev = client; } } } static void main_loop(void) { fd_set permset; fd_set fdset; evdev_t *evdev; int maxfd = 0; int retselect; FD_ZERO(&permset); for(evdev = evdevs; evdev; evdev = evdev->next) { if(evdev->fd < 0) continue; FD_SET(evdev->fd, &permset); if(evdev->fd > maxfd) maxfd = evdev->fd; } FD_SET(sockfd, &permset); if(sockfd > maxfd) maxfd = sockfd; maxfd++; while(true) { fdset = permset; //wait for 30 secs, then rescan devices evdev_timeout.tv_sec = 30; retselect = select(maxfd, &fdset, NULL, NULL, &evdev_timeout); if(retselect > 0) { for(evdev = evdevs; evdev; evdev = evdev->next) if(FD_ISSET(evdev->fd, &fdset)) processevent(evdev, &permset); if(FD_ISSET(sockfd, &fdset)) processnewclient(); } else { if(retselect < 0) { if(errno == EINTR) continue; syslog(LOG_ERR, "Error during select(): %s\n", strerror(errno)); } rescan_evdevs(&permset); } } } int main(int argc, char *argv[]) { char *user = "nobody"; char *translation_path = NULL; int opt, i; bool foreground = false, named = false; gettimeofday(&previous_input, NULL); while((opt = getopt(argc, argv, "cd:gm:n:fu:r:t:")) != -1) { switch(opt) { case 'd': device = strdup(optarg); break; case 'g': grab = true; break; case 'c': capture_modifiers = true; break; case 'm': key_min = atoi(optarg); break; case 'n': named = true; add_named(optarg); break; case 'u': user = strdup(optarg); break; case 'f': foreground = true; break; case 'r': repeat_time = atoi(optarg) * 1000L; break; case 't': translation_path = strdup(optarg); break; default: fprintf(stderr, "Unknown option!\n"); return EX_USAGE; } } if(argc <= optind && !named) { fprintf(stderr, "Not enough arguments.\n"); return EX_USAGE; } openlog("inputlircd", LOG_PERROR, LOG_DAEMON); for(i = optind; i < argc; i++) add_evdev(argv[i]); if(!evdevs) { fprintf(stderr, "Unable to open any event device!\n"); return EX_OSERR; } parse_translation_table(translation_path); add_unixsocket(); struct passwd *pwd = getpwnam(user); if(!pwd) { fprintf(stderr, "Unable to resolve user %s!\n", user); return EX_OSERR; } if(setgid(pwd->pw_gid) || setuid(pwd->pw_uid)) { fprintf(stderr, "Unable to setuid/setguid to %s!\n", user); return EX_OSERR; } if(!foreground) { closelog(); daemon(0, 0); openlog("inputlircd", 0, LOG_DAEMON); } syslog(LOG_INFO, "Started"); signal(SIGPIPE, SIG_IGN); main_loop(); return 0; }