refactor: Clean up config logic

Simplify the modifier table and reuse config parsing logic to simplify
config initialization. This comes with a small performance
penalty when parsing configs (~50 us), but makes things much
tidier.
master
Raheman Vaiya 3 years ago
parent 10df81b988
commit 5fd41ab2a0
  1. 2
      Makefile
  2. 125
      src/config.c
  3. 58
      src/keyboard.c
  4. 13
      src/keys.c
  5. 9
      src/keys.h
  6. 13
      src/macro.c

@ -98,7 +98,7 @@ test-io:
src/string.c \
src/macro.c \
src/config.c \
src/error.c \
src/log.c \
src/ini.c \
src/keys.c \
src/unicode.c && \

@ -390,50 +390,6 @@ static int config_add_layer(struct config *config, const char *s)
return 0;
}
static void config_init(struct config *config)
{
size_t i;
memset(config, 0, sizeof *config);
config_add_layer(config, "main");
config_add_layer(config, "control:C");
config_add_layer(config, "meta:M");
config_add_layer(config, "shift:S");
config_add_layer(config, "altgr:G");
config_add_layer(config, "alt:A");
/* Add default modifier bindings to the main layer. */
for (i = 0; i < MAX_MOD; i++) {
const struct modifier_table_ent *mod = &modifier_table[i];
struct descriptor *d1 = &config->layers[0].keymap[mod->code1];
struct descriptor *d2 = &config->layers[0].keymap[mod->code2];
int idx = config_get_layer_index(config, mod->name);
assert(idx != -1);
d1->op = OP_LAYER;
d1->args[0].idx = idx;
d2->op = OP_LAYER;
d2->args[0].idx = idx;
strcpy(config->aliases[mod->code1], mod->name);
strcpy(config->aliases[mod->code2], mod->name);
}
/* In ms */
config->chord_interkey_timeout = 50;
config->chord_hold_timeout = 0;
config->oneshot_timeout = 0;
config->macro_timeout = 600;
config->macro_repeat_timeout = 50;
}
/* Modifies the input string */
static int parse_fn(char *s,
char **name,
@ -598,7 +554,7 @@ static int parse_descriptor(char *s,
/* TODO: fixme. */
if (keycode_to_mod(code))
warn("y{NOTE:} mapping modifier keycodes directly may produce unintended results.\n");
warn("y{NOTE:} mapping modifier keycodes directly may produce unintended results.");
return 0;
} else if ((ret=parse_command(s, &cmd)) >= 0) {
@ -803,7 +759,7 @@ static void parse_id_section(struct config *config, struct ini_section *section)
config->ids[config->nr_ids].flags = ID_KEYBOARD | ID_MOUSE;
config->nr_ids++;
}
}
else {
warn("%s is not a valid device id", s);
}
@ -844,27 +800,18 @@ static void parse_alias_section(struct config *config, struct ini_section *secti
}
}
int config_parse(struct config *config, const char *path)
static int config_parse_string(struct config *config, char *content)
{
size_t i;
char *content;
struct ini *ini;
struct ini_section *section;
config_init(config);
if (!(content = read_file(path)))
return -1;
if (!(ini = ini_parse_string(content, NULL)))
return -1;
snprintf(config->path, sizeof(config->path), "%s", path);
/* First pass: create all layers based on section headers. */
for (i = 0; i < ini->nr_sections; i++) {
section = &ini->sections[i];
struct ini_section *section = &ini->sections[i];
if (!strcmp(section->name, "ids")) {
parse_id_section(config, section);
@ -882,7 +829,7 @@ int config_parse(struct config *config, const char *path)
for (i = 0; i < ini->nr_sections; i++) {
size_t j;
char *layername;
section = &ini->sections[i];
struct ini_section *section = &ini->sections[i];
if (!strcmp(section->name, "ids") ||
!strcmp(section->name, "aliases") ||
@ -910,6 +857,64 @@ int config_parse(struct config *config, const char *path)
return 0;
}
static void config_init(struct config *config)
{
size_t i;
memset(config, 0, sizeof *config);
char default_config[] =
"[aliases]\n"
"leftshift = shift\n"
"rightshift = shift\n"
"leftalt = alt\n"
"rightalt = altgr\n"
"leftmeta = meta\n"
"rightmeta = meta\n"
"leftcontrol = control\n"
"rightcontrol = control\n"
"[main]\n"
"shift = layer(shift)\n"
"alt = layer(alt)\n"
"altgr = layer(altgr)\n"
"meta = layer(meta)\n"
"control = layer(control)\n"
"[control:C]\n"
"[shift:S]\n"
"[meta:M]\n"
"[alt:A]\n"
"[altgr:G]\n";
config_parse_string(config, default_config);
/* In ms */
config->chord_interkey_timeout = 50;
config->chord_hold_timeout = 0;
config->oneshot_timeout = 0;
config->macro_timeout = 600;
config->macro_repeat_timeout = 50;
}
int config_parse(struct config *config, const char *path)
{
char *content;
if (!(content = read_file(path)))
return -1;
config_init(config);
snprintf(config->path, sizeof(config->path), "%s", path);
return config_parse_string(config, content);
}
int config_check_match(struct config *config, uint16_t vendor, uint16_t product, uint8_t flags)
{
size_t i;
@ -941,7 +946,7 @@ int config_get_layer_index(const struct config *config, const char *name)
return -1;
}
/*
/*
* Adds a binding of the form [<layer>.]<key> = <descriptor expression>
* to the given config.
*/

@ -83,40 +83,45 @@ static void send_key(struct keyboard *kbd, uint8_t code, uint8_t pressed)
}
}
static void clear_mod(struct keyboard *kbd, uint8_t code)
{
/*
* Some modifiers have a special meaning when used in
* isolation (e.g meta in Gnome, alt in Firefox).
* In order to prevent spurious key presses we
* avoid adjacent down/up pairs by interposing
* additional control sequences.
*/
int guard = (((kbd->last_pressed_output_code == code) &&
(code == KEYD_LEFTMETA ||
code == KEYD_LEFTALT ||
code == KEYD_RIGHTALT)) &&
!kbd->inhibit_modifier_guard &&
!kbd->config.disable_modifier_guard);
if (guard && !kbd->keystate[KEYD_LEFTCTRL]) {
send_key(kbd, KEYD_LEFTCTRL, 1);
send_key(kbd, code, 0);
send_key(kbd, KEYD_LEFTCTRL, 0);
} else {
send_key(kbd, code, 0);
}
}
static void set_mods(struct keyboard *kbd, uint8_t mods)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(modifier_table); i++) {
uint8_t code = modifier_table[i].code1;
uint8_t mask = modifier_table[i].mask;
for (i = 0; i < ARRAY_SIZE(modifiers); i++) {
uint8_t mask = modifiers[i].mask;
uint8_t code = modifiers[i].key;
if (mask & mods) {
if (!kbd->keystate[code])
send_key(kbd, code, 1);
} else {
/*
* Some modifiers have a special meaning when used in
* isolation (e.g meta in Gnome, alt in Firefox).
* In order to prevent spurious key presses we
* avoid adjacent down/up pairs by interposing
* additional control sequences.
*/
int guard = ((((kbd->last_pressed_output_code == KEYD_LEFTMETA) && mask == MOD_SUPER) ||
((kbd->last_pressed_output_code == KEYD_LEFTALT) && mask == MOD_ALT) ||
((kbd->last_pressed_output_code == KEYD_RIGHTALT) && mask == MOD_ALT_GR)) &&
!kbd->inhibit_modifier_guard &&
!kbd->config.disable_modifier_guard);
if (kbd->keystate[code]) {
if (guard && !kbd->keystate[KEYD_LEFTCTRL]) {
send_key(kbd, KEYD_LEFTCTRL, 1);
send_key(kbd, code, 0);
send_key(kbd, KEYD_LEFTCTRL, 0);
} else {
send_key(kbd, code, 0);
}
}
if (kbd->keystate[code])
clear_mod(kbd, code);
}
}
}
@ -778,8 +783,7 @@ struct keyboard *new_keyboard(struct config *config,
}
if (!found)
fprintf(stderr,
"\tWARNING: could not find default layout %s.\n",
keyd_log("\tWARNING: could not find default layout %s.\n",
kbd->config.default_layout);
}

@ -7,13 +7,12 @@
#include <string.h>
#include "keys.h"
const struct modifier_table_ent modifier_table[MAX_MOD] = {
{"alt", MOD_ALT, KEYD_LEFTALT, 0},
{"altgr", MOD_ALT_GR, KEYD_RIGHTALT, 0},
{"shift", MOD_SHIFT, KEYD_LEFTSHIFT, KEYD_RIGHTSHIFT},
{"meta", MOD_SUPER, KEYD_LEFTMETA, KEYD_RIGHTMETA},
{"control", MOD_CTRL, KEYD_LEFTCTRL, KEYD_RIGHTCTRL},
const struct modifier modifiers[MAX_MOD] = {
{MOD_ALT, KEYD_LEFTALT},
{MOD_ALT_GR, KEYD_RIGHTALT},
{MOD_SHIFT, KEYD_LEFTSHIFT},
{MOD_SUPER, KEYD_LEFTMETA},
{MOD_CTRL, KEYD_LEFTCTRL},
};
const struct keycode_table_ent keycode_table[256] = {

@ -24,12 +24,9 @@ struct keycode_table_ent {
const char *shifted_name;
};
struct modifier_table_ent {
const char *name;
struct modifier {
uint8_t mask;
uint8_t code1;
uint8_t code2; /* May be 0. */
uint8_t key;
};
#define KEYD_ESC 1
@ -295,7 +292,7 @@ uint8_t keycode_to_mod(uint8_t code);
int parse_modset(const char *s, uint8_t *mods);
int parse_key_sequence(const char *s, uint8_t *code, uint8_t *mods);
extern const struct modifier_table_ent modifier_table[MAX_MOD];
extern const struct modifier modifiers[MAX_MOD];
extern const struct keycode_table_ent keycode_table[256];
#endif

@ -131,9 +131,9 @@ void macro_execute(void (*output)(uint8_t, uint8_t),
code = ent->data;
mods = ent->data >> 8;
for (j = 0; j < ARRAY_SIZE(modifier_table); j++) {
uint8_t code = modifier_table[j].code1;
uint8_t mask = modifier_table[j].mask;
for (j = 0; j < ARRAY_SIZE(modifiers); j++) {
uint8_t code = modifiers[j].key;
uint8_t mask = modifiers[j].mask;
if (mods & mask)
output(code, 1);
@ -142,14 +142,15 @@ void macro_execute(void (*output)(uint8_t, uint8_t),
output(code, 1);
output(code, 0);
for (j = 0; j < ARRAY_SIZE(modifier_table); j++) {
uint8_t code = modifier_table[j].code1;
uint8_t mask = modifier_table[j].mask;
for (j = 0; j < ARRAY_SIZE(modifiers); j++) {
uint8_t code = modifiers[j].key;
uint8_t mask = modifiers[j].mask;
if (mods & mask)
output(code, 0);
}
break;
case MACRO_TIMEOUT:
usleep(ent->data * 1E3);

Loading…
Cancel
Save