initial import
This commit is contained in:
commit
521c9b0442
3 changed files with 343 additions and 0 deletions
5
README
Normal file
5
README
Normal file
|
@ -0,0 +1,5 @@
|
|||
This is logikeys, a program that listens for scancodes and behaves according to a configuration file.
|
||||
See logikeysrc for how it is configured.
|
||||
I build with (on FreeBSD):
|
||||
|
||||
cc -L/usr/X11R6/lib -I/usr/X11R6/include -ggdb -lX11 -o logikeys logikeys.c
|
310
logikeys.c
Normal file
310
logikeys.c
Normal file
|
@ -0,0 +1,310 @@
|
|||
/*
|
||||
* Small C program to execute arbitrary commands or write to pipes/files
|
||||
* upon keypresses of arbitrary scancodes (useful for logitech and other
|
||||
* multimedia keyboards.
|
||||
* (C)2005, Dan Ponte
|
||||
* BSD license
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <signal.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
#define EV_CMD 0x1
|
||||
#define EV_WRITE 0x2
|
||||
|
||||
Display *d;
|
||||
Window r;
|
||||
struct keyentry {
|
||||
int scancode;
|
||||
int type;
|
||||
int fd;
|
||||
void *data;
|
||||
size_t dlen;
|
||||
char *command;
|
||||
struct keyentry *next;
|
||||
};
|
||||
|
||||
struct keyentry *head = NULL, *last = NULL;
|
||||
char buf[1024];
|
||||
int wquit = 0;
|
||||
|
||||
int udom_open(fn) /* not really a udom, but oh well...sounds cool */
|
||||
char *fn;
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open(fn, O_APPEND|O_WRONLY);
|
||||
if(fd == -1) {
|
||||
perror("udopen");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
void qsig(s)
|
||||
int s;
|
||||
{
|
||||
wquit = 1;
|
||||
}
|
||||
|
||||
void get_keys(h)
|
||||
struct keyentry *h;
|
||||
{
|
||||
struct keyentry *c;
|
||||
|
||||
for(c = h; c != NULL; c = c->next) {
|
||||
XGrabKey(d, c->scancode, AnyModifier, r, False, GrabModeAsync, GrabModeAsync);
|
||||
}
|
||||
}
|
||||
|
||||
void init_x(void)
|
||||
{
|
||||
char *dpy;
|
||||
|
||||
dpy = getenv("DISPLAY");
|
||||
if(dpy == NULL) {
|
||||
fprintf(stderr, "error: needs $DISPLAY\n");
|
||||
exit(-1);
|
||||
}
|
||||
d = XOpenDisplay(dpy);
|
||||
if(d == NULL) {
|
||||
fprintf(stderr, "error: cannot open display %s\n", dpy);
|
||||
exit(-2);
|
||||
}
|
||||
r = DefaultRootWindow(d);
|
||||
if(!r) {
|
||||
fprintf(stderr, "error: no root window\n");
|
||||
exit(-3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void free_keys(h)
|
||||
struct keyentry *h;
|
||||
{
|
||||
struct keyentry *n, *c = h;
|
||||
|
||||
while(c != NULL) {
|
||||
n = c->next;
|
||||
XUngrabKey(d, c->scancode, AnyModifier, r);
|
||||
if(c->command != NULL)
|
||||
free(c->command);
|
||||
if(c->data != NULL)
|
||||
free(c->data);
|
||||
if(c->fd != 0)
|
||||
close(c->fd);
|
||||
free(c);
|
||||
c = n;
|
||||
}
|
||||
}
|
||||
|
||||
int read_config_file(file, hp, lp)
|
||||
char *file;
|
||||
struct keyentry **hp;
|
||||
struct keyentry **lp;
|
||||
{
|
||||
FILE *f;
|
||||
char *kc, *cmd, *r;
|
||||
struct keyentry *new;
|
||||
int lnum = 0;
|
||||
|
||||
if((f = fopen(file, "r")) == NULL) {
|
||||
perror("logikeys");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
while(!feof(f)) {
|
||||
char *nlt;
|
||||
fgets(buf, 1023, f);
|
||||
lnum++;
|
||||
if(*buf == '#' || *buf == '\n' || *buf == '\0')
|
||||
continue;
|
||||
if((nlt = strrchr(buf, '\n')) != NULL)
|
||||
*nlt = '\0';
|
||||
|
||||
kc = buf;
|
||||
cmd = buf;
|
||||
r = strsep(&cmd, ":");
|
||||
if(*r == '\0') {
|
||||
fprintf(stderr, "Syntax error at line %d!\n", lnum);
|
||||
exit(-1);
|
||||
}
|
||||
if(cmd == NULL) {
|
||||
continue;
|
||||
}
|
||||
new = calloc(1, sizeof(struct keyentry));
|
||||
if(*hp == NULL) {
|
||||
*hp = new;
|
||||
*lp = new;
|
||||
} else {
|
||||
(*lp)->next = new;
|
||||
*lp = new;
|
||||
}
|
||||
new->scancode = atoi(kc);
|
||||
if(*cmd == '=') {
|
||||
struct keyentry *ct;
|
||||
int found = 0, tsc;
|
||||
char *ssrc;
|
||||
char *tpipe = cmd + 1;
|
||||
char *tdata = tpipe;
|
||||
|
||||
ssrc = strsep(&tdata, "|");
|
||||
if(*ssrc == '\0') {
|
||||
fprintf(stderr, "Syntax error on line %d!\n", lnum);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
tsc = atoi(tpipe);
|
||||
|
||||
for(ct = *hp; ct != NULL; ct = ct->next) {
|
||||
if(ct->scancode == tsc && ct->fd != 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
fprintf(stderr, "No such scancode defined with pipe %d (line %d)\n", tsc, lnum);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
new->type = EV_WRITE;
|
||||
new->fd = ct->fd;
|
||||
new->data = strdup(tdata);
|
||||
new->dlen = strlen(new->data);
|
||||
} else if(*cmd == '|') {
|
||||
char *pipefn, *dat, *ssret;
|
||||
|
||||
pipefn = cmd + 1;
|
||||
dat = pipefn;
|
||||
ssret = strsep(&dat, "|");
|
||||
if(*ssret == '\0') {
|
||||
fprintf(stderr, "Syntax error on line %d!\n", lnum);
|
||||
exit(-1);
|
||||
}
|
||||
if((new->fd = udom_open(pipefn)) == -1) {
|
||||
/* not reached? */
|
||||
fprintf(stderr, "Error opening pipe %s (line %d)\n", pipefn, lnum);
|
||||
exit(-2);
|
||||
}
|
||||
new->type = EV_WRITE;
|
||||
new->data = strdup(dat);
|
||||
new->dlen = strlen(new->data);
|
||||
} else {
|
||||
new->type = EV_CMD;
|
||||
new->command = strdup(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void doevent(e)
|
||||
struct keyentry *e;
|
||||
{
|
||||
char *cmd;
|
||||
size_t tl;
|
||||
int rc;
|
||||
|
||||
switch(e->type) {
|
||||
case EV_CMD:
|
||||
tl = strlen(e->command) + 4;
|
||||
cmd = malloc(tl);
|
||||
strlcpy(cmd, e->command, tl);
|
||||
strlcat(cmd, " &", tl);
|
||||
rc = system(cmd);
|
||||
free(cmd);
|
||||
return;
|
||||
case EV_WRITE:
|
||||
if(write(e->fd, e->data, e->dlen) == -1) {
|
||||
perror("ev_write");
|
||||
wquit = 1;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void handle_ev(k)
|
||||
int k;
|
||||
{
|
||||
struct keyentry *c;
|
||||
|
||||
for(c = head; c != NULL; c = c->next) {
|
||||
if(c->scancode == k) {
|
||||
doevent(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ev_loop(void)
|
||||
{
|
||||
long mask = KeyPressMask;
|
||||
XEvent ev;
|
||||
|
||||
while(!wquit) {
|
||||
while(XCheckMaskEvent(d, mask, &ev)) {
|
||||
handle_ev(ev.xkey.keycode);
|
||||
}
|
||||
usleep(100000);
|
||||
}
|
||||
}
|
||||
|
||||
void usage(pn)
|
||||
char *pn;
|
||||
{
|
||||
printf("%s: usage: %s [-h] [-v] configfile\n", pn, pn);
|
||||
}
|
||||
|
||||
void version(pn)
|
||||
char *pn;
|
||||
{
|
||||
printf("%s: logikeys v0.1\n(C)2005, Dan Ponte\n", pn);
|
||||
}
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
char *pn = *argv;
|
||||
|
||||
signal(SIGINT, qsig);
|
||||
signal(SIGTERM, qsig);
|
||||
while((c = getopt(argc, argv, "hv")) != -1)
|
||||
switch(c) {
|
||||
case 'h':
|
||||
usage(*argv);
|
||||
return 1;
|
||||
case 'v':
|
||||
version(*argv);
|
||||
return 1;
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if(argc != 1) {
|
||||
fprintf(stderr, "%s: must specify config file!\n", pn);
|
||||
usage(pn);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
read_config_file(*argv, &head, &last);
|
||||
|
||||
init_x();
|
||||
get_keys(head);
|
||||
ev_loop();
|
||||
free_keys(head);
|
||||
|
||||
return 0;
|
||||
}
|
28
logikeysrc
Normal file
28
logikeysrc
Normal file
|
@ -0,0 +1,28 @@
|
|||
# example configuration
|
||||
# for the logitech "corded keyboard"
|
||||
# requires xmms-pipe be running to run (might fix in a later version)
|
||||
# general format of lines is
|
||||
# scancode:action
|
||||
# If action starts with '|' it is in the format of
|
||||
# |/pipe/filename|text to write
|
||||
# If action starts with '=' it means "use the same pipe handle as scancode X"
|
||||
# In all other cases, action is just a command (" &" will be appended to run in the background)
|
||||
|
||||
# next key
|
||||
153:|/home/dcp1990/.xmms/inpipe|playlist next
|
||||
# prev key
|
||||
144:=153|playlist prev
|
||||
# stop key
|
||||
164:=153|stop
|
||||
# mute key
|
||||
160:=153|mute
|
||||
# play/pause key
|
||||
162:=153|play_pause
|
||||
# volume up
|
||||
176:=153|add_volume 8
|
||||
# volume down
|
||||
174:=153|add_volume -8
|
||||
# calculator key
|
||||
161:xcalc
|
||||
# home key
|
||||
178:opera http://www.yahoo.com/
|
Loading…
Reference in a new issue