#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define ARRLEN(a) (sizeof(a)/sizeof(*(a))) static pid_t child_pid = -1; static int child_fd = -1; static FILE *child_io = NULL; static const char *play_arg = "-p"; static bool ptty = false; static void die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); fputs("xf86ctrl: ", stderr); vfprintf(stderr, fmt, ap); if (*fmt && fmt[strlen(fmt) - 1] == ':') { fputc(' ', stderr); perror(NULL); } else { fputc('\n', stderr); } va_end(ap); exit(1); } static void child_exit(int sig) { int status, rc; do { rc = waitpid(child_pid, &status, 0); if (rc < 0 && errno == ECHILD) exit(123); } while (rc < 0 || !WIFEXITED(status) && !WIFSIGNALED(status)); if (WIFSIGNALED(status)) exit(128 + WTERMSIG(status)); exit(WEXITSTATUS(status)); } int main(int argc, char **argv) { char **arg; struct termios childterm; struct winsize ws; int child_pipe[2]; ssize_t nwrite; Display *d; Window win; XEvent e; KeySym key; for (arg = argv + 1; *arg && strcmp(*arg, "--"); arg++) { if (!strcmp(*arg, "-h") || !strcmp(*arg, "--help")) { *arg = NULL; break; } else if (!strcmp(*arg, "-p")) { play_arg = *++arg; } else if (!strcmp(*arg, "-t")) { ptty = true; } else { break; } } if (!*arg) { fprintf(stderr, "Usage: xf86ctrl [-p PLAY] [-t] CMD [ARGS..]\n"); return 1; } signal(SIGCHLD, child_exit); if (ptty) { cfmakeraw(&childterm); ws.ws_col = 80; ws.ws_row = 40; child_pid = forkpty(&child_fd, NULL, &childterm, &ws); if (child_pid < 0) die("forkpty:"); if (!child_pid) { signal(SIGCHLD, SIG_DFL); execvp(*arg, arg); die("execvp:"); } } else { pipe(child_pipe); child_pid = fork(); if (child_pid < 0) die("fork:"); if (!child_pid) { signal(SIGCHLD, SIG_DFL); close(1); close(2); dup2(child_pipe[0], 0); close(child_pipe[1]); close(child_pipe[0]); execvp(*arg, arg); die("execvp:"); } child_fd = child_pipe[1]; close(child_pipe[0]); } child_io = fdopen(child_fd, "w"); if (!child_io) die("fdopen:"); d = XOpenDisplay(NULL); if (!d) die("XOpenDisplay(NULL)"); win = DefaultRootWindow(d); if (!win) die("XDefaultRootWindow no result"); XGrabKey(d, XKeysymToKeycode(d, XF86XK_AudioNext), 0, win, False, GrabModeAsync, GrabModeAsync); XGrabKey(d, XKeysymToKeycode(d, XF86XK_AudioPlay), 0, win, False, GrabModeAsync, GrabModeAsync); while (1) { XNextEvent(d, &e); if (e.type == KeyPress) { key = XkbKeycodeToKeysym(d, (KeyCode) e.xkey.keycode, 0, !!(e.xkey.state & ShiftMask)); switch (key) { case XF86XK_AudioNext: goto exit; case XF86XK_AudioPlay: nwrite = fputs(play_arg, child_io); if (nwrite != strlen(play_arg)) goto exit; fflush(child_io); break; } } } exit: XCloseDisplay(d); }