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
Any user which can interact with a program that directly controls input devices
should be assumed to have full access to the system.
*Any user which can interact with a program that directly controls input devices
should be assumed to have full access to the system.*
While keyd offers slightly better isolation compared to other remappers by dint
of mediating access through an IPC mechanism (rather than granting users

@ -372,6 +372,15 @@ arguments.
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*
Do nothing.

@ -14,7 +14,9 @@
#define MAX_ARGS 5
/* modifies the input string */
/* TODO: Make this a bit nicer. */
/* Modifies the input string */
static int parse_fn(char *s,
char **name,
char *args[MAX_ARGS],
@ -314,13 +316,12 @@ static size_t escape(char *s)
return n;
}
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);
if (len >= MAX_MACROEXP_LEN) {
if (len > MAX_MACROEXP_LEN) {
err("macro exceeds maximum macro length (%d)", MAX_MACROEXP_LEN);
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)
{
uint8_t code1, code2;
char *keystr, *descstr, *c, *s;
char *keystr, *descstr, *dot, *paren, *s;
char *layername = "main";
struct descriptor d;
struct layer *layer;
@ -410,10 +411,13 @@ int layer_table_add_entry(struct layer_table *lt, const char *exp)
strcpy(buf, exp);
s = buf;
if ((c = strchr(s, '.'))) {
dot = strchr(s, '.');
paren = strchr(s, '(');
if (dot && (!paren || dot < paren)) {
layername = s;
*c = 0;
s = c+1;
*dot = 0;
s = dot+1;
}
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;
}
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:
*
@ -586,6 +620,11 @@ int parse_descriptor(const char *descstr,
if (keycode_to_mod(code))
fprintf(stderr,
"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) {
if (ret > 0)
return -1;

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

@ -68,7 +68,7 @@ static int device_init(const char *path, struct device *dev)
int fd;
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);
return -1;
}
@ -167,7 +167,7 @@ int devmon_create()
assert(!init);
init = 1;
int fd = inotify_init1(IN_NONBLOCK);
int fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (fd < 0) {
perror("inotify");
exit(-1);

@ -324,6 +324,33 @@ static void activate_layer(struct keyboard *kbd, uint8_t code, struct layer *lay
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)
{
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 timeout *timeouts = kbd->layer_table.timeouts;
struct layer *layers = kbd->layer_table.layers;
struct command *commands = kbd->layer_table.commands;
switch (d->op) {
struct macro *macro;
@ -476,6 +504,10 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code,
timeout = kbd->pending_timeout.t.timeout;
}
break;
case OP_COMMAND:
if (pressed)
execute_command(commands[d->args[0].idx].cmd);
break;
case OP_SWAP:
layer = &layers[d->args[0].idx];
macro = d->args[1].idx == -1 ? NULL : &macros[d->args[1].idx];

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

@ -36,7 +36,7 @@ static int create_virtual_keyboard(const char *name)
size_t code;
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) {
perror("open uinput");
exit(-1);
@ -93,7 +93,7 @@ static int create_virtual_pointer(const char *name)
uint16_t code;
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) {
perror("open");
exit(-1);

Loading…
Cancel
Save