diff --git a/src/config.c b/src/config.c index 5b65566..b69a1a7 100644 --- a/src/config.c +++ b/src/config.c @@ -4,6 +4,7 @@ * © 2019 Raheman Vaiya (see also: LICENSE). */ +#include #include #include #include @@ -517,21 +518,74 @@ int parse_macro_expression(const char *s, struct macro *macro) return macro_parse(ptr, macro) == 0 ? 0 : 1; } -static int parse_command(const char *s, struct command *command) +static int parse_command(const char *s, struct command *command, char **args, struct descriptor *d) { int len = strlen(s); - - if (len == 0 || strstr(s, "command(") != s || s[len-1] != ')') + if (len == 0 || strstr(s, "command") != s || s[len-1] != ')') return -1; - if (len > (int)sizeof(command->cmd)) { - err("max command length (%ld) exceeded\n", sizeof(command->cmd)); - return 1; - } + if (s[7] == '(') { + if (len-7 > (int)sizeof(command->cmd)) { + err("max command length (%ld) exceeded\n", sizeof(command->cmd)); + return 1; + } + + if (!strlen(s+9)) { + err("command requires 1 argument"); + return 1; + } + + strcpy(command->cmd, s+8); + command->cmd[len-9] = 0; + str_escape(command->cmd); + d->op = OP_COMMAND; - strcpy(command->cmd, s+8); - command->cmd[len-9] = 0; - str_escape(command->cmd); + return 0; + } else if (s[7] == '2' && s[8] == '(') { + size_t nargs = 0; + char *c = alloca(strlen(s+9)+1); + strcpy(c, s+9); + + for (int i=0; i<=2; i++){ + while (*c == ' ') + c++; + + args[i] = c; + if (i < 2) { + while (*c != ',' && *c) + c++; + + if (c != args[i] && *c) + (nargs)++; + + *c++ = 0; + } else { + c[strlen(c)-1] = 0; + (nargs)++; + } + } + + if (nargs < 3) { + err("command2 requires 3 arguments"); + return 1; + } + + if (strlen(c)+1 > (int)sizeof(command->cmd)) { + err("max command length (%ld) exceeded\n", sizeof(command->cmd)); + return 1; + } + + strcpy(command->cmd, args[2]); + str_escape(command->cmd); + + d->op = OP_COMMAND2; + d->args[1].timeout = atoi(args[0]); + d->args[2].timeout = atoi(args[1]); + + return 0; + } else { + return -1; + } return 0; } @@ -580,7 +634,7 @@ static int parse_descriptor(char *s, d->args[1].mods = mods; return 0; - } else if ((ret=parse_command(s, &cmd)) >= 0) { + } else if ((ret=parse_command(s, &cmd, args, d)) >= 0) { if (ret) { return -1; } @@ -590,10 +644,7 @@ static int parse_descriptor(char *s, return -1; } - - d->op = OP_COMMAND; d->args[0].idx = config->nr_commands; - config->commands[config->nr_commands++] = cmd; return 0; @@ -738,6 +789,8 @@ static void parse_global_section(struct config *config, struct ini_section *sect if (!strcmp(ent->key, "macro_timeout")) config->macro_timeout = atoi(ent->val); + else if (!strcmp(ent->key, "command_timeout")) + config->command_timeout = atoi(ent->val); else if (!strcmp(ent->key, "macro_sequence_timeout")) config->macro_sequence_timeout = atoi(ent->val); else if (!strcmp(ent->key, "disable_modifier_guard")) @@ -753,6 +806,8 @@ static void parse_global_section(struct config *config, struct ini_section *sect "%s", ent->val); else if (!strcmp(ent->key, "macro_repeat_timeout")) config->macro_repeat_timeout = atoi(ent->val); + else if (!strcmp(ent->key, "command_repeat_timeout")) + config->command_repeat_timeout = atoi(ent->val); else if (!strcmp(ent->key, "layer_indicator")) config->layer_indicator = atoi(ent->val); else if (!strcmp(ent->key, "overload_tap_timeout")) @@ -944,6 +999,8 @@ static void config_init(struct config *config) config->macro_timeout = 600; config->macro_repeat_timeout = 50; + config->command_timeout = 0; + config->command_repeat_timeout = 0; } int config_parse(struct config *config, const char *path) diff --git a/src/config.h b/src/config.h index e961f5d..5f29bb8 100644 --- a/src/config.h +++ b/src/config.h @@ -46,6 +46,7 @@ enum op { OP_MACRO, OP_MACRO2, OP_COMMAND, + OP_COMMAND2, OP_TIMEOUT, /* Experimental */ @@ -137,6 +138,8 @@ struct config { long macro_sequence_timeout; long macro_repeat_timeout; long oneshot_timeout; + long command_timeout; + long command_repeat_timeout; long overload_tap_timeout; diff --git a/src/keyboard.c b/src/keyboard.c index b21d6df..9b7db35 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -425,6 +425,7 @@ static void clear(struct keyboard *kbd) } kbd->active_macro = NULL; + kbd->active_command = NULL; reset_keystate(kbd); } @@ -727,11 +728,22 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code, } break; + case OP_COMMAND2: case OP_COMMAND: if (pressed) { + if (d->op == OP_COMMAND2) { + timeout = d->args[1].timeout; + kbd->command_repeat_interval = d->args[2].timeout; + } else { + timeout = kbd->config.command_timeout; + kbd->command_repeat_interval = kbd->config.command_repeat_timeout; + } execute_command(kbd->config.commands[d->args[0].idx].cmd); + kbd->active_command = kbd->config.commands[d->args[0].idx].cmd; clear_oneshot(kbd); - update_mods(kbd, -1, 0); + + kbd->command_timeout = time + timeout; + schedule_timeout(kbd, kbd->command_timeout); } break; case OP_SWAP: @@ -1146,6 +1158,17 @@ static long process_event(struct keyboard *kbd, uint8_t code, int pressed, long } } + if (kbd->active_command) { + if (code) { + kbd->active_command = NULL; + update_mods(kbd, -1, 0); + } else if (time >= kbd->command_timeout) { + execute_command(kbd->active_command); + kbd->command_timeout = time+kbd->command_repeat_interval; + schedule_timeout(kbd, kbd->command_timeout); + } + } + if (code) { struct descriptor d; int dl = 0; diff --git a/src/keyboard.h b/src/keyboard.h index dc94075..1cb259c 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -55,13 +55,16 @@ struct keyboard { uint8_t inhibit_modifier_guard; struct macro *active_macro; + const char *active_command; int active_macro_layer; int overload_last_layer_code; long macro_timeout; long oneshot_timeout; + long command_timeout; long macro_repeat_interval; + long command_repeat_interval; long overload_start_time;