main.c (3115B)
1#include <X11/X.h> 2#include <X11/XKBlib.h> 3#include <X11/Xlib.h> 4#include <X11/keysym.h> 5#include <X11/XF86keysym.h> 6 7#include <sys/wait.h> 8#include <pty.h> 9#include <errno.h> 10#include <signal.h> 11#include <unistd.h> 12#include <termios.h> 13#include <string.h> 14#include <stdarg.h> 15#include <stdbool.h> 16#include <stdio.h> 17#include <stdlib.h> 18 19#define ARRLEN(a) (sizeof(a)/sizeof(*(a))) 20 21static pid_t child_pid = -1; 22static int child_fd = -1; 23static FILE *child_io = NULL; 24 25static const char *play_arg = "-p"; 26static bool ptty = false; 27 28static void 29die(const char *fmt, ...) 30{ 31 va_list ap; 32 33 va_start(ap, fmt); 34 fputs("xf86ctrl: ", stderr); 35 vfprintf(stderr, fmt, ap); 36 if (*fmt && fmt[strlen(fmt) - 1] == ':') { 37 fputc(' ', stderr); 38 perror(NULL); 39 } else { 40 fputc('\n', stderr); 41 } 42 va_end(ap); 43 44 exit(1); 45} 46 47static void 48child_exit(int sig) 49{ 50 int status, rc; 51 52 do { 53 rc = waitpid(child_pid, &status, 0); 54 if (rc < 0 && errno == ECHILD) exit(123); 55 } while (rc < 0 || !WIFEXITED(status) && !WIFSIGNALED(status)); 56 57 if (WIFSIGNALED(status)) 58 exit(128 + WTERMSIG(status)); 59 60 exit(WEXITSTATUS(status)); 61} 62 63int 64main(int argc, char **argv) 65{ 66 char **arg; 67 struct termios childterm; 68 struct winsize ws; 69 int child_pipe[2]; 70 ssize_t nwrite; 71 Display *d; 72 Window win; 73 XEvent e; 74 KeySym key; 75 76 for (arg = argv + 1; *arg && strcmp(*arg, "--"); arg++) { 77 if (!strcmp(*arg, "-h") || !strcmp(*arg, "--help")) { 78 *arg = NULL; 79 break; 80 } else if (!strcmp(*arg, "-p")) { 81 play_arg = *++arg; 82 } else if (!strcmp(*arg, "-t")) { 83 ptty = true; 84 } else { 85 break; 86 } 87 } 88 if (!*arg) { 89 fprintf(stderr, "Usage: xf86ctrl [-p PLAY] [-t] CMD [ARGS..]\n"); 90 return 1; 91 } 92 93 signal(SIGCHLD, child_exit); 94 95 if (ptty) { 96 cfmakeraw(&childterm); 97 ws.ws_col = 80; 98 ws.ws_row = 40; 99 child_pid = forkpty(&child_fd, NULL, &childterm, &ws); 100 if (child_pid < 0) die("forkpty:"); 101 if (!child_pid) { 102 signal(SIGCHLD, SIG_DFL); 103 execvp(*arg, arg); 104 die("execvp:"); 105 } 106 } else { 107 pipe(child_pipe); 108 child_pid = fork(); 109 if (child_pid < 0) die("fork:"); 110 if (!child_pid) { 111 signal(SIGCHLD, SIG_DFL); 112 close(1); 113 close(2); 114 dup2(child_pipe[0], 0); 115 close(child_pipe[1]); 116 close(child_pipe[0]); 117 execvp(*arg, arg); 118 die("execvp:"); 119 } 120 child_fd = child_pipe[1]; 121 close(child_pipe[0]); 122 } 123 124 child_io = fdopen(child_fd, "w"); 125 if (!child_io) die("fdopen:"); 126 127 d = XOpenDisplay(NULL); 128 if (!d) die("XOpenDisplay(NULL)"); 129 130 win = DefaultRootWindow(d); 131 if (!win) die("XDefaultRootWindow no result"); 132 133 XGrabKey(d, XKeysymToKeycode(d, XF86XK_AudioNext), 0, 134 win, False, GrabModeAsync, GrabModeAsync); 135 XGrabKey(d, XKeysymToKeycode(d, XF86XK_AudioPlay), 0, 136 win, False, GrabModeAsync, GrabModeAsync); 137 138 while (1) { 139 XNextEvent(d, &e); 140 if (e.type == KeyPress) { 141 key = XkbKeycodeToKeysym(d, 142 (KeyCode) e.xkey.keycode, 0, 143 !!(e.xkey.state & ShiftMask)); 144 switch (key) { 145 case XF86XK_AudioNext: 146 goto exit; 147 case XF86XK_AudioPlay: 148 nwrite = fputs(play_arg, child_io); 149 if (nwrite != strlen(play_arg)) goto exit; 150 fflush(child_io); 151 break; 152 } 153 } 154 } 155exit: 156 157 XCloseDisplay(d); 158}