feature: Add command()

master
Raheman Vaiya 4 years ago
parent 49f863c407
commit 65984d30e0
  1. BIN
      data/keyd-application-mapper.1.gz
  2. BIN
      data/keyd.1.gz
  3. 4
      docs/keyd-application-mapper.scdoc
  4. 9
      docs/keyd.scdoc
  5. 55
      src/descriptor.c
  6. 1
      src/descriptor.h
  7. 4
      src/device.c
  8. 32
      src/keyboard.c
  9. 11
      src/layer.h
  10. 4
      src/vkbd/uinput.c

Binary file not shown.

Binary file not shown.

@ -76,8 +76,8 @@ to */var/run/keyd.socket* (i.e be a member of the *keyd* group).
# A note on security # A note on security
Any user which can interact with a program that directly controls input devices *Any user which can interact with a program that directly controls input devices
should be assumed to have full access to the system. should be assumed to have full access to the system.*
While keyd offers slightly better isolation compared to other remappers by dint While keyd offers slightly better isolation compared to other remappers by dint
of mediating access through an IPC mechanism (rather than granting users of mediating access through an IPC mechanism (rather than granting users

@ -372,6 +372,15 @@ arguments.
macro2(400, 50, macro(Hello space World)) macro2(400, 50, macro(Hello space World))
*command(<shell command>)*
Execute the given shell command.
E.G
command(brightness down)
*NOTE:* Commands are executed by root, which means any user which has access
to the keyd socket should be assumed to have root access.
*noop* *noop*
Do nothing. Do nothing.

@ -14,7 +14,9 @@
#define MAX_ARGS 5 #define MAX_ARGS 5
/* modifies the input string */ /* TODO: Make this a bit nicer. */
/* Modifies the input string */
static int parse_fn(char *s, static int parse_fn(char *s,
char **name, char **name,
char *args[MAX_ARGS], char *args[MAX_ARGS],
@ -314,13 +316,12 @@ static size_t escape(char *s)
return n; return n;
} }
static int parse_macro(const char *exp, struct macro *macro) static int parse_macro(const char *exp, struct macro *macro)
{ {
char s[MAX_MACROEXP_LEN]; char s[MAX_MACROEXP_LEN+1];
int len = strlen(exp); int len = strlen(exp);
if (len >= MAX_MACROEXP_LEN) { if (len > MAX_MACROEXP_LEN) {
err("macro exceeds maximum macro length (%d)", MAX_MACROEXP_LEN); err("macro exceeds maximum macro length (%d)", MAX_MACROEXP_LEN);
return -1; return -1;
} }
@ -394,7 +395,7 @@ int layer_table_lookup(const struct layer_table *lt, const char *name)
int layer_table_add_entry(struct layer_table *lt, const char *exp) int layer_table_add_entry(struct layer_table *lt, const char *exp)
{ {
uint8_t code1, code2; uint8_t code1, code2;
char *keystr, *descstr, *c, *s; char *keystr, *descstr, *dot, *paren, *s;
char *layername = "main"; char *layername = "main";
struct descriptor d; struct descriptor d;
struct layer *layer; struct layer *layer;
@ -410,10 +411,13 @@ int layer_table_add_entry(struct layer_table *lt, const char *exp)
strcpy(buf, exp); strcpy(buf, exp);
s = buf; s = buf;
if ((c = strchr(s, '.'))) { dot = strchr(s, '.');
paren = strchr(s, '(');
if (dot && (!paren || dot < paren)) {
layername = s; layername = s;
*c = 0; *dot = 0;
s = c+1; s = dot+1;
} }
if (parse_kvp(s, &keystr, &descstr) < 0) { if (parse_kvp(s, &keystr, &descstr) < 0) {
@ -518,6 +522,36 @@ int create_layer(struct layer *layer, const char *desc, const struct layer_table
return 0; return 0;
} }
int set_command_arg(struct descriptor *d, int idx,
struct layer_table *lt, const char *exp)
{
struct command *command = &lt->commands[lt->nr_commands];
int len = strlen(exp);
if (len == 0 || strstr(exp, "command(") != exp || exp[len-1] != ')')
return -1;
if (lt->nr_commands >= MAX_COMMANDS) {
err("maximum number of commands exceeded");
return 1;
}
if (len > MAX_COMMAND_LEN) {
err("maximum command length exceeded");
return 1;
}
strcpy(command->cmd, exp+8);
command->cmd[len-9] = 0;
command->cmd[len-1] = 0;
escape(command->cmd);
d->args[0].idx = lt->nr_commands;
lt->nr_commands++;
return 0;
}
/* /*
* Returns: * Returns:
* *
@ -586,6 +620,11 @@ int parse_descriptor(const char *descstr,
if (keycode_to_mod(code)) if (keycode_to_mod(code))
fprintf(stderr, fprintf(stderr,
"WARNING: mapping modifier keycodes directly may produce unintended results, you probably want layer(<modifier name>) instead\n"); "WARNING: mapping modifier keycodes directly may produce unintended results, you probably want layer(<modifier name>) instead\n");
} else if ((ret=set_command_arg(d, 0, lt, descstr)) >= 0) {
if (ret > 0)
return -1;
else
d->op = OP_COMMAND;
} else if ((ret=set_macro_arg(d, 0, lt, descstr, -1, -1)) >= 0) { } else if ((ret=set_macro_arg(d, 0, lt, descstr, -1, -1)) >= 0) {
if (ret > 0) if (ret > 0)
return -1; return -1;

@ -29,6 +29,7 @@ enum op {
OP_TOGGLE, OP_TOGGLE,
OP_MACRO, OP_MACRO,
OP_COMMAND,
OP_TIMEOUT OP_TIMEOUT
}; };

@ -68,7 +68,7 @@ static int device_init(const char *path, struct device *dev)
int fd; int fd;
int type; int type;
if ((fd = open(path, O_RDWR | O_NONBLOCK, 0600)) < 0) { if ((fd = open(path, O_RDWR | O_NONBLOCK | O_CLOEXEC, 0600)) < 0) {
fprintf(stderr, "failed to open %s\n", path); fprintf(stderr, "failed to open %s\n", path);
return -1; return -1;
} }
@ -167,7 +167,7 @@ int devmon_create()
assert(!init); assert(!init);
init = 1; init = 1;
int fd = inotify_init1(IN_NONBLOCK); int fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (fd < 0) { if (fd < 0) {
perror("inotify"); perror("inotify");
exit(-1); exit(-1);

@ -324,6 +324,33 @@ static void activate_layer(struct keyboard *kbd, uint8_t code, struct layer *lay
kbd->last_layer_code = code; kbd->last_layer_code = code;
} }
static void execute_command(const char *cmd)
{
int fd;
dbg("Executing command: %s", cmd);
if (fork())
return;
fd = open("/dev/null", O_RDWR);
if (fd < 0) {
perror("open");
exit(-1);
}
close(0);
close(1);
close(2);
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
execl("/bin/sh", "/bin/sh", "-c", cmd);
}
static void clear_oneshot(struct keyboard *kbd) static void clear_oneshot(struct keyboard *kbd)
{ {
size_t i = 0; size_t i = 0;
@ -348,6 +375,7 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code,
struct macro *macros = kbd->layer_table.macros; struct macro *macros = kbd->layer_table.macros;
struct timeout *timeouts = kbd->layer_table.timeouts; struct timeout *timeouts = kbd->layer_table.timeouts;
struct layer *layers = kbd->layer_table.layers; struct layer *layers = kbd->layer_table.layers;
struct command *commands = kbd->layer_table.commands;
switch (d->op) { switch (d->op) {
struct macro *macro; struct macro *macro;
@ -476,6 +504,10 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code,
timeout = kbd->pending_timeout.t.timeout; timeout = kbd->pending_timeout.t.timeout;
} }
break; break;
case OP_COMMAND:
if (pressed)
execute_command(commands[d->args[0].idx].cmd);
break;
case OP_SWAP: case OP_SWAP:
layer = &layers[d->args[0].idx]; layer = &layers[d->args[0].idx];
macro = d->args[1].idx == -1 ? NULL : &macros[d->args[1].idx]; macro = d->args[1].idx == -1 ? NULL : &macros[d->args[1].idx];

@ -16,6 +16,9 @@
#define MAX_MACRO_SIZE 64 #define MAX_MACRO_SIZE 64
#define MAX_MACROS 256 #define MAX_MACROS 256
#define MAX_COMMAND_LEN 256
#define MAX_COMMANDS 64
#define LT_NORMAL 0 #define LT_NORMAL 0
#define LT_LAYOUT 1 #define LT_LAYOUT 1
#define LT_COMPOSITE 2 #define LT_COMPOSITE 2
@ -32,7 +35,7 @@
*/ */
struct layer { struct layer {
char name[MAX_LAYER_NAME_LEN]; char name[MAX_LAYER_NAME_LEN+1];
size_t nr_layers; size_t nr_layers;
int layers[MAX_COMPOSITE_LAYERS]; int layers[MAX_COMPOSITE_LAYERS];
@ -48,6 +51,10 @@ struct layer {
long activation_time; long activation_time;
}; };
struct command {
char cmd[MAX_COMMAND_LEN+1];
};
struct timeout { struct timeout {
uint16_t timeout; uint16_t timeout;
struct descriptor d1; struct descriptor d1;
@ -84,9 +91,11 @@ struct layer_table {
struct timeout timeouts[MAX_TIMEOUTS]; struct timeout timeouts[MAX_TIMEOUTS];
struct macro macros[MAX_MACROS]; struct macro macros[MAX_MACROS];
struct command commands[MAX_COMMANDS];
size_t nr_macros; size_t nr_macros;
size_t nr_timeouts; size_t nr_timeouts;
size_t nr_commands;
}; };
#endif #endif

@ -36,7 +36,7 @@ static int create_virtual_keyboard(const char *name)
size_t code; size_t code;
struct uinput_user_dev udev = {0}; struct uinput_user_dev udev = {0};
int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK | O_CLOEXEC);
if (fd < 0) { if (fd < 0) {
perror("open uinput"); perror("open uinput");
exit(-1); exit(-1);
@ -93,7 +93,7 @@ static int create_virtual_pointer(const char *name)
uint16_t code; uint16_t code;
struct uinput_user_dev udev = {0}; struct uinput_user_dev udev = {0};
int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK | O_CLOEXEC);
if (fd < 0) { if (fd < 0) {
perror("open"); perror("open");
exit(-1); exit(-1);

Loading…
Cancel
Save