refactor: Clean up key handling logic + reduce output noise

This patch attempts to minimize the number of extraneous modifier events. We
 used to do this in v1, but impetuously abandoned the attempt in the name of
 reducing code complexity.

 We achieve this by strategically updating modifier state and internally
 reintroducing key sequences as distinct (from macros) entities, which are tied
 to the generating key down/up pair.

 This will be transparent to most users, but should make the output sequences
 easier to reason about and may help in certain edge cases (#184) or in the
 case of software with buggy input systems (#181).
master
Raheman Vaiya 4 years ago
parent 9325bf375a
commit a5e6a83798
  1. 4
      TODO
  2. 12
      src/config.c
  3. 4
      src/config.h
  4. 24
      src/descriptor.c
  5. 3
      src/descriptor.h
  6. 14
      src/device.h
  7. 4
      src/ini.h
  8. 7
      src/ipc.h
  9. 612
      src/keyboard.c
  10. 25
      src/keyboard.h
  11. 6
      src/keys.c
  12. 16
      src/keys.h
  13. 9
      src/layer.h
  14. 11
      src/vkbd.h
  15. 6
      t/composite.t
  16. 8
      t/composite2.t
  17. 4
      t/layout-seq.t
  18. 4
      t/layout.t
  19. 13
      t/oneshot-single-key.t
  20. 2
      t/oneshot10.t
  21. 2
      t/oneshot12.t
  22. 2
      t/oneshot14.t
  23. 2
      t/oneshot5.t
  24. 2
      t/oneshot6.t
  25. 2
      t/oneshotn.t
  26. 2
      t/oneshotn3.t
  27. 4
      t/swap9.t
  28. 2
      t/toggle2.t

@ -1,7 +1,7 @@
streamline test logic
organize tests
cleanup manpage cleanup manpage
[idea] tmux like layer timeouts [idea] tmux like layer timeouts
nested timeouts? (perhaps not...)
toggleable composite layers? toggleable composite layers?
improved mouse support (integrate moused?) improved mouse support (integrate moused?)
organize tests
multi-user support (remove keyd group) multi-user support (remove keyd group)

@ -49,19 +49,19 @@ static int config_add_layer(struct config *config, const char *s)
if (name && layer_table_lookup(&config->layer_table, name) != -1) if (name && layer_table_lookup(&config->layer_table, name) != -1)
return 1; return 1;
if (config->layer_table.nr >= MAX_LAYERS) { if (config->layer_table.nr_layers >= MAX_LAYERS) {
err("max layers (%d) exceeded", MAX_LAYERS); err("max layers (%d) exceeded", MAX_LAYERS);
return -1; return -1;
} }
ret = create_layer(&config->layer_table.layers[config->layer_table.nr], ret = create_layer(&config->layer_table.layers[config->layer_table.nr_layers],
s, s,
&config->layer_table); &config->layer_table);
if (ret < 0) if (ret < 0)
return -1; return -1;
config->layer_table.nr++; config->layer_table.nr_layers++;
return 0; return 0;
} }
@ -82,8 +82,9 @@ static void config_init(struct config *config)
km = config->layer_table.layers[0].keymap; km = config->layer_table.layers[0].keymap;
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
km[i].op = OP_KEYCODE; km[i].op = OP_KEYSEQUENCE;
km[i].args[0].code = i; km[i].args[0].code = i;
km[i].args[1].mods = 0;
} }
for (i = 0; i < MAX_MOD; i++) { for (i = 0; i < MAX_MOD; i++) {
@ -101,8 +102,7 @@ static void config_init(struct config *config)
ent2->args[0].idx = idx; ent2->args[0].idx = idx;
} }
config->layer_table.layers[0].flags = LF_ACTIVE; config->layer_table.layers[0].active = 1;
/* In ms */ /* In ms */
config->macro_timeout = 600; config->macro_timeout = 600;
config->macro_repeat_timeout = 50; config->macro_repeat_timeout = 50;

@ -19,7 +19,7 @@ struct config {
long layer_indicator; long layer_indicator;
}; };
const char *config_find_path(const char *dir, uint16_t vendor, uint16_t product); int config_parse(struct config *config, const char *path);
int config_parse(struct config *config, const char *path); const char *config_find_path(const char *dir, uint16_t vendor, uint16_t product);
#endif #endif

