21625f40b5
I tried to get the latest versions from dockapps.org, but I haven't tested any of them. More dockapps will be added as time permits.
235 lines
4.7 KiB
C
235 lines
4.7 KiB
C
/*
|
|
* 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 <ctype.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#include <X11/Xlib.h>
|
|
|
|
#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;
|
|
}
|