Skip to content

Commit d31fba8

Browse files
committed
Add + to macros.
1 parent ad6d734 commit d31fba8

17 files changed

+162
-59
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
# v2.0-beta
1+
# v2.0.1-beta
2+
3+
- Added + syntax to macros to allow for simultaenously held keys.
4+
5+
# v2.0.0-beta
26

37
Major version update.
48

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LOCK_FILE="/var/lock/keyd.lock"
77
LOG_FILE="/var/log/keyd.log"
88
CONFIG_DIR="/etc/keyd"
99

10-
VERSION=2.0.0-beta
10+
VERSION=2.0.1-beta
1111
GIT_HASH=$(shell git describe --no-match --always --abbrev=40 --dirty)
1212

1313
CFLAGS+=-DVERSION=\"$(VERSION)\" \

keyd.1.gz

74 Bytes
Binary file not shown.

man.md

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@
1212

1313
keyd is a system wide key remapping daemon which supports features like
1414
layering, oneshot modifiers, and macros. In its most basic form it can be used
15-
to define a custom key layout that persists accross display server boundaries
15+
to define a custom key layout that persists across display server boundaries
1616
(e.g wayland/X/tty).
1717

1818
The program is intended to run as a systemd service but is capable of running
19-
as a standalone daemon. The default behaviour is to run in the forground and print
19+
as a standalone daemon. The default behaviour is to run in the foreground and print
2020
to stderr, unless **-d** is supplied, in which case in which case log output
2121
will be stored in */var/log/keyd.log*.
2222

2323
**NOTE**
2424

25-
Becuase keyd modifies your primary input device it is possible to render your
26-
machine unusuable with a bad config file. If you find yourself in this
25+
Because keyd modifies your primary input device it is possible to render your
26+
machine unusable with a bad config file. If you find yourself in this
2727
situation the sequence *\<backspace\>+\<backslash\>+\<enter\>* will force keyd
2828
to terminate.
2929

@@ -141,7 +141,7 @@ Layouts also have the additional property of being affected by the active modifi
141141
set. That is, unlike layouts, key sequences mapped within them are not
142142
interpreted literally.
143143

144-
If you wish to use an alternative letter arrangement, this is the appropriate
144+
If you wish to use an alternative letter arrangement this is the appropriate
145145
place to define it.
146146

147147
E.G
@@ -181,9 +181,9 @@ For example:
181181
Will cause the leftalt key to behave as alt in all instances except when
182182
alt+1 is pressed, in which case the key sequence `C-A-f1` will be emitted.
183183

184-
By default each modifier is mapped to an eponymously named layer.
184+
By default each modifier key is mapped to an eponymously named modifier layer.
185185

186-
Thus, the above config can be shortened to:
186+
Thus the above config can be shortened to:
187187

188188
[A]
189189

@@ -239,7 +239,7 @@ distinct from `layout()` which should be used for letter layouts.
239239

240240
: Activates the given layer while held and emits the given key sequence when
241241
tapped. A timeout in milliseconds may optionally be supplied to disambiguate
242-
between a tap and a hold.
242+
a tap and a hold.
243243

244244
If a timeout is present depression of the corresponding key is only interpreted
245245
as a layer activation in the event that it is sustained for more than
@@ -267,6 +267,7 @@ Where `<macro>` has the form `<token1> [<token2>...]` where each token is one of
267267

268268
- a valid key sequence.
269269
- a contiguous group of characters each of which is a valid key sequence.
270+
- a group of key codes delimited by + to be depressed as a unit.
270271
- a timeout of the form `<time>ms` (where `<time>` < 1024).
271272

272273
Examples:
@@ -280,6 +281,15 @@ Examples:
280281
# Identical to the above
281282
macro(Hello space World)
282283

284+
# Produces control + b
285+
macro(control + b)
286+
287+
# Produces the sequence <control down> <b down> <control up> <b up>
288+
macro(control+b)
289+
290+
# Produces the sequence <control down> <control up> <b down> <b up>
291+
macro(control b)
292+
283293
# EXAMPLES
284294

285295
## Example 1

src/config.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ static struct layer *lookup_layer(const char *name, void *_config)
189189

