/* * Copyright (c) 2007 Daniel Borca All rights reserved. * * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include "xhookey.h" #define LOG(x) printf x static void grab_key (Display *dpy, KeyCode keycode, unsigned int modifier, Window win) { XGrabKey(dpy, keycode, modifier, (win ? win : DefaultRootWindow(dpy)), False, GrabModeAsync, GrabModeAsync); } int xhk_grab (Display *dpy, int num, KTUPLE keys[]) { int screen = DefaultScreen(dpy); for (screen = 0; screen < ScreenCount(dpy); screen++) { int i; for (i = 0; i < num; i++) { grab_key(dpy, keys[i].key, keys[i].mod, RootWindow(dpy, screen)); } } return 0; } void xhk_ungrab (Display *dpy) { int screen = DefaultScreen(dpy); for (screen = 0; screen < ScreenCount(dpy); screen++) { XUngrabKey(dpy, AnyKey, AnyModifier, RootWindow(dpy, screen)); } } int xhk_parse (int argc, char **argv, KTUPLE **out_keys) { int i = 0; KTUPLE *keys; keys = malloc((argc - 1) * sizeof(KTUPLE)); if (keys == NULL) { return -1; } while (--argc) { const char *p = *++argv; if (!strncmp(p, "-key=", 5)) { char *q; errno = 0; p += 5; keys[i].mod = 0; for (;;) { if (!strncmp(p, "Shift+", 6)) { p += 6; keys[i].mod |= ShiftMask; continue; } if (!strncmp(p, "Control+", 8)) { p += 8; keys[i].mod |= ControlMask; continue; } if (!strncmp(p, "Alt+", 4)) { p += 4; keys[i].mod |= Mod1Mask; continue; } break; } keys[i].key = strtol(p, &q, 0); if (errno || q == p || !isspace(*q)) { LOG(("ignoring `%s'\n", p)); continue; } while (isspace(*++q)) { } keys[i].command = q; LOG(("key%d: 0x%X+%d -> \"%s\"\n", i, keys[i].mod, keys[i].key, keys[i].command)); i++; } } if (i) { *out_keys = keys; } else { free(keys); } return i; } #if XHK_SIGFORK void xhk_sig_handler (int sig) { if (sig == SIGCHLD) { int status; pid_t child; /* if more than one child exits at approximately the same time, the signals may get merged. */ while ((child = waitpid(-1, &status, WNOHANG)) > 0) { LOG(("pid %d exited\n", child)); } } } #endif #if XHK_XERROR int xhk_eks_handler (Display *dpy, XErrorEvent *evt) { static int been_there_done_that = 0; if (!been_there_done_that) { been_there_done_that++; fprintf(stderr, "*** X ERROR %d\n", evt->error_code); (void)dpy; } return 0; } #endif static int display_env (Display *dpy) { const char *display_name = DisplayString(dpy); char *envstr = malloc(strlen(display_name) + 8 + 1); if (envstr != NULL) { strcat(strcpy(envstr, "DISPLAY="), display_name); putenv(envstr); } } static int run_command (Display *dpy, KTUPLE *key) { pid_t pid; #if XHK_SIGFORK pid = fork(); if (pid < 0) { return -1; } if (pid == 0) { if (setsid() < 0) { exit(-1); } display_env(dpy); exit(execlp("sh", "sh", "-c", key->command, (char *)0)); } return 0; #else /* !XHK_SIGFORK */ int status; pid = fork(); if (pid < 0) { return -1; } if (pid == 0) { if (setsid() < 0) { exit(-1); } /* fork again and exit, so that init(1) reaps the grandchildren */ pid = fork(); if (pid < 0) { exit(-1); } if (pid > 0) { exit(0); } display_env(dpy); exit(execlp("sh", "sh", "-c", key->command, (char *)0)); } waitpid(pid, &status, 0); return WEXITSTATUS(status); #endif /* !XHK_SIGFORK */ } int xhk_run (Display *dpy, XEvent *evt, int num, KTUPLE keys[]) { if (evt->type == KeyPress) { int i; unsigned int mod = evt->xkey.state & (ShiftMask | ControlMask | Mod1Mask); for (i = 0; i < num; i++) { if (evt->xkey.keycode == keys[i].key && mod == keys[i].mod) { LOG(("key: 0x%X+%d, cmd: %s\n", keys[i].mod, keys[i].key, keys[i].command)); return run_command(dpy, &keys[i]); } } } return -1; }