Rename swap2/toggle2/overload2 + add oneshotm and layerm

Switch to hungarian notation to distinguish between timeout and macro variants of
existing actions. The old names are kept for backward compatibility but will
eventually be removed.

toggle2 -> togglem
swap2 -> swapm
overload2 -> overloadt
overload3 -> overloadt2

oneshotm and layerm have also been added for completeness.
master
Raheman Vaiya 4 years ago
parent eb06a67532
commit 190bd68242
  1. 2
      TODO
  2. BIN
      data/keyd-application-mapper.1.gz
  3. BIN
      data/keyd.1.gz
  4. 197
      docs/keyd.scdoc
  5. 43
      src/config.c
  6. 10
      src/config.h
  7. 76
      src/keyboard.c
  8. 21
      t/layerm.t
  9. 17
      t/oneshotm.t
  10. 2
      t/swap5.t
  11. 2
      t/test.conf

@ -2,6 +2,6 @@ streamline test logic
organize tests
cleanup manpage
[idea] tmux like layer timeouts
toggleable composite layers?
improved mouse support (integrate moused?)
multi-user support (remove keyd group)
split up the man page + add FAQ

Binary file not shown.

Binary file not shown.

@ -56,13 +56,13 @@ terminate.
# CONFIGURATION
Configuration files loosely follow an INI style file format and consist of sections
of the form _[section_name]_ followed by key-value pairs delimited
by an equal sign (one per line). Lines which are empty or begin with a hash sign
are ignored.
Configuration files loosely follow an INI style format consisting of headers of
the form _[section_name]_ followed by a set of _bindings_. Lines beginning
with a hash are ignored.
The files are stored in _/etc/keyd/_ and loaded upon initialization.
Changes can be triggered using the reload command (sudo keyd reload).
Config files are stored in _/etc/keyd/_ and loaded upon initialization.
The reload command can be used to update the working set of config
files (e.g sudo keyd reload).
A valid config file has the extension _.conf_ and *must* begin with an _[ids]_
section that has one of the following forms:
@ -111,7 +111,7 @@ Each subsequent section of the file corresponds to a _layer_ (with the exception
of _[global]_ (see _GLOBALS_).
Config errors will appear in the log output and can be accessed in the usual
way using your system's service manager (e.g `sudo journalctl -eu keyd`).
way using your system's service manager (e.g sudo journalctl -eu keyd).
Note: All keyboards defined within a given config file will share the
same state. This is useful for linking separate input devices together
@ -170,6 +170,11 @@ will cause _capslock_ to behave as _control_, except in the case of _control+j_,
emit _down_. This makes it trivial to define custom modifiers which don't interfere with
one another.
Note that bindings are not affected by the modifiers of the layer in which they
are defined. Thus *capslock+j* will produce an unmodified *down* keypress, while
*shift+control+j* will produce *shift+down* as expected.
Formally, each layer heading has the following form:
```
@ -194,11 +199,6 @@ Finally, each layer heading is followed by a set of bindings which take the form
for a description of <action> and <macro> see _ACTIONS_ and _MACROS_.
As hinted at above, when a binding is activated through a key press, it inherits
the modifiers attached to all other currently active layers (irrespective of
their position in the layer stack) but ignores the modifier sets of the layer it
is defined on.
By default, each key is bound to itself within the main layer. The exception to this
are the modifier keys, which are instead bound to eponymously named layers with the
corresponding modifiers.
@ -234,34 +234,30 @@ the full config actually looks something like this:
j = down
```
A key may be bound multiple times on a given layer, in which
case every binding encountered overrides an earlier one. Furthermore, it is
allowed (but discouraged) to scatter layer bindings over multiple identically
named sections, again with later definitions taking precedence over earlier
ones. However, modifier sets of a repeated layer section are ignored. For
example
If multiple bindings for the same key are present, the most recent one takes precedence.
```
[mylayer:A]
a = b
A layer heading may also appear multiple times, in which case the layer will
contain the sum of all bindings. Note that the layer type may not be reassigned.
[control:C]
j = down
That is:
[mylayer:M]
a = c
b = d
```
[mylayer:A]
a = b
c = d
is equivalent to
[mylayer:C]
a = x
b = c
```
[mylayer:A]
a = c
b = d
[control:C]
j = down
is equivalent to:
```
[mylayer:A]
a = x
b = c
c = d
```
## Composite Layers
@ -270,15 +266,13 @@ A special kind of layer called a *composite layer* can be defined by creating a
layer with a name consisting of existing layers delimited by _+_. The resultant
layer will be activated and given precedence when all of its constituents are
activated. Composite layers are not allowed to have modifiers attached and
cannot be explicitly assigned. In the same way that an explicit binding on a
regular layer ignores the modifier set of that layer, an explicit binding on a
composite layer ignores the modifier sets of all constituents.
cannot be explicitly assigned.
E.g.
```
[control+alt]
h = left
[control+alt]
h = left
```
will cause the sequence _control+alt+h_ to produce _left_ (ignoring the control
@ -286,6 +280,19 @@ and alt modifiers attached to the active control and alt layers), while pressing
_control+alt+f1_ preserves those modifiers, emitting exactly what was pressed,
as there is no explicit binding for _f1_ on the composite layer.
```
[main]
capslock = layer(capslock)
[capslock:C]
[capslock+shift]
h = left
```
Will cause the sequence _capslock+shift+h_ to produce _left_, while preserving the expected functionality of _capslock_ and _shift_ in isolation.
*Note:* composite layers *must* always be defined _after_ the layers of which they
are comprised.
@ -355,26 +362,24 @@ E.g.
**Additionally you will need to be using the default US layout on your
display server.** Users of non-english layouts are advised to set their layout
within keyd (see **Layouts**).
within keyd (see **Layouts**) to avoid conflicts between the display server
layout and keyd's unicode functionality.
**Note:** You may have to restart your applications for this to take effect.
**Caveat:** Modifiers (in particular shift) are applied to this compose sequence
as usual, which might not be what you want. For example, pressing a key bound to
an accented letter while a shift modifier is active does not result in the
corresponding capital letter. In such cases, an explicit mapping on the shift
layer has to be added.
**Note 2:** The generated compose sequences are affected by modifiers in the
normal way. If you want shift to produce a different symbol, you will need to
define a custom shift layer (see the included layout files for an example).
## Aliases
Each key may optionally be assigned to an *alias*. This alias may be used in place
Each key may optionally be assigned an *alias*. This alias may be used in place
of the key as a valid left hand value. Multiple keys may be bound to the same alias,
but only one alias may be assigned to a key at a given time.
For example, the keys 'leftmeta' and 'rightmeta' are bound to the alias *meta*
by default. Thus the binding 'meta = a' is equivalent to the bindings 'leftmeta
= a' and 'rightmeta = a'. Further default aliases are *alt*, *shift*, *control*
(with bindings analogous to *meta*) and *altgr* (an alias for the key 'rightalt').
= a' and 'rightmeta = a'.
Aliases are defined in a special section called 'aliases' where each line takes
the form:
@ -489,8 +494,8 @@ Limitations:
# GLOBALS
A special section called _[global]_ may be defined in the file
and can contain any of the following options:
A special section called _[global]_ may be defined in the file and can contain
any of the following options:
*macro_timeout:* The time (in milliseconds) separating the initial execution of a macro
sequence and the first repetition.
@ -515,29 +520,28 @@ are consequently affected by the corresponding timeout options.
Various keyd actions accept macro expressions.
A valid macro expression has one of the following forms:
A macro expression has one of the following forms:
. macro(<exp>)
. [<modifier 1>[-<modifier 2>...]-<key>
. <utf8_character>
. <char>
Where _<exp>_ has the form _<token1> [<token2>...]_ and each token is one of:
Where _<char>_ is a valid unicode character and _<exp>_ has the form _<token1> [<token2>...]_ and each token is one of:
- a valid key code (_keyd list-keys_ prints a list).
- a type 2 macro.
- a contiguous group of UTF-8 characters.
- a group of key codes delimited by + to be depressed as a unit.
- a timeout of the form _<time>ms_ (where _<time>_ < n1024).
- A valid key code.
- A type 2 macro.
- A contiguous group of unicode characters.
- A group of key codes delimited by + to be depressed as a unit.
- A timeout of the form _<time>ms_ (where _<time>_ < 1024).
The following are all valid macro expressions:
- C-a
- macro(C-a) (equivalent to the above)
- macro(control+a) (yet another form of the above)
- macro(a+control) (not equivalent to the above, as a is pressed earlier than control)
- macro(C-a)
- macro(leftcontrol+leftmeta) # simultaneously taps the left meta and left control keys
- A-M-x
- macro(Hello space World)
- macro(h e l l o space w o r ld) (identical to the above)
- macro(h e l l o space w o r ld) (identical to the above)
- macro(C-t 100ms google.com enter)
Splitting into smaller tokens serves as an escaping mechanism: _macro(space)_
@ -548,47 +552,19 @@ Some prerequisites are needed for non-ASCII characters to work, see _Unicode Sup
# ACTIONS
A key may optionally be bound to an _action_ which accepts zero or more
arguments.
Whenever an argument is another action, a valid macro expressions may be supplied instead.
Whenever an argument is a layer, neither _main_, nor a composite layer are accepted.
## Manipulation of the layer stack
A key may optionally be bound to an _action_ which accepts zero or more arguments.
*layer(<layer>)*
Activate the given layer for the duration of the keypress.
*oneshot(<layer>)* If tapped, activate the supplied layer for the duration of
the next keypress. If _<layer>_ is a modifier layer then it will cause
the key to behave as the corresponding modifiers while held. If the next
pressed keys are bound to actions which resolve to further layer
activations (such as _layer_, _overload_, _oneshot_ or a _timeout_
resolving to one of the aforementioned three actions), the original
oneshot layer _<layer>_ is kept active. This makes it possible to stack
modifiers. Consider for example
*oneshot(<layer>)*
```
[main]
shift = overload(shift, S-9)
control = oneshot(control)
alt = oneshot(alt)
tab = timeout(oneshot(meta), 200, tab)
```
Here,
- tapping control, tapping alt and then tapping a would result in C-A-a.
- tapping control, holding shift and then tapping a would result in C-S-a.
- tapping control, tapping tab within 200 ms and then tapping a would result in C-M-a, and so would tapping control, holding meta (by default bound to _layer(meta)_) and then tapping a.
- tapping control, tapping tab within 200 ms, tapping alt and then tapping a would result in C-A-M-a.
If tapped, activate the supplied layer for the duration of the next keypress.
*swap(<layer>)*
Swap the currently active layer with the supplied one. The
supplied layer is active for the duration of the depression of the
current layer's activation key. This only works if a _layer_ action is
currently active (i.e. another key is held down) and results in a noop
otherwise.
current layer's activation key.
```
[control]
@ -601,30 +577,35 @@ Here,
b = S-insert
```
*swap2(<layer>, <macro>)*
*setlayout(<layout>)*
Set the current layout.
Identical to *swap*, but accepts a macro to be executed immediately after the layer change.
*clear()*
Clear any active layers (the active layout is preserved).
*toggle(<layer>)*
Permanently toggle the state of the given layer. Toggling the main layer
is not allowed.
Permanently toggle the state of the given layer.
*toggle2(<layer>, <macro>)*
Equivalent to *toggle*, but additionally executes the supplied macro before
toggling the layer.
*layerm(<layer>, <macro>)*
Identical to *layer*, but executes the supplies macro before the layer change.
*setlayout(<layout>)*
Set the current layout.
*oneshotm(<layer>, <macro>)*
Identical to *oneshot*, but executes the supplies macro before the layer change.
*clear()*
Clear any active layers (the active layout is preserved).
*swapm(<layer>, <macro>)*
Identical to *swap*, but accepts a macro to be executed immediately
after the layer change.
*togglem(<layer>, <macro>)*
Equivalent to *toggle*, but additionally executes the supplied macro before
toggling the layer.
## Key overloading
*overload(<layer>, <action>)*
Activates the given layer while held and executes <action> on tap.
*overload2(<layer>, <action>, <timeout>)*
*overloadt(<layer>, <action>, <timeout>)*
Identical to overload, but only activates the layer if the bound key is
held for \<timeout\> milliseconds. This is mainly useful for overloading keys
which are commonly struck in sequence (e.g letter keys).
@ -633,8 +614,8 @@ Here,
keys will be queued until the timeout expires or the bound key is
released.
*overload3(<layer>, <action>, <timeout>)*
Identical to overload2, but additionally resolves as a hold in the
*overloadt2(<layer>, <action>, <timeout>)*
Identical to overloadt, but additionally resolves as a hold in the
event of an intervening key tap.
*timeout(<action 1>, <timeout>, <action 2>)*
@ -649,8 +630,6 @@ Here,
Will cause the assigned key to behave as _control_ if it is held for more than
500 ms.
## Miscellaneous
*macro2(<timeout>, <repeat timeout>, <macro>)*
Creates a macro with the given timeout and repeat timeout. If a timeout value of 0 is used,
macro repeat is disabled.

@ -32,6 +32,7 @@
static struct {
const char *name;
const char *preferred_name;
uint8_t op;
enum {
ARG_EMPTY,
@ -43,19 +44,32 @@ static struct {
ARG_DESCRIPTOR,
} args[MAX_DESCRIPTOR_ARGS];
} actions[] = {
{ "swap", OP_SWAP, { ARG_LAYER } },
{ "swap2", OP_SWAP2, { ARG_LAYER, ARG_MACRO } },
{ "clear", OP_CLEAR, {} },
{ "oneshot", OP_ONESHOT, { ARG_LAYER } },
{ "toggle", OP_TOGGLE, { ARG_LAYER } },
{ "toggle2", OP_TOGGLE2, { ARG_LAYER, ARG_MACRO } },
{ "layer", OP_LAYER, { ARG_LAYER } },
{ "overload", OP_OVERLOAD, { ARG_LAYER, ARG_DESCRIPTOR } },
{ "overload2", OP_OVERLOAD2, { ARG_LAYER, ARG_DESCRIPTOR, ARG_TIMEOUT } },
{ "overload3", OP_OVERLOAD3, { ARG_LAYER, ARG_DESCRIPTOR, ARG_TIMEOUT } },
{ "timeout", OP_TIMEOUT, { ARG_DESCRIPTOR, ARG_TIMEOUT, ARG_DESCRIPTOR } },
{ "macro2", OP_MACRO2, { ARG_TIMEOUT, ARG_TIMEOUT, ARG_MACRO } },
{ "setlayout", OP_LAYOUT, { ARG_LAYOUT } },
{ "swap", NULL, OP_SWAP, { ARG_LAYER } },
{ "clear", NULL, OP_CLEAR, {} },
{ "oneshot", NULL, OP_ONESHOT, { ARG_LAYER } },
{ "toggle", NULL, OP_TOGGLE, { ARG_LAYER } },
{ "swapm", NULL, OP_SWAPM, { ARG_LAYER, ARG_MACRO } },
{ "togglem", NULL, OP_TOGGLEM, { ARG_LAYER, ARG_MACRO } },
{ "layerm", NULL, OP_LAYERM, { ARG_LAYER, ARG_MACRO } },
{ "oneshotm", NULL, OP_ONESHOTM, { ARG_LAYER, ARG_MACRO } },
{ "layer", NULL, OP_LAYER, { ARG_LAYER } },
{ "overload", NULL, OP_OVERLOAD, { ARG_LAYER, ARG_DESCRIPTOR } },
{ "overloadt", NULL, OP_OVERLOAD_TIMEOUT, { ARG_LAYER, ARG_DESCRIPTOR, ARG_TIMEOUT } },
{ "overloadt2", NULL, OP_OVERLOAD_TIMEOUT_TAP, { ARG_LAYER, ARG_DESCRIPTOR, ARG_TIMEOUT } },
{ "timeout", NULL, OP_TIMEOUT, { ARG_DESCRIPTOR, ARG_TIMEOUT, ARG_DESCRIPTOR } },
{ "macro2", NULL, OP_MACRO2, { ARG_TIMEOUT, ARG_TIMEOUT, ARG_MACRO } },
{ "setlayout", NULL, OP_LAYOUT, { ARG_LAYOUT } },
//TODO: deprecate
{ "overload2", "overloadt", OP_OVERLOAD_TIMEOUT, { ARG_LAYER, ARG_DESCRIPTOR, ARG_TIMEOUT } },
{ "overload3", "overloadt2", OP_OVERLOAD_TIMEOUT_TAP, { ARG_LAYER, ARG_DESCRIPTOR, ARG_TIMEOUT } },
{ "toggle2", "togglem", OP_TOGGLEM, { ARG_LAYER, ARG_MACRO } },
{ "swap2", "swapm", OP_SWAPM, { ARG_LAYER, ARG_MACRO } },
};
@ -538,6 +552,9 @@ static int parse_descriptor(char *s,
if (!strcmp(actions[i].name, fn)) {
int j;
if (actions[i].preferred_name)
warn("%s is deprecated (renamed to %s).", actions[i].name, actions[i].preferred_name);
d->op = actions[i].op;
for (j = 0; j < MAX_DESCRIPTOR_ARGS; j++) {

@ -25,16 +25,18 @@ enum op {
OP_KEYSEQUENCE = 1,
OP_ONESHOT,
OP_ONESHOTM,
OP_LAYERM,
OP_SWAP,
OP_SWAP2,
OP_SWAPM,
OP_LAYER,
OP_LAYOUT,
OP_CLEAR,
OP_OVERLOAD,
OP_OVERLOAD2,
OP_OVERLOAD3,
OP_OVERLOAD_TIMEOUT,
OP_OVERLOAD_TIMEOUT_TAP,
OP_TOGGLE,
OP_TOGGLE2,
OP_TOGGLEM,
OP_MACRO,
OP_MACRO2,

@ -159,8 +159,18 @@ static void update_mods(struct keyboard *kbd, int excluded_layer_idx, uint8_t mo
static void execute_macro(struct keyboard *kbd, int dl, const struct macro *macro)
{
update_mods(kbd, dl, 0);
macro_execute(kbd->output, macro, kbd->config.macro_sequence_timeout);
/* Minimize redundant modifier strokes for simple key sequences. */
if (macro->sz == 1 && macro->entries[0].type == MACRO_KEYSEQUENCE) {
uint8_t code = macro->entries[0].data;
uint8_t mods = macro->entries[0].data >> 8;
update_mods(kbd, dl, mods);
send_key(kbd, code, 1);
send_key(kbd, code, 0);
} else {
update_mods(kbd, dl, 0);
macro_execute(kbd->output, macro, kbd->config.macro_sequence_timeout);
}
}
static void lookup_descriptor(struct keyboard *kbd, uint8_t code,
@ -336,6 +346,21 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code,
{
int timeout = 0;
if (pressed) {
struct macro *macro;
switch (d->op) {
case OP_LAYERM:
case OP_ONESHOTM:
case OP_TOGGLEM:
macro = &kbd->config.macros[d->args[1].idx];
execute_macro(kbd, dl, macro);
break;
default:
break;
}
}
switch (d->op) {
int idx;
struct macro *macro;
@ -365,15 +390,15 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code,
}
break;
case OP_OVERLOAD3:
case OP_OVERLOAD2:
case OP_OVERLOAD_TIMEOUT_TAP:
case OP_OVERLOAD_TIMEOUT:
if (pressed) {
uint8_t layer = d->args[0].idx;
struct descriptor *action = &kbd->config.descriptors[d->args[1].idx];
timeout = d->args[2].idx;
kbd->overload2.active = 1;
kbd->overload2.resolve_on_tap = d->op == OP_OVERLOAD2 ? 0 : 1;
kbd->overload2.resolve_on_tap = d->op == OP_OVERLOAD_TIMEOUT_TAP ? 1 : 0;
kbd->overload2.code = code;
kbd->overload2.layer = layer;
kbd->overload2.action = action;
@ -391,6 +416,7 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code,
setlayout(kbd, d->args[0].idx);
break;
case OP_LAYERM:
case OP_LAYER:
idx = d->args[0].idx;
@ -434,6 +460,7 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code,
}
break;
case OP_ONESHOTM:
case OP_ONESHOT:
idx = d->args[0].idx;
@ -479,7 +506,7 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code,
}
break;
case OP_TOGGLE2:
case OP_TOGGLEM:
case OP_TOGGLE:
idx = d->args[0].idx;
@ -494,12 +521,6 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code,
update_mods(kbd, -1, 0);
} else {
clear_oneshot(kbd);
if (d->op == OP_TOGGLE2) {
macro = &kbd->config.macros[d->args[1].idx];
execute_macro(kbd, dl, macro);
}
}
break;
@ -521,15 +542,16 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code,
execute_command(kbd->config.commands[d->args[0].idx].cmd);
break;
case OP_SWAP:
case OP_SWAP2:
case OP_SWAPM:
idx = d->args[0].idx;
macro = d->op == OP_SWAP2 ? &kbd->config.macros[d->args[1].idx] : NULL;
macro = d->op == OP_SWAPM ? &kbd->config.macros[d->args[1].idx] : NULL;
if (pressed) {
struct descriptor od;
int odl;
if (!cache_get(kbd, kbd->last_layer_code, &od, &odl)) {
if (kbd->last_layer_code &&
!cache_get(kbd, kbd->last_layer_code, &od, &odl)) {
int oldlayer = od.args[0].idx;
od.args[0].idx = d->args[0].idx;
@ -537,28 +559,10 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code,
deactivate_layer(kbd, oldlayer);
activate_layer(kbd, kbd->last_layer_code, idx);
update_mods(kbd, -1, 0);
if (macro) {
/*
* If we are dealing with a simple macro of the form <mod>-<key>
* keep the corresponding key sequence depressed for the duration
* of the swapping key stroke. This is necessary to account for
* pathological input systems (e.g Gnome) which expect a human-scale
* interval between key down/up events.
*/
if (macro->sz == 1 &&
macro->entries[0].type == MACRO_KEYSEQUENCE) {
uint8_t code = macro->entries[0].data;
uint8_t mods = macro->entries[0].data >> 8;
update_mods(kbd, idx, mods);
send_key(kbd, code, 1);
} else {
execute_macro(kbd, dl, macro);
}
} else {
update_mods(kbd, -1, 0);
}
if (macro)
execute_macro(kbd, dl, macro);
}
} else {
if (macro &&

@ -0,0 +1,21 @@
p down
x down
x up
x down
x up
p up
x down
x up
o down
o up
n down
n up
shift down
x down
x up
x down
x up
shift up
x down
x up

@ -0,0 +1,17 @@
e down
e up
x down
x up
x down
x up
o down
o up
n down
n up
shift down
x down
x up
shift up
x down
x up

@ -12,9 +12,9 @@ alt down
control down
alt up
control up
control down
tab down
tab up
control down
x down
x up
control up

@ -13,6 +13,8 @@ capslock = layer(capslock)
1 = layer(layer1)
2 = oneshot(customshift)
w = oneshot(customshift)
e = oneshotm(shift, macro(on))
p = layerm(shift, macro(on))
3 = layer(layer3)
4 = toggle(test)
5 = layer(symbols)

Loading…
Cancel
Save