xf86ctrl

mplay control using xf86 media keys
git clone https://git.sinitax.com/sinitax/xf86ctrl
Log | Files | Refs | LICENSE | sfeed.txt

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}