Skip to content

Commit 8337cf9

Browse files
committed
add xdotool type --aftermodifiers option
This waits for the user to release any modifier keys that are currently held before starting to type. This allows avoiding race conditions when xdotool is called from a keyboard shortcut, and starts to type characters with the modifier still held. Currently the usual way to do so is with --clearmodifiers, but this introduces its own race conditions (see e.g. issue #43) if the physical key is released while the typing is in progress.
1 parent df94eb6 commit 8337cf9

File tree

2 files changed

+38
-13
lines changed

2 files changed

+38
-13
lines changed

cmd_type.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,17 @@ int cmd_type(context_t *context) {
2626

2727
/* Options */
2828
int clear_modifiers = 0;
29+
int after_modifiers = 0;
2930
useconds_t delay = 12000; /* 12ms between keystrokes default */
3031

3132
enum {
32-
opt_unused, opt_clearmodifiers, opt_delay, opt_help, opt_window, opt_args,
33-
opt_terminator, opt_file
33+
opt_unused, opt_clearmodifiers, opt_aftermodifiers, opt_delay, opt_help,
34+
opt_window, opt_args, opt_terminator, opt_file
3435
};
3536

3637
struct option longopts[] = {
3738
{ "clearmodifiers", no_argument, NULL, opt_clearmodifiers },
39+
{ "aftermodifiers", no_argument, NULL, opt_aftermodifiers },
3840
{ "delay", required_argument, NULL, opt_delay },
3941
{ "help", no_argument, NULL, opt_help },
4042
{ "window", required_argument, NULL, opt_window },
@@ -50,6 +52,7 @@ int cmd_type(context_t *context) {
5052
"--window <windowid> - specify a window to send keys to\n"
5153
"--delay <milliseconds> - delay between keystrokes\n"
5254
"--clearmodifiers - reset active modifiers (alt, etc) while typing\n"
55+
"--aftermodifiers - wait for modifiers to be released before typing\n"
5356
"--args N - how many arguments to expect in the exec command. This is\n"
5457
" useful for ending an exec and continuing with more xdotool\n"
5558
" commands\n"
@@ -76,6 +79,9 @@ int cmd_type(context_t *context) {
7679
case opt_clearmodifiers:
7780
clear_modifiers = 1;
7881
break;
82+
case opt_aftermodifiers:
83+
after_modifiers = 1;
84+
break;
7985
case opt_help:
8086
printf(usage, cmd);
8187
consume_args(context, context->argc);
@@ -180,6 +186,15 @@ int cmd_type(context_t *context) {
180186
}
181187

182188
window_each(context, window_arg, {
189+
if (after_modifiers) {
190+
for (;;) {
191+
xdo_get_active_modifiers(context->xdo, NULL, &active_mods_n);
192+
if (active_mods_n == 0) {
193+
break;
194+
}
195+
usleep(30000);
196+
}
197+
}
183198
if (clear_modifiers) {
184199
xdo_get_active_modifiers(context->xdo, &active_mods, &active_mods_n);
185200
xdo_clear_active_modifiers(context->xdo, window, active_mods, active_mods_n);

xdo.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1631,15 +1631,20 @@ void _xdo_send_modifier(const xdo_t *xdo, int modmask, int is_press) {
16311631
int xdo_get_active_modifiers(const xdo_t *xdo, charcodemap_t **keys,
16321632
int *nkeys) {
16331633
/* For each keyboard device, if an active key is a modifier,
1634-
* then add the keycode to the keycode list */
1634+
* then add the keycode to the keycode list.
1635+
*
1636+
* If keys is null, only count the number of modifiers pressed,
1637+
* without recording them. */
16351638

16361639
char keymap[32]; /* keycode map: 256 bits */
16371640
int keys_size = 10;
16381641
int keycode = 0;
16391642
int mod_index, mod_key;
16401643
XModifierKeymap *modifiers = XGetModifierMapping(xdo->xdpy);
16411644
*nkeys = 0;
1642-
*keys = malloc(keys_size * sizeof(charcodemap_t));
1645+
if (keys) {
1646+
*keys = malloc(keys_size * sizeof(charcodemap_t));
1647+
}
16431648

16441649
XQueryKeymap(xdo->xdpy, keymap);
16451650

@@ -1654,15 +1659,20 @@ int xdo_get_active_modifiers(const xdo_t *xdo, charcodemap_t **keys,
16541659
* 'xdotool key --clearmodifiers ...' sometimes failed trying
16551660
* to clear modifiers that didn't exist since charcodemap_t's modmask was
16561661
* uninitialized */
1657-
memset(*keys + *nkeys, 0, sizeof(charcodemap_t));
1658-
1659-
(*keys)[*nkeys].code = keycode;
1660-
(*nkeys)++;
1661-
1662-
if (*nkeys == keys_size) {
1663-
keys_size *= 2;
1664-
*keys = realloc(keys, keys_size * sizeof(charcodemap_t));
1665-
}
1662+
if (keys) {
1663+
memset(*keys + *nkeys, 0, sizeof(charcodemap_t));
1664+
1665+
(*keys)[*nkeys].code = keycode;
1666+
(*nkeys)++;
1667+
1668+
if (*nkeys == keys_size) {
1669+
keys_size *= 2;
1670+
*keys = realloc(keys, keys_size * sizeof(charcodemap_t));
1671+
}
1672+
}
1673+
else {
1674+
(*nkeys)++;
1675+
}
16661676
}
16671677
}
16681678
}

0 commit comments

Comments
 (0)