@ -85,21 +85,6 @@ exit:
} }
} }
static uint8_t parse_code(const char *s)
{
size_t i;
for (i = 0; i < 256; i++) {
const struct keycode_table_ent *ent = &keycode_table[i];
if ((ent->name && !strcmp(ent->name, s)) ||
(ent->alt_name && !strcmp(ent->alt_name, s)))
return i;
}
return 0;
}
static int parse_sequence(const char *s, uint8_t *codep, uint8_t *modsp) static int parse_sequence(const char *s, uint8_t *codep, uint8_t *modsp)
{ {
const char *c = s; const char *c = s;
@ -390,7 +375,7 @@ int layer_table_lookup(const struct layer_table *lt, const char *name)
{ {
size_t i; size_t i;
for (i = 0; i < lt->nr; i++) for (i = 0; i < lt->nr_layers; i++)
if (!strcmp(lt->layers[i].name, name)) if (!strcmp(lt->layers[i].name, name))
return i; return i;
@ -566,7 +551,7 @@ int parse_descriptor(const char *descstr,
char *fn = NULL; char *fn = NULL;
char *args[MAX_ARGS]; char *args[MAX_ARGS];
size_t nargs = 0; size_t nargs = 0;
uint8_t code; uint8_t code, mods;
int idx; int idx;
int ret; int ret;
@ -579,9 +564,10 @@ int parse_descriptor(const char *descstr,
strcpy(fnstr, descstr); strcpy(fnstr, descstr);
if ((code = parse_code(descstr))) { if (!parse_sequence(descstr, &code, &mods)) {
d->op = OP_KEYCODE; d->op = OP_KEYSEQUENCE;
d->args[0].code = code; d->args[0].code = code;
d->args[1].mods = mods;
/* TODO: fixme. */ /* TODO: fixme. */
if (keycode_to_mod(code)) if (keycode_to_mod(code))

@ -20,7 +20,7 @@ struct layer_table;
enum op { enum op {
OP_UNDEFINED, OP_UNDEFINED,
OP_KEYCODE, OP_KEYSEQUENCE,
OP_ONESHOT, OP_ONESHOT,
OP_SWAP, OP_SWAP,
@ -39,6 +39,7 @@ struct descriptor {
union { union {
uint8_t code; uint8_t code;
uint8_t mods;
int16_t idx; int16_t idx;
uint16_t sz; uint16_t sz;
uint16_t timeout; uint16_t timeout;

@ -41,14 +41,14 @@ struct device_event {
}; };
struct device_event *device_read_event(struct device *dev); struct device_event *device_read_event(struct device *dev);
int device_scan(struct device devices[MAX_DEVICES]); int device_scan(struct device devices[MAX_DEVICES]);
int device_grab(struct device *dev); int device_grab(struct device *dev);
int device_ungrab(struct device *dev); int device_ungrab(struct device *dev);
int devmon_create(); int devmon_create();
struct device *devmon_read_device(int fd); struct device *devmon_read_device(int fd);
void device_set_led(const struct device *dev, int led, int state); void device_set_led(const struct device *dev, int led, int state);
#endif #endif

@ -56,8 +56,8 @@ struct ini {
* freed. * freed.
*/ */
struct ini *ini_parse_file(const char *path, const char *default_section_name); struct ini *ini_parse_file(const char *path, const char *default_section_name);
int parse_kvp(char *s, char **key, char **value); int parse_kvp(char *s, char **key, char **value);
#endif #endif

@ -22,9 +22,8 @@
#define MAX_MESSAGE_SIZE 4096 #define MAX_MESSAGE_SIZE 4096
int ipc_create_server(const char *path);
int ipc_create_server(const char *path); void ipc_server_process_connection(int sd, int (*handler) (int fd, const char *input));
void ipc_server_process_connection(int sd, int (*handler) (int fd, const char *input)); int ipc_run(const char *socket, const char *input);
int ipc_run(const char *socket, const char *input);
#endif #endif

@ -14,18 +14,65 @@
#include "descriptor.h" #include "descriptor.h"
#include "layer.h" #include "layer.h"
static struct macro *active_macro = NULL; /*
static uint8_t active_macro_mods = 0; * Here be tiny dragons.
static uint8_t oneshot_latch = 0; */
static long get_time() static long get_time()
{ {
/* close enough :/. using a syscall is unnecessary. */ /* Close enough :/. Using a syscall is unnecessary. */
static long time = 1; static long time = 1;
return time++; return time++;
} }
static void kbd_send_key(struct keyboard *kbd, uint8_t code, uint8_t pressed) static int cache_set(struct keyboard *kbd, uint8_t code,
const struct descriptor *d, struct layer *dl)
{
size_t i;
int slot = -1;
for (i = 0; i < CACHE_SIZE; i++)
if (kbd->cache[i].code == code) {
slot = i;
break;
} else if (!kbd->cache[i].code) {
slot = i;
}
if (slot == -1)
return -1;
if (d == NULL) {
kbd->cache[slot].code = 0;
} else {
kbd->cache[slot].code = code;
kbd->cache[slot].d = *d;
kbd->cache[slot].dl = dl;
}
return 0;
}
static int cache_get(struct keyboard *kbd, uint8_t code,
struct descriptor *d, struct layer **dl)
{
size_t i;
for (i = 0; i < CACHE_SIZE; i++)
if (kbd->cache[i].code == code) {
if (d)
*d = kbd->cache[i].d;
if (dl)
*dl = kbd->cache[i].dl;
return 0;
}
return -1;
}
static void send_key(struct keyboard *kbd, uint8_t code, uint8_t pressed)
{ {
if (code == KEYD_NOOP || code == KEYD_EXTERNAL_MOUSE_BUTTON) if (code == KEYD_NOOP || code == KEYD_EXTERNAL_MOUSE_BUTTON)
return; return;
@ -51,14 +98,7 @@ static void kbd_send_key(struct keyboard *kbd, uint8_t code, uint8_t pressed)
} }
} }
/* static void set_mods(struct keyboard *kbd, uint8_t mods)
* refcounted to account for overlapping active mods without adding manual
* accounting to the calling code, each send_mods(foo, 1) *must* be accompanied
* by a corresponding send_mods(foo, 0) at some point. Failure to do so is
* considered a bug (i.e treat this like malloc).
*/
static void send_mods(struct keyboard *kbd, uint8_t mods, int press)
{ {
size_t i; size_t i;
@ -67,63 +107,66 @@ static void send_mods(struct keyboard *kbd, uint8_t mods, int press)
uint8_t mask = modifier_table[i].mask; uint8_t mask = modifier_table[i].mask;
if (mask & mods) { if (mask & mods) {
kbd->modstate[i] += press ? 1 : -1; if (!kbd->keystate[code])
send_key(kbd, code, 1);
if (kbd->modstate[i] == 0) } else {
kbd_send_key(kbd, code, 0); /*
else if (kbd->modstate[i] == 1) * Some modifiers have a special meaning when used in
kbd_send_key(kbd, code, 1); * 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->inhibit_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);
}
}
} }
} }
} }
/* intelligently disarm active mods to avoid spurious alt/meta keypresses. */ static void update_mods(struct keyboard *kbd, struct layer *excluded_layer, uint8_t mods)
static void disarm_mods(struct keyboard *kbd, uint8_t mods)
{ {
uint8_t dmods = (MOD_ALT|MOD_SUPER) & mods; int i;
/*
* We interpose a control sequence to prevent '<alt down> <alt up>' for (i = 0; i < (int)kbd->layer_table.nr_layers; i++) {
* from being interpreted as an alt keypress. struct layer *layer = &kbd->layer_table.layers[i];
*/ int excluded = 0;
if (dmods && ((kbd->last_pressed_output_code == KEYD_LEFTMETA) || (kbd->last_pressed_output_code == KEYD_LEFTALT))) {
if (kbd->keystate[KEYD_LEFTCTRL]) if (!layer->active)
send_mods(kbd, dmods, 0); continue;
else {
kbd_send_key(kbd, KEYD_LEFTCTRL, 1); if (layer == excluded_layer) {
send_mods(kbd, dmods, 0); excluded = 1;
kbd_send_key(kbd, KEYD_LEFTCTRL, 0); } else if (excluded_layer && excluded_layer->type == LT_COMPOSITE) {
size_t j;
for (j = 0; j < excluded_layer->nr_layers; j++)
if (excluded_layer->layers[j] == i)
excluded = 1;
} }
mods &= ~dmods; if (!excluded)
mods |= layer->mods;
} }
send_mods(kbd, mods, 0); set_mods(kbd, mods);
} }
static void execute_macro(struct keyboard *kbd, const struct macro *macro, uint8_t disable_mods) static void execute_macro(struct keyboard *kbd, struct layer *dl, const struct macro *macro)
{ {
size_t i; size_t i;
int hold_start = -1; int hold_start = -1;
/*
* Minimize unnecessary noise by avoiding redundant modifier key up/down
* events in the case that the requisite modifiers are already present
* in the layer modifier set and the macro is a simple key sequence.
*
* This makes common cases like:
*
* [meta]
*
* a = M-b
*
* less likely to produce undesirable side effects as a consequence of additional
* meta up/down presses.
*/
if (macro->sz == 1 && macro->entries[0].type == MACRO_KEYSEQUENCE)
disable_mods &= ~(macro->entries[0].data >> 8);
disarm_mods(kbd, disable_mods);
for (i = 0; i < macro->sz; i++) { for (i = 0; i < macro->sz; i++) {
const struct macro_entry *ent = &macro->entries[i]; const struct macro_entry *ent = &macro->entries[i];
@ -133,10 +176,12 @@ static void execute_macro(struct keyboard *kbd, const struct macro *macro, uint8
uint8_t code, mods; uint8_t code, mods;
case MACRO_HOLD: case MACRO_HOLD:
if (hold_start == -1) if (hold_start == -1) {
update_mods(kbd, dl, 0);
hold_start = i; hold_start = i;
}
kbd_send_key(kbd, ent->data, 1); send_key(kbd, ent->data, 1);
break; break;
case MACRO_RELEASE: case MACRO_RELEASE:
@ -145,7 +190,7 @@ static void execute_macro(struct keyboard *kbd, const struct macro *macro, uint8
for (j = hold_start; j < i; j++) { for (j = hold_start; j < i; j++) {
const struct macro_entry *ent = &macro->entries[j]; const struct macro_entry *ent = &macro->entries[j];
kbd_send_key(kbd, ent->data, 0); send_key(kbd, ent->data, 0);
} }
hold_start = -1; hold_start = -1;
@ -154,15 +199,15 @@ static void execute_macro(struct keyboard *kbd, const struct macro *macro, uint8
case MACRO_UNICODE: case MACRO_UNICODE:
n = ent->data; n = ent->data;
kbd_send_key(kbd, KEYD_LINEFEED, 1); send_key(kbd, KEYD_LINEFEED, 1);
kbd_send_key(kbd, KEYD_LINEFEED, 0); send_key(kbd, KEYD_LINEFEED, 0);
for (j = 10000; j; j /= 10) { for (j = 10000; j; j /= 10) {
int digit = n / j; int digit = n / j;
code = digit == 0 ? KEYD_0 : digit - 1 + KEYD_1; code = digit == 0 ? KEYD_0 : digit - 1 + KEYD_1;
kbd_send_key(kbd, code, 1); send_key(kbd, code, 1);
kbd_send_key(kbd, code, 0); send_key(kbd, code, 0);
n %= j; n %= j;
} }
break; break;
@ -171,12 +216,11 @@ static void execute_macro(struct keyboard *kbd, const struct macro *macro, uint8
mods = ent->data >> 8; mods = ent->data >> 8;
if (kbd->keystate[code]) if (kbd->keystate[code])
kbd_send_key(kbd, code, 0); send_key(kbd, code, 0);
send_mods(kbd, mods, 1); update_mods(kbd, dl, mods);
kbd_send_key(kbd, code, 1); send_key(kbd, code, 1);
kbd_send_key(kbd, code, 0); send_key(kbd, code, 0);
send_mods(kbd, mods, 0);
break; break;
case MACRO_TIMEOUT: case MACRO_TIMEOUT:
@ -186,58 +230,30 @@ static void execute_macro(struct keyboard *kbd, const struct macro *macro, uint8
} }
send_mods(kbd, disable_mods, 1); update_mods(kbd, NULL, 0);
}
int kbd_execute_expression(struct keyboard *kbd, const char *exp)
{
return layer_table_add_entry(&kbd->layer_table, exp);
}
void kbd_reset(struct keyboard *kbd)
{
uint8_t flags[MAX_LAYERS];
long at[MAX_LAYERS];
size_t i;
/* Preserve layer state to facilitate hotswapping (TODO: make this more robust) */
for (i = 0; i < kbd->config.layer_table.nr; i++) {
flags[i] = kbd->layer_table.layers[i].flags;
at[i] = kbd->layer_table.layers[i].activation_time;
}
memcpy(&kbd->layer_table,
&kbd->config.layer_table,
sizeof(kbd->layer_table));
for (i = 0; i < kbd->config.layer_table.nr; i++) {
kbd->layer_table.layers[i].flags = flags[i];
kbd->layer_table.layers[i].activation_time = at[i];
}
} }
static void lookup_descriptor(struct keyboard *kbd, uint8_t code, uint8_t *layer_mods, struct descriptor *d) static void lookup_descriptor(struct keyboard *kbd, uint8_t code,
struct descriptor *d, struct layer **dl)
{ {
size_t max; size_t max;
size_t i; size_t i;
uint8_t active[MAX_LAYERS]; uint8_t active[MAX_LAYERS];
struct layer_table *lt = &kbd->layer_table; struct layer_table *lt = &kbd->layer_table;
d->op = OP_UNDEFINED; d->op = OP_UNDEFINED;
*layer_mods = 0;
long maxts = 0; long maxts = 0;
for (i = 0; i < lt->nr; i++) { for (i = 0; i < lt->nr_layers; i++) {
struct layer *layer = &lt->layers[i]; struct layer *layer = &lt->layers[i];
if (layer->flags) { if (layer->active) {
active[i] = 1; active[i] = 1;
if (layer->keymap[code].op && layer->activation_time >= maxts) { if (layer->keymap[code].op && layer->activation_time >= maxts) {
maxts = layer->activation_time; maxts = layer->activation_time;
*layer_mods = layer->mods;
*d = layer->keymap[code]; *d = layer->keymap[code];
*dl = layer;
} }
} else { } else {
active[i] = 0; active[i] = 0;
@ -246,7 +262,7 @@ static void lookup_descriptor(struct keyboard *kbd, uint8_t code, uint8_t *layer
max = 0; max = 0;
/* Scan for any composite matches (which take precedence). */ /* Scan for any composite matches (which take precedence). */
for (i = 0; i < lt->nr; i++) { for (i = 0; i < lt->nr_layers; i++) {
struct layer *layer = &lt->layers[i]; struct layer *layer = &lt->layers[i];
if (layer->type == LT_COMPOSITE) { if (layer->type == LT_COMPOSITE) {
@ -262,7 +278,7 @@ static void lookup_descriptor(struct keyboard *kbd, uint8_t code, uint8_t *layer
} }
if (match && layer->keymap[code].op && (layer->nr_layers > max)) { if (match && layer->keymap[code].op && (layer->nr_layers > max)) {
*layer_mods = mods; *dl = layer;
*d = layer->keymap[code]; *d = layer->keymap[code];
max = layer->nr_layers; max = layer->nr_layers;
@ -271,231 +287,180 @@ static void lookup_descriptor(struct keyboard *kbd, uint8_t code, uint8_t *layer
} }
} }
static int cache_set(struct keyboard *kbd, uint8_t code, const struct descriptor *d, uint8_t mods) static void update_leds(struct keyboard *kbd)
{ {
size_t i; struct layer_table *lt = &kbd->layer_table;
int slot = -1;
for (i = 0; i < CACHE_SIZE; i++) if (!kbd->config.layer_indicator)
if (kbd->cache[i].code == code) { return;
slot = i;
break;
} else if (!kbd->cache[i].code) {
slot = i;
}
if (slot == -1) size_t i;
return -1; int active = 0;
if (d == NULL) { for (i = 0; i < lt->nr_layers; i++) {
kbd->cache[slot].code = 0; if (lt->layers[i].active && lt->layers[i].mods)
} else { active = 1;
kbd->cache[slot].code = code;
kbd->cache[slot].d = *d;
kbd->cache[slot].layermods = mods;
} }
return 0; device_set_led(kbd->dev, 1, active);
} }
static int cache_get(struct keyboard *kbd, uint8_t code, struct descriptor *d, uint8_t *mods) static void deactivate_layer(struct keyboard *kbd, struct layer *layer)
{ {
size_t i; if (layer->active > 0)
layer->active--;
for (i = 0; i < CACHE_SIZE; i++)
if (kbd->cache[i].code == code) {
if (d)
*d = kbd->cache[i].d;
if (mods)
*mods = kbd->cache[i].layermods;
return 0;
}
return -1;
} }
static void activate_layer(struct keyboard *kbd, struct layer *layer) /*
{ * NOTE: Every activation call *must* be paired with a
layer->flags |= LF_ACTIVE; * corresponding deactivation call.
send_mods(kbd, layer->mods, 1); */
layer->activation_time = get_time();
}
static void deactivate_layer(struct keyboard *kbd, struct layer *layer, int disarm_p) static void activate_layer(struct keyboard *kbd, uint8_t code, struct layer *layer)
{ {
layer->flags &= ~LF_ACTIVE; layer->active++;
layer->activation_time = get_time();
if (disarm_p) kbd->last_layer_code = code;
disarm_mods(kbd, layer->mods);
else
send_mods(kbd, layer->mods, 0);
} }
static void update_leds(struct keyboard *kbd) static void clear_oneshot(struct keyboard *kbd)
{ {
struct layer_table *lt = &kbd->layer_table; size_t i = 0;
struct layer *layers = kbd->layer_table.layers;
if (!kbd->config.layer_indicator) size_t nr_layers = kbd->layer_table.nr_layers;
return;
size_t i;
int active = 0;
for (i = 0; i < lt->nr; i++) { for (i = 0; i < nr_layers; i++)
if (lt->layers[i].flags && lt->layers[i].mods) if (layers[i].flags & LF_ONESHOT) {
active = 1; layers[i].flags &= ~LF_ONESHOT;
} deactivate_layer(kbd, &layers[i]);
}
if (active) { kbd->oneshot_latch = 0;
device_set_led(kbd->dev, 1, 1);
} else {
device_set_led(kbd->dev, 1, 0);
}
} }
static long process_descriptor(struct keyboard *kbd, uint8_t code, struct descriptor *d, int descriptor_layer_mods, int pressed) static long process_descriptor(struct keyboard *kbd, uint8_t code,
struct descriptor *d, struct layer *dl,
int pressed)
{ {
int timeout = 0; int timeout = 0;
uint8_t clear_oneshot = 0;
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;
size_t nr_layers = kbd->layer_table.nr;
switch (d->op) { switch (d->op) {
struct macro *macro; struct macro *macro;
struct layer *layer; struct layer *layer;
uint8_t mods;
case OP_MACRO: case OP_KEYSEQUENCE:
macro = &macros[d->args[0].idx]; code = d->args[0].code;
mods = d->args[1].mods;
if (pressed) { if (pressed) {
execute_macro(kbd, macro, descriptor_layer_mods); /*
* Permit variations of the same key
* to be actuated next to each other
* E.G [/{
*/
if (kbd->keystate[code])
send_key(kbd, code, 0);
active_macro = macro; update_mods(kbd, dl, mods);
active_macro_mods = descriptor_layer_mods;
timeout = kbd->config.macro_timeout; send_key(kbd, code, 1);
clear_oneshot(kbd);
} else {
send_key(kbd, code, 0);
update_mods(kbd, NULL, 0);
} }
oneshot_latch = 0;
clear_oneshot = 1;
break; break;
case OP_ONESHOT: case OP_LAYER:
layer = &layers[d->args[0].idx]; layer = &layers[d->args[0].idx];
if (pressed) { if (pressed) {
if (layer->flags & LF_ONESHOT_HELD) { activate_layer(kbd, code, layer);
/* Neutralize key up */
cache_set(kbd, code, NULL, 0);
} else {
if (layer->flags & LF_ONESHOT) {
disarm_mods(kbd, layer->mods);
layer->flags &= ~LF_ONESHOT;
}
send_mods(kbd, layer->mods, 1);
oneshot_latch = 1;
layer->flags |= LF_ONESHOT_HELD;
layer->activation_time = get_time();
}
} else if (oneshot_latch) {
if (layer->flags & LF_ONESHOT) {
/*
* If oneshot is already set for the layer we can't
* rely on the clear logic to mirror our send_mod()
* call.
*/
disarm_mods(kbd, layer->mods);
} else {
layer->flags |= LF_ONESHOT;
layer->flags &= ~LF_ONESHOT_HELD;
}
} else { } else {
send_mods(kbd, layer->mods, 0); deactivate_layer(kbd, layer);
}
layer->flags &= ~LF_ONESHOT_HELD; if (kbd->last_pressed_code == code) {
kbd->inhibit_modifier_guard = 1;
update_mods(kbd, NULL, 0);
kbd->inhibit_modifier_guard = 0;
} else {
update_mods(kbd, NULL, 0);
} }
break; break;
case OP_TOGGLE: case OP_OVERLOAD:
layer = &layers[d->args[0].idx]; layer = &layers[d->args[0].idx];
macro = &macros[d->args[1].idx];
if (!pressed) {
layer->flags ^= LF_TOGGLE;
if (layer->flags & LF_TOGGLE)
activate_layer(kbd, layer);
else
deactivate_layer(kbd, layer, 0);
}
clear_oneshot = 1;
break;
case OP_KEYCODE:
if (pressed) { if (pressed) {
disarm_mods(kbd, descriptor_layer_mods); activate_layer(kbd, code, layer);
kbd_send_key(kbd, d->args[0].code, 1); update_mods(kbd, NULL, 0);
} else { } else {
kbd_send_key(kbd, d->args[0].code, 0); deactivate_layer(kbd, layer);
send_mods(kbd, descriptor_layer_mods, 1);
clear_oneshot = 1; if (kbd->last_pressed_code == code) {
clear_oneshot(kbd);
update_mods(kbd, dl, 0);
execute_macro(kbd, dl, macro);
}
update_mods(kbd, NULL, 0);
} }
oneshot_latch = 0;
break; break;
case OP_LAYER: case OP_ONESHOT:
layer = &layers[d->args[0].idx]; layer = &layers[d->args[0].idx];
if (pressed) { if (pressed) {
activate_layer(kbd, layer); if (layer->active) {
kbd->last_layer_code = code; /* Neutralize the upstroke. */
cache_set(kbd, code, NULL, NULL);
} else {
activate_layer(kbd, code, layer);
update_mods(kbd, dl, 0);
kbd->oneshot_latch = 1;
}
} else { } else {
deactivate_layer(kbd, layer, kbd->last_pressed_keycode != code); if (kbd->oneshot_latch) {
layer->flags |= LF_ONESHOT;
} else {
deactivate_layer(kbd, layer);
update_mods(kbd, NULL, 0);
}
} }
break; break;
case OP_SWAP: case OP_MACRO:
layer = &layers[d->args[0].idx]; macro = &macros[d->args[0].idx];
macro = d->args[1].idx == -1 ? NULL : &macros[d->args[1].idx];
if (pressed) { if (pressed) {
struct descriptor od; clear_oneshot(kbd);
if (!cache_get(kbd, kbd->last_layer_code, &od, NULL)) {
struct layer *oldlayer = &layers[od.args[0].idx];
cache_set(kbd, kbd->last_layer_code, d, descriptor_layer_mods); execute_macro(kbd, dl, macro);
cache_set(kbd, code, NULL, 0); kbd->active_macro = macro;
kbd->active_macro_layer = dl;
activate_layer(kbd, layer); timeout = kbd->config.macro_timeout;
deactivate_layer(kbd, oldlayer, 1); }
if (macro)
execute_macro(kbd, macro, layer->mods);
}
} else
deactivate_layer(kbd, layer, 1);
break; break;
case OP_OVERLOAD: case OP_TOGGLE:
layer = &layers[d->args[0].idx]; layer = &layers[d->args[0].idx];
macro = &macros[d->args[1].idx];
if (pressed) {
activate_layer(kbd, layer);
kbd->last_layer_code = code;
} else {
deactivate_layer(kbd, layer, 1);
if (kbd->last_pressed_keycode == code) { if (!pressed) {
execute_macro(kbd, macro, descriptor_layer_mods); layer->flags ^= LF_TOGGLED;
oneshot_latch = 0; if (layer->flags & LF_TOGGLED)
clear_oneshot = 1; activate_layer(kbd, code, layer);
} else
deactivate_layer(kbd, layer);
} }
break; break;
@ -503,44 +468,52 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code, struct descri
if (pressed) { if (pressed) {
kbd->pending_timeout.t = timeouts[d->args[0].idx]; kbd->pending_timeout.t = timeouts[d->args[0].idx];
kbd->pending_timeout.code = code; kbd->pending_timeout.code = code;
kbd->pending_timeout.mods = descriptor_layer_mods; kbd->pending_timeout.dl = dl;
kbd->pending_timeout.active = 1;
timeout = kbd->pending_timeout.t.timeout; timeout = kbd->pending_timeout.t.timeout;
} }
break; break;
case OP_UNDEFINED: case OP_SWAP:
if (pressed) layer = &layers[d->args[0].idx];
clear_oneshot = 1; macro = d->args[1].idx == -1 ? NULL : &macros[d->args[1].idx];
break;
}
if (clear_oneshot) {
size_t i = 0;
for (i = 0; i < nr_layers; i++) { if (pressed) {
struct layer *layer = &layers[i]; struct descriptor od;
struct layer *odl;
if (!cache_get(kbd, kbd->last_layer_code, &od, &odl)) {
struct layer *oldlayer = &layers[od.args[0].idx];
if (layer->flags & LF_ONESHOT) { cache_set(kbd, kbd->last_layer_code, d, odl);
layer->flags &= ~LF_ONESHOT; cache_set(kbd, code, NULL, 0);
activate_layer(kbd, kbd->last_layer_code, layer);
deactivate_layer(kbd, oldlayer);
update_mods(kbd, layer, 0);
send_mods(kbd, layer->mods, 0); if (macro)
execute_macro(kbd, layer, macro);
} }
} else {
deactivate_layer(kbd, layer);
update_mods(kbd, layer, mods);
} }
oneshot_latch = 0; break;
} }
update_leds(kbd);
if (pressed) if (pressed)
kbd->last_pressed_keycode = code; kbd->last_pressed_code = code;
update_leds(kbd);
return timeout; return timeout;
} }
/* /*
* Here be tiny dragons.
*
* `code` may be 0 in the event of a timeout. * `code` may be 0 in the event of a timeout.
* *
* The return value corresponds to a timeout before which the next invocation * The return value corresponds to a timeout before which the next invocation
@ -548,54 +521,87 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code, struct descri
* main loop to call at liberty. * main loop to call at liberty.
*/ */
long kbd_process_key_event(struct keyboard *kbd, long kbd_process_key_event(struct keyboard *kbd,
uint8_t code, uint8_t code, int pressed)
int pressed)
{ {
uint8_t descriptor_layer_mods; struct layer *dl;
struct descriptor d; struct descriptor d;
/* timeout */ /* timeout */
if (!code) { if (!code) {
if (active_macro) { if (kbd->active_macro) {
execute_macro(kbd, active_macro, active_macro_mods); execute_macro(kbd, kbd->active_macro_layer, kbd->active_macro);
return kbd->config.macro_repeat_timeout; return kbd->config.macro_repeat_timeout;
} else if (kbd->pending_timeout.code) { }
uint8_t mods = kbd->pending_timeout.mods;
if (kbd->pending_timeout.active) {
struct layer *dl = kbd->pending_timeout.dl;
uint8_t code = kbd->pending_timeout.code; uint8_t code = kbd->pending_timeout.code;
struct descriptor *d = &kbd->pending_timeout.t.d2; struct descriptor *d = &kbd->pending_timeout.t.d2;
cache_set(kbd, code, d, mods); cache_set(kbd, code, d, dl);
kbd->pending_timeout.code = 0; kbd->pending_timeout.active = 0;
return process_descriptor(kbd, code, d, mods, 1); return process_descriptor(kbd, code, d, dl, 1);
} }
} } else {
if (kbd->pending_timeout.active) {
struct layer *dl = kbd->pending_timeout.dl;
uint8_t code = kbd->pending_timeout.code;
struct descriptor *d = &kbd->pending_timeout.t.d1;
if (kbd->pending_timeout.code) { cache_set(kbd, code, d, dl);
uint8_t mods = kbd->pending_timeout.mods; process_descriptor(kbd, code, d, dl, 1);
uint8_t code = kbd->pending_timeout.code; }
struct descriptor *d = &kbd->pending_timeout.t.d1;
cache_set(kbd, code, d, mods); if (kbd->active_macro) {
process_descriptor(kbd, code, d, mods, 1); kbd->active_macro = NULL;
update_mods(kbd, NULL, 0);
}
kbd->pending_timeout.code = 0; kbd->pending_timeout.active = 0;
} }
if (active_macro)
active_macro = NULL;
if (pressed) { if (pressed) {
lookup_descriptor(kbd, code, &descriptor_layer_mods, &d); lookup_descriptor(kbd, code, &d, &dl);
if (cache_set(kbd, code, &d, descriptor_layer_mods) < 0) if (cache_set(kbd, code, &d, dl) < 0)
return 0; return 0;
} else { } else {
if (cache_get(kbd, code, &d, &descriptor_layer_mods) < 0) if (cache_get(kbd, code, &d, &dl) < 0)
return 0; return 0;
cache_set(kbd, code, NULL, 0); cache_set(kbd, code, NULL, NULL);
}
return process_descriptor(kbd, code, &d, dl, pressed);
}
int kbd_execute_expression(struct keyboard *kbd, const char *exp)
{
return layer_table_add_entry(&kbd->layer_table, exp);
}
void kbd_reset(struct keyboard *kbd)
{
uint8_t ad[MAX_LAYERS];
long at[MAX_LAYERS];
size_t i;
/* Preserve layer state to facilitate hotswapping (TODO: make this more robust) */
for (i = 0; i < kbd->config.layer_table.nr_layers; i++) {
ad[i] = kbd->layer_table.layers[i].active;
at[i] = kbd->layer_table.layers[i].activation_time;
} }
return process_descriptor(kbd, code, &d, descriptor_layer_mods, pressed); memcpy(&kbd->layer_table,
&kbd->config.layer_table,
sizeof(kbd->layer_table));
for (i = 0; i < kbd->config.layer_table.nr_layers; i++) {
kbd->layer_table.layers[i].active = ad[i];
kbd->layer_table.layers[i].activation_time = at[i];
}
} }

@ -15,7 +15,7 @@
struct cache_entry { struct cache_entry {
uint8_t code; uint8_t code;
struct descriptor d; struct descriptor d;
uint8_t layermods; struct layer *dl;
}; };
struct keyboard { struct keyboard {
@ -25,23 +25,34 @@ struct keyboard {
struct layer_table layer_table; struct layer_table layer_table;
/* state*/ /*
* Cache descriptors to preserve code->descriptor
/* for key up events */ * mappings in the event of mid-stroke layer changes.
*/
struct cache_entry cache[CACHE_SIZE]; struct cache_entry cache[CACHE_SIZE];
uint8_t transient_mods;
uint8_t last_pressed_output_code; uint8_t last_pressed_output_code;
uint8_t last_pressed_keycode; uint8_t last_pressed_code;
uint8_t last_layer_code; uint8_t last_layer_code;
uint8_t oneshot_latch;
uint8_t inhibit_modifier_guard;
struct macro *active_macro;
struct layer *active_macro_layer;
struct { struct {
uint8_t active;
uint8_t code; uint8_t code;
uint8_t mods; struct layer *dl;
struct timeout t; struct timeout t;
} pending_timeout; } pending_timeout;
uint8_t keystate[256]; uint8_t keystate[256];
uint8_t modstate[MAX_MOD];
}; };
long kbd_process_key_event(struct keyboard *kbd, uint8_t code, int pressed); long kbd_process_key_event(struct keyboard *kbd, uint8_t code, int pressed);

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

@ -10,17 +10,14 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#define MOD_ALT_GR 0x10 #define MOD_ALT_GR 0x10
#define MOD_CTRL 0x8 #define MOD_CTRL 0x8
#define MOD_SHIFT 0x4 #define MOD_SHIFT 0x4
#define MOD_SUPER 0x2 #define MOD_SUPER 0x2
#define MOD_ALT 0x1 #define MOD_ALT 0x1
#define MAX_MOD 5 #define MAX_MOD 5
uint8_t keycode_to_mod(uint8_t code);
int parse_modset(const char *s, uint8_t *mods);
struct keycode_table_ent { struct keycode_table_ent {
const char *name; const char *name;
const char *alt_name; const char *alt_name;
@ -291,6 +288,9 @@ struct modifier_table_ent {
#define KEYD_MOUSE_2 253 #define KEYD_MOUSE_2 253
#define KEYD_FN 254 #define KEYD_FN 254
uint8_t keycode_to_mod(uint8_t code);
int parse_modset(const char *s, uint8_t *mods);
extern const struct modifier_table_ent modifier_table[MAX_MOD]; extern const struct modifier_table_ent modifier_table[MAX_MOD];
extern const struct keycode_table_ent keycode_table[256]; extern const struct keycode_table_ent keycode_table[256];

@ -20,10 +20,8 @@
#define LT_LAYOUT 1 #define LT_LAYOUT 1
#define LT_COMPOSITE 2 #define LT_COMPOSITE 2
#define LF_ACTIVE 0x1 #define LF_TOGGLED 0x1
#define LF_TOGGLE 0x2 #define LF_ONESHOT 0x2
#define LF_ONESHOT 0x4
#define LF_ONESHOT_HELD 0x8
/* /*
* A layer is a map from keycodes to descriptors. It may optionally * A layer is a map from keycodes to descriptors. It may optionally
@ -45,6 +43,7 @@ struct layer {
struct descriptor keymap[256]; struct descriptor keymap[256];
/* state */ /* state */
uint8_t active;
uint8_t flags; uint8_t flags;
long activation_time; long activation_time;
}; };
@ -78,7 +77,7 @@ struct macro {
struct layer_table { struct layer_table {
struct layer layers[MAX_LAYERS]; struct layer layers[MAX_LAYERS];
size_t nr; size_t nr_layers;
struct timeout timeouts[MAX_TIMEOUTS]; struct timeout timeouts[MAX_TIMEOUTS];
struct macro macros[MAX_MACROS]; struct macro macros[MAX_MACROS];

@ -10,11 +10,12 @@
struct vkbd; struct vkbd;
struct vkbd *vkbd_init(const char *name); struct vkbd *vkbd_init(const char *name);
void vkbd_move_mouse(const struct vkbd *vkbd, int x, int y);
void vkbd_send_key(const struct vkbd *vkbd, uint8_t code, int state);
void vkbd_send_button(const struct vkbd *vkbd, uint8_t btn, int state);
void free_vkbd(struct vkbd *vkbd); void vkbd_move_mouse(const struct vkbd *vkbd, int x, int y);
void vkbd_send_key(const struct vkbd *vkbd, uint8_t code, int state);
void vkbd_send_button(const struct vkbd *vkbd, uint8_t btn, int state);
void free_vkbd(struct vkbd *vkbd);
#endif #endif

@ -8,14 +8,12 @@ alt up
control down control down
alt down alt down
alt up alt up
control up
shift down shift down
control up
h down h down
h up h up
alt down
shift up shift up
control down control down
alt down
control up control up
control down
alt up alt up
control up

@ -11,15 +11,13 @@ control down
shift down shift down
alt down alt down
alt up alt up
control up
shift up shift up
control up
left down left down
left up left up
control down
shift down
alt down alt down
shift down
control down
control up control up
shift up shift up
control down
alt up alt up
control up

@ -1,11 +1,11 @@
9 down 9 down
9 up 9 up
control down
shift down shift down
meta down meta down
control down
x down x down
x up x up
control up
shift up shift up
meta up meta up
control up

@ -14,14 +14,14 @@ x up
o down o down
o up o up
alt down alt down
control down
shift down shift down
meta down meta down
control down
x down x down
x up x up
control up
shift up shift up
meta up meta up
control up
alt up alt up
x down x down
x up x up

@ -0,0 +1,13 @@
2 down
2 up
u down
i down
u up
i up
shift down
u down
shift up
i down
u up
i up

@ -11,7 +11,5 @@ o down
o up o up
n down n down
n up n up
shift down
shift up
x down x down
x up x up

@ -16,8 +16,6 @@ o up
n down n down
n up n up
shift down shift down
shift up
shift down
a down a down
a up a up
shift up shift up

@ -11,7 +11,5 @@ shift down
shift up shift up
a down a down
a up a up
shift down
shift up
b down b down
b up b up

@ -9,5 +9,5 @@ shift down
control down control down
i down i down
i up i up
control up
shift up shift up
control up

@ -9,5 +9,5 @@ shift down
control down control down
i down i down
i up i up
control up
shift up shift up
control up

@ -7,5 +7,3 @@ control down
control up control up
b down b down
b up b up
control down
control up

@ -9,5 +9,5 @@ control down
shift down shift down
i down i down
i up i up
control up
shift up shift up
control up

@ -6,14 +6,12 @@ a up
alt up alt up
alt down alt down
meta down
control down control down
alt up alt up
control up control up
meta down
a down a down
a up a up
b down b down
b up b up
control down
meta up meta up
control up

@ -11,8 +11,6 @@ t up
b down b down
b up b up
shift down
shift up
shift down shift down
shift up shift up
a down a down

Loading…
Cancel
Save