Added layert() + resolve mapping conflicts.

master
Raheman Vaiya 5 years ago
parent 6f3674eb69
commit bc1c91a2f6
  1. 5
      CHANGELOG.md
  2. 2
      Makefile
  3. BIN
      keyd.1.gz
  4. 4
      man.md
  5. 12
      src/config.c
  6. 5
      src/config.h
  7. 160
      src/main.c

@ -1,3 +1,8 @@
# v1.0.1
- Added layert().
- No resolve layer conflicts by picking the most recently activated one in the case of multiple mappings.
# v1.0.0
Major version update:

@ -3,7 +3,7 @@
DESTDIR=
PREFIX=/usr
VERSION=1.0.0
VERSION=1.0.1
GIT_HASH=$(shell git describe --no-match --always --abbrev=40 --dirty)
CFLAGS=-DVERSION=\"$(VERSION)\" -DGIT_COMMIT_HASH=\"$(GIT_HASH)\"

Binary file not shown.

@ -150,6 +150,10 @@ like modifier stacking and pointer combos.
**layer(\<layer\>)**: Activates the given layer while held.
**layert(\<layer\>)**: Toggle the state of the given layer. Note this is
intended for transient layers and is distinct from layout() which should
be used for letter layouts.
**overload(\<keyseq\>,\<layer\>)**: Activates the given layer while held and emits the given key sequence when tapped.
**layout(\<layer\>)**: Sets the current layout to the given layer. You will likely want

@ -522,6 +522,18 @@ static int parse_descriptor(const char *_s, struct key_descriptor *desc)
desc->action = ACTION_LAYER;
desc->arg.layer = idx;
goto cleanup;
} else if(!strcmp(fn, "layert") && nargs == 1) {
int idx = lookup_layer(args[0]);
if(idx < 0) {
err("%s is not a valid layer.", args[0]);
goto fail;
}
desc->action = ACTION_LAYER_TOGGLE;
desc->arg.layer = idx;
goto cleanup;
} else if(!strcmp(fn, "layout") && nargs > 0) {
int idx;

@ -41,6 +41,7 @@ enum action {
ACTION_LAYOUT,
ACTION_KEYSEQ,
ACTION_LAYER,
ACTION_LAYER_TOGGLE,
ACTION_ONESHOT,
};
@ -66,6 +67,10 @@ struct key_descriptor
struct layer {
uint16_t mods;
struct key_descriptor *keymap;
//State
uint8_t active;
uint64_t timestamp;
};
struct keyboard_config {

@ -62,16 +62,14 @@ struct keyboard {
int fd;
char devnode[256];
uint8_t active_layers[MAX_LAYERS];
uint16_t mods; //The active modifier set
struct layer **layers;
size_t nlayers;
//The layer to which modifiers are applied,
//this may be distinct from the main layout
int modlayout;
struct layer *modlayout;
struct layer *layout;
int layout;
struct keyboard_config *cfg;
struct keyboard *next;
};
@ -100,6 +98,13 @@ static void _die(char *fmt, ...)
#define die(fmt, ...) _die("%s:%d: "fmt, __FILE__, __LINE__, ## __VA_ARGS__)
static uint64_t get_time()
{
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
return (tv.tv_sec*1E9)+tv.tv_nsec;
}
static int is_keyboard(struct udev_device *dev)
{
int is_keyboard = 0;
@ -259,66 +264,75 @@ static void setmods(uint16_t mods)
send_key(KEY_RIGHTALT, !keystate[KEY_RIGHTALT]);
}
static void reify_layer_mods(struct keyboard *kbd)
{
uint16_t mods = 0;
size_t i;
for(i = 0;i < kbd->nlayers;i++) {
struct layer *layer = kbd->layers[i];
if(layer->active)
mods |= layer->mods;
}
setmods(mods);
}
static struct key_descriptor *kbd_lookup_descriptor(struct keyboard *kbd, uint16_t code, uint16_t *modsp)
{
size_t i;
struct key_descriptor *desc = NULL;
int active_layers = 0;
struct layer *layer = NULL;
uint16_t mods = 0;
size_t i;
size_t nactive = 0;
for(i = 0;i < kbd->cfg->nlayers;i++) {
if(kbd->active_layers[i]) {
struct layer *layer = kbd->cfg->layers[i];
struct key_descriptor *d = &layer->keymap[code];
//Pick the most recently activated layer in which a mapping is defined.
if(!desc && d->action != ACTION_UNDEFINED)
for(i = 0;i < kbd->nlayers;i++) {
struct layer *l = kbd->layers[i];
struct key_descriptor *d = &l->keymap[code];
if(l->active) {
if(d->action && (!desc || (l->timestamp > layer->timestamp))) {
desc = d;
else
mods |= layer->mods;
layer = l;
}
active_layers++;
nactive++;
}
}
//Calculate the modifier union of active layers, excluding the mods for
//the layer in which the mapping is defined.
mods = 0;
for(i = 0;i < kbd->nlayers;i++) {
struct layer *l = kbd->layers[i];
if(l->active && l != layer)
mods |= l->mods;
}
if(!desc) {
//If any modifier layers are active and do not explicitly
//define a mapping, obtain the target from modlayout.
if(mods) {
//If the shift key is the only modifier active, we probably
//want to use the key layout.
if(mods == MOD_SHIFT || mods == MOD_ALT_GR)
desc = &kbd->cfg->layers[kbd->layout]->keymap[code];
desc = &kbd->layout->keymap[code];
else
desc = &kbd->cfg->layers[kbd->modlayout]->keymap[code];
} else if(active_layers)
return NULL;
desc = &kbd->modlayout->keymap[code];
} else if(!nactive) //If no layers are active use the default layout
desc = &kbd->layout->keymap[code];
else
desc = &kbd->cfg->layers[kbd->layout]->keymap[code];
return NULL;
}
*modsp = mods;
return desc;
}
static void reify_layer_mods(struct keyboard *kbd)
{
uint16_t mods = 0;
size_t i;
for(i = 0;i < kbd->cfg->nlayers;i++) {
struct layer *layer = kbd->cfg->layers[i];
if(kbd->active_layers[i])
mods |= layer->mods;
}
setmods(mods);
}
static uint64_t get_time()
{
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
return (tv.tv_sec*1E9)+tv.tv_nsec;
}
//Where the magic happens
static void process_event(struct keyboard *kbd, struct input_event *ev)
{
@ -366,17 +380,18 @@ static void process_event(struct keyboard *kbd, struct input_event *ev)
return;
switch(d->action) {
int layer;
struct layer *layer;
uint32_t keyseq;
case ACTION_OVERLOAD:
keyseq = d->arg.keyseq;
layer = d->arg2.layer;
layer = kbd->layers[d->arg2.layer];
if(pressed) {
kbd->active_layers[layer] = 1;
layer->active = 1;
layer->timestamp = get_time();
} else {
kbd->active_layers[layer] = 0;
layer->active = 0;
if(lastd == d) { //If tapped
uint16_t key = keyseq & 0xFF;
@ -386,6 +401,7 @@ static void process_event(struct keyboard *kbd, struct input_event *ev)
send_key(key, 1);
send_key(key, 0);
last_keyseq_timestamp = get_time();
goto keyseq_cleanup;
}
}
@ -393,26 +409,40 @@ static void process_event(struct keyboard *kbd, struct input_event *ev)
reify_layer_mods(kbd);
break;
case ACTION_LAYOUT:
kbd->layout = d->arg.layer;
kbd->modlayout = d->arg2.layer;
kbd->layout = kbd->layers[d->arg.layer];
kbd->modlayout = kbd->layers[d->arg2.layer];
dbg("layer: %d, modlayout: %d", kbd->layout, kbd->modlayout);
break;
case ACTION_ONESHOT:
if(pressed)
kbd->active_layers[d->arg.layer] = 1;
else if(pressed_timestamps[code] < last_keyseq_timestamp)
kbd->active_layers[d->arg.layer] = 0;
else //Tapped
layer = kbd->layers[d->arg.layer];
if(pressed) {
layer->active = 1;
layer->timestamp = get_time();
} else if(pressed_timestamps[code] < last_keyseq_timestamp) {
layer->active = 0;
} else //Tapped
oneshot_layers[d->arg.layer] = 1;
reify_layer_mods(kbd);
break;
case ACTION_LAYER_TOGGLE:
if(pressed) {
layer = kbd->layers[d->arg.layer];
layer->active = !layer->active;
reify_layer_mods(kbd);
}
break;
case ACTION_LAYER:
if(pressed)
kbd->active_layers[d->arg.layer] = 1;
else
kbd->active_layers[d->arg.layer] = 0;
layer = kbd->layers[d->arg.layer];
if(pressed) {
layer->active = 1;
layer->timestamp = get_time();
} else
layer->active = 0;
reify_layer_mods(kbd);
break;
@ -466,9 +496,9 @@ keyseq_cleanup:
last_keyseq_timestamp = get_time();
//Clear active oneshot layers.
for(i = 0;i < kbd->cfg->nlayers;i++) {
for(i = 0;i < kbd->nlayers;i++) {
if(oneshot_layers[i]) {
kbd->active_layers[i] = 0;
kbd->layers[i]->active = 0;
oneshot_layers[i] = 0;
}
}
@ -594,9 +624,11 @@ static int manage_keyboard(const char *devnode)
kbd = calloc(1, sizeof(struct keyboard));
kbd->fd = fd;
kbd->cfg = cfg;
kbd->modlayout = kbd->cfg->default_modlayout;
kbd->layout = kbd->cfg->default_layout;
kbd->layers = cfg->layers;
kbd->nlayers = cfg->nlayers;
kbd->modlayout = cfg->layers[cfg->default_modlayout];
kbd->layout = cfg->layers[cfg->default_layout];
strcpy(kbd->devnode, devnode);

Loading…
Cancel
Save