keyd: bug: strange macro behaviour

In order to properly understand the macro parsing algorithm, I started playing with it a bit. Specifically, I think that line 379 of docs/keyd.scdoc, which reads

  • contiguous group of characters, each of which is a valid key code

and describes one of the valid space separated tokens accepted by macro() is a bit misleading, as, for groups consisting of more than one character, “key code” seems to only include their one character descriptions if available (such as ‘a’, ‘A’, ‘.’ but not ‘dot’ for the latter). In my opinion - given that I understood the functionality correctly, “key code” should be changed to “one character key name (all recognized key names can be printed by keyd --list) except ’ ', such as ‘a’, ‘A’, ‘.’ but not ‘dot’”.

While testing, I encountered the following strange behaviour: With keyd config only including

[ids]
<some_valid_id>

[main]
a = macro(semicolonspaceworld)

repeatedly tapping a in a shell, sometimes no text is entered at all after an individual press and sometimes semicolonspaceworld is entered correctly. The frequency with which a inserts nothing seems to be random and independent of the speed with which one presses the key in succession. I had up to eight presses in a row without any effect. The problem seems to be that the string inside macro() contains long forms of valid key codes, as the bug is gone with a = macro(test).

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 19 (12 by maintainers)

Commits related to this issue

Most upvoted comments

@clipcarl

Can you please post the following?

Your config The output of keyd -v OS Desktop Environment A terminal emulator in which the issue can be reproduced (including the version)

(Is there a way to donate to you for this fantastic program I wish I’ve had for my last 25+ years on Linux?)

From distribution:

$ keyd -v
keyd v2.4.1

$ apk info|grep keyd
keyd-2.4.1-r1
keyd-openrc-2.4.1-r1
keyd-doc-2.4.1-r1

Self compiled:

$ keyd/bin/keyd -v
keyd v2.4.1 (99a7869-dirty)

$ file keyd/bin/keyd
keyd/bin/keyd: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped

OS: Alpine Linux Edge (Linux 5.19.0-rc7) on a Dell Inspiron 7620 (12th gen Core i7 1260P, 32GB RAM, very fast SSD) (BTW, my statically compiled binary works great on ChromeOS too!)

DE: KDE 5.25.3.1 / Wayland / libinput

The issue is somewhat random. Occasionally the whole macro is output correctly but usually only part of the macro is output or nothing at all (see below).

The issue occurs in (at least) Konsole 22.04.3, gnome-terminal 3.44.0, xfce4-terminal 1.0.4 and xterm 372. The issue occurs in other GUI applications as well, including (at least) gedit 42.1, Firefox 102.0.1 and Chromium 103.0.5060.114. The issue does not occur in the Linux virtual console. (At least it doesn’t occur with the relatively short macros I’ve tested.) The issue does not occur for macros of 15 or fewer characters. These are always output correctly for me.

  • If a macro is exactly 16 characters long, it is either printed entirely or not at all.
  • The probability of a macro being partially output (as opposed to all or none of it) goes up quickly with the length of the macro over 16 characters.

Config:

[ids]
*

[global]
# Turn capslock LED on if layer with mappings is active. This doesn't work
# well if you actually use capslock so this should only be turned on if you
# map capslock out of existence.
layer_indicator = 1

[main]

# Maps capslock to capslock when pressed and control when held
#capslock = overload(control, capslock)

# If capslock is tapped by itself for less than 240ms then send C-insert (copy)
# else use as modifier to select a category of oneshot macros to trigger
capslock = timeout(overload(macros,C-insert),240,layer(macros))


# If left control key is pressed by itself then send C-c else control key
# acts normally as modifier (layer selector) while held down
#leftcontrol = overload(control, C-c)

# If left control key is tapped by itself for less than 100ms then send C-A-c
# else control key acts normally as modifier (layer selector) while held down
leftcontrol = timeout(overload(control,C-A-c),100,layer(control))


# If left meta key is tapped by itself for less than 240ms then send M-f1
# else meta key acts normally as modifier (layer selector) while held down
leftmeta = timeout(overload(meta,M-f2),240,layer(meta))

# Map insert key to Shift-insert (paste)
insert = S-insert

[macros]
t = oneshot(macroT)
a = oneshot(macroA)
c = oneshot(macroC)

[macroT]
t = macro(Test!)
l = macro(This space is space a space test space of space a space long space macro.)

[macroA]
n = macro(Carl space Thompson)
a = macro(<my street address>)
c = macro(<my city>)
s = macro(<my state>)
z = macro(<my zip code>)
p = macro(<my phone number>)
d = macro(<my domain>)

[macroC]
n = macro(Carl space Thompson)
a = macro(<my full address>)
p = macro(<my phone number>)

My guess is the culprit might be libinput or maybe Wayland.

You will need to be running the latest version.

Yes, my stupid rookie mistake …

After upgraded to 2.4.3, macro_sequence_timeout=10000 works ! (except when I unreasonably quickly continuously emit)

(sorry for my mistake and this late reply …

I’ve tentatively added an option called macro_sequence_timeout to the latest commit.

Thanks for addressing this issue. The problem completely disappeared for me using a value of one.