190190
static int parse_header(const char *s,
191191
char name[MAX_LAYER_NAME_LEN],
192-
char type[MAX_LAYER_NAME_LEN])
192+
char type[MAX_LAYER_NAME_LEN])
193193
{
194194
char *d;
195195
size_t typelen, namelen;
@@ -219,7 +219,7 @@ static int parse_header(const char *s,
219219
return 0;
220220
}
221221

222-
static void parse_id_section(struct config *config, struct ini_section *section)
222+
static void parse_id_section(struct config *config, struct ini_section *section)
223223
{
224224
size_t i;
225225

@@ -292,7 +292,7 @@ static int parse_config(const char *config_name, char *str, struct config *confi
292292
assert(strlen(config_name) < MAX_CONFIG_NAME);
293293
strcpy(config->name, config_name);
294294

295-
/*
295+
/*
296296
* First pass, create layers so they are available
297297
* for lookup during descriptor parsing.
298298
*/
@@ -306,7 +306,7 @@ static int parse_config(const char *config_name, char *str, struct config *confi
306306
if (!strcmp(section->name, "ids")) {
307307
parse_id_section(config, section);
308308
continue;
309-
}
309+
}
310310

311311
if (parse_header(section->name, name, type) < 0) {
312312
fprintf(stderr,
@@ -351,7 +351,6 @@ static int parse_config(const char *config_name, char *str, struct config *confi
351351

352352
char *k, *v;
353353
uint16_t code;
354-
uint16_t mod;
355354

356355
struct descriptor desc;
357356

@@ -389,7 +388,7 @@ static void post_process_config(const struct config *config)
389388
size_t i;
390389
uint16_t code;
391390

392-
/*
391+
/*
393392
* Convert all modifier keycodes into their corresponding layer
394393
* counterparts for consistency. This allows us to avoid explicitly
395394
* accounting for modifier layer/modifier keycode overlap within the

src/descriptor.c

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,14 @@ static int parse_key_sequence(const char *s, struct key_sequence *seq)
110110
const struct keycode_table_ent *ent = &keycode_table[code];
111111

112112
if (ent->name) {
113-
if (ent->shifted_name &&
113+
if (ent->shifted_name &&
114114
!strcmp(ent->shifted_name, c)) {
115115

116116
seq->mods |= MOD_SHIFT;
117117
seq->code = code;
118118

119119
return 0;
120-
} else if (!strcmp(ent->name, c) ||
120+
} else if (!strcmp(ent->name, c) ||
121121
(ent->alt_name && !strcmp(ent->alt_name, c))) {
122122

123123
seq->code = code;
@@ -154,6 +154,8 @@ static struct macro *parse_macro_fn(char *s)
154154
assert(sz < MAX_MACRO_SIZE);
155155

156156
ent.type = MACRO_KEYSEQUENCE;
157+
158+
assert(macro->sz < MAX_MACRO_SIZE);
157159
macro->entries[macro->sz++] = ent;
158160
} else if (len > 1 && tok[len-2] == 'm' && tok[len-1] == 's') {
159161
int len = atoi(tok);
@@ -162,23 +164,42 @@ static struct macro *parse_macro_fn(char *s)
162164
ent.data.timeout = len;
163165

164166
assert(macro->sz < MAX_MACRO_SIZE);
165-
166167
macro->entries[macro->sz++] = ent;
167168
} else {
168169
char *c;
169170

170-
for (c = tok; *c; c++) {
171-
char s[2];
171+
if (strchr(tok, '+')) {
172+
char *saveptr;
173+
char *key;
174+
175+
for (key = strtok_r(tok, "+", &saveptr); key; key = strtok_r(NULL, "+", &saveptr)) {
176+
if (parse_key_sequence(key, &ent.data.sequence) < 0)
177+
return NULL;
172178

173-
s[0] = *c;
174-
s[1] = 0;
179+
ent.type = MACRO_HOLD;
175180

176-
if (parse_key_sequence(s, &ent.data.sequence) < 0)
177-
return NULL;
181+
assert(macro->sz < MAX_MACRO_SIZE);
182+
macro->entries[macro->sz++] = ent;
183+
}
178184

179-
ent.type = MACRO_KEYSEQUENCE;
185+
ent.type = MACRO_RELEASE;
180186
assert(macro->sz < MAX_MACRO_SIZE);
181187
macro->entries[macro->sz++] = ent;
188+
} else {
189+
for (c = tok; *c; c++) {
190+
char s[2];
191+
192+
s[0] = *c;
193+
s[1] = 0;
194+
195+
if (parse_key_sequence(s, &ent.data.sequence) < 0)
196+
return NULL;
197+
198+
ent.type = MACRO_KEYSEQUENCE;
199+
200+
assert(macro->sz < MAX_MACRO_SIZE);
201+
macro->entries[macro->sz++] = ent;
202+
}
182203
}
183204
}
184205
}
@@ -188,7 +209,7 @@ static struct macro *parse_macro_fn(char *s)
188209
return macro;
189210
}
190211

191-
/*
212+
/*
192213
* Modifies the input string, consumes a function which which is used for
193214
* resolving layer names as required.
194215
*/

src/descriptor.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ struct key_sequence {
3131
struct macro_entry {
3232
enum {
3333
MACRO_KEYSEQUENCE,
34+
MACRO_HOLD,
35+
MACRO_RELEASE,
3436
MACRO_TIMEOUT
3537
} type;
3638

@@ -40,8 +42,8 @@ struct macro_entry {
4042
} data;
4143
};
4244

43-
/*
44-
* A series of key sequences optionally punctuated by
45+
/*
46+
* A series of key sequences optionally punctuated by
4547
* timeouts
4648
*/
4749
struct macro {

src/ini.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,19 @@ struct ini {
2828

2929
/*
3030
* Reads a file of the form:
31-
*
31+
*
3232
* [section]
33-
*
33+
*
3434
* # Comment
35-
*
35+
*
3636
* entry1
3737
* entry2
38-
*
38+
*
3939
* [section2]
4040
* ...
41-
*
41+
*
4242
* Stripping comments and empty lines along the way.
43-
* Each entry is a non comment, non empty line
43+
* Each entry is a non comment, non empty line
4444
* sripped of leading whitespace. If a default
4545
* section name is supplied then entries not
4646
* listed under an explicit heading will be

src/keyboard.c

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <stdint.h>
2424
#include <unistd.h>
2525
#include <stdio.h>
26+
#include <time.h>
2627
#include "keyboard.h"
2728
#include "keyd.h"
2829
#include "descriptor.h"
@@ -254,24 +255,46 @@ static void kbd_swap_layer(struct keyboard *kbd,
254255
}
255256
}
256257

257-
#include <time.h>
258-
259258
static void kbd_execute_macro(struct keyboard *kbd, struct macro *macro)
260259
{
261260
size_t i;
261+
int hold_start = -1;
262262

263263
for (i = 0; i < macro->sz; i++) {
264-
struct macro_entry *ent = &macro->entries[i];
264+
struct macro_entry *ent = &macro->entries[i];
265+
266+
switch (ent->type) {
267+
case MACRO_HOLD:
268+
if (hold_start == -1) {
269+
hold_start = i;
270+
set_mods(0);
271+
}
265272

266-
if (ent->type == MACRO_KEYSEQUENCE) {
273+
send_key(ent->data.sequence.code, 1);
274+
275+
break;
276+
case MACRO_RELEASE:
277+
if (hold_start != -1) {
278+
size_t j;
279+
280+
for (j = hold_start; j < i; j++) {
281+
struct macro_entry *ent = &macro->entries[j];
282+
send_key(ent->data.sequence.code, 0);
283+
}
284+
}
285+
break;
286+
case MACRO_KEYSEQUENCE:
267287
set_mods(ent->data.sequence.mods);
268288

269289
send_key(ent->data.sequence.code, 1);
270290
send_key(ent->data.sequence.code, 0);
271-
} else
291+
break;
292+
case MACRO_TIMEOUT:
272293
usleep(ent->data.timeout*1E3);
273-
}
294+
break;
295+
}
274296

297+
}
275298
kbd_reify_mods(kbd);
276299
}
277300

@@ -295,7 +318,6 @@ long kbd_process_key_event(struct keyboard *kbd,
295318
uint16_t code,
296319
int pressed)
297320
{
298-
int i;
299321
const struct descriptor *d;
300322
const struct layer *dl;
301323
static int oneshot_latch = 0;
@@ -320,7 +342,7 @@ long kbd_process_key_event(struct keyboard *kbd,
320342
if (pending_overload) {
321343
struct layer *layer = pending_overload->args[0].layer;
322344
const struct key_sequence *sequence = &pending_overload->args[1].sequence;
323-
size_t timeout = pending_overload->args[2].timeout;
345+
long timeout = pending_overload->args[2].timeout;
324346

325347
if ((get_time() - overload_ts) >= timeout) {
326348
kbd_activate_layer(kbd, layer, 0);

0 commit comments

Comments
 (0)