keyd icon indicating copy to clipboard operation
keyd copied to clipboard

Rolling overload: when the release of the first key happends before the release of the second key

Open tobiasBora opened this issue 1 year ago • 16 comments

I configured

capslock = overload(control, capslock)

in order to have capslock behaving like control unless I just type it, in which case it should behave like capslock.

Unfortunately, when I type stuff like C-a, I naturally do a rolling movement, resulting in the following event:

  1. press capslock
  2. press a
  3. release capslock
  4. release a Unfortunately, it seems like overload will consider this as a kind of tap (but not exactly as capslock is not enabled)… at least it prints a instead of selecting the text.

Is there a way to consider also this sequence as a valid overload? Or am I missing something?

tobiasBora avatar May 22 '24 16:05 tobiasBora

That sequence should indeed emit C-a. Are you sure your config is correct? What is your full config and the output in the logs? (journalctl -u keyd on systemd-based systems)

nsbgn avatar May 22 '24 16:05 nsbgn

Thanks for your quick answer. So I'm using 2.4.3 and indeed if the config is only:

$ cat /etc/keyd/test.conf 
[ids]
*

[main]
capslock = overload(control, capslock)

then it works as intended. But if I do:

[ids]
*

[main]
capslock = overload(control, capslock)
# Without the dt version, typing 'at' really quickly would move the cursor instead of typing 'at'
a = overloadt(arrows, a, 200)

[arrows]
k=up
j=left
l=down
;=right
h=C-right
'=C-left
i=C-up
o=C-down

then the behavior I mentionned starts with the later a. Similarly, if I press really quickly shift + a, then a will not be printed in upper case letter.

$ journalct -u keyd
mai 22 18:08:52 bestos systemd[1]: Stopped Keyd remapping daemon.
mai 22 18:08:52 bestos systemd[1]: keyd.service: Consumed 1.628s CPU time, no IP traffic.
mai 22 18:08:52 bestos systemd[1]: Started Keyd remapping daemon.
mai 22 18:08:52 bestos keyd[1669277]: WARNING: failed to set effective group to "keyd" (make sure the group exists)
mai 22 18:08:52 bestos keyd[1669277]: CONFIG: parsing /etc/keyd/test.conf
mai 22 18:08:52 bestos keyd[1669277]: Starting keyd v2.4.3 ()
mai 22 18:08:52 bestos keyd[1669277]: DEVICE: ignoring 0fac:1ade  (keyd virtual pointer)
mai 22 18:08:52 bestos keyd[1669277]: DEVICE: ignoring 0002:0001  (PS/2 Generic Mouse)
mai 22 18:08:52 bestos keyd[1669277]: DEVICE: ignoring 0488:121f  (DELL08B9:00 0488:121F Touchpad)
mai 22 18:08:52 bestos keyd[1669277]: DEVICE: ignoring 0488:121f  (DELL08B9:00 0488:121F Mouse)
mai 22 18:08:52 bestos keyd[1669277]: DEVICE: ignoring 03f0:6141  (HP 280M HP 280 Silent Wireless Mouse Consumer Control)
mai 22 18:08:52 bestos keyd[1669277]: DEVICE: ignoring 03f0:6141  (HP 280M HP 280 Silent Wireless Mouse)
mai 22 18:08:52 bestos keyd[1669277]: DEVICE: match    0001:0001  /etc/keyd/test.conf        (AT Translated Set 2 keyboard)

tobiasBora avatar May 22 '24 16:05 tobiasBora

Ah, gotcha. The problem is not with the capslock = overload(...) but with the a = overloadt(...). When you tap a, it will emit the macro a, but it either emits it too late (after keyup, so you will have released capslock and thus control already), or it just doesn't stack in general. I don't remember which it is, and will investigate more later, but for now I think you should be able to explicitly override the overlapping case like this:

[main]
capslock = overload(control, capslock)
a = overloadt(arrows, a, 200)

[control]
a = C-a

[arrows]
# ...

nsbgn avatar May 22 '24 17:05 nsbgn

Thanks a lot, I'm not sure to understand what this changes but it seems to fix this bug. I also did:

[shift]
a = S-a

and it seems to fix the bug with shift-A… not sure why, is it because the signal is sent twice?

EDIT Oh, I guess this behaves as a priority, where if control is already typed then it sends C-a instead of the overloadt. So I might want to do it for all modifiers.

tobiasBora avatar May 22 '24 18:05 tobiasBora

Oh, I guess this behaves as a priority, where if control is already typed then it sends C-a instead of the overloadt. So I might want to do it for all modifiers.

Yes, exactly, that's how the solution works.

Ideally, I suppose you shouldn't need it: when overload is activated, whatever modifiers were active at the start of the keypress should be applied to the emitted macro when the overloaded key is released, even if that modifier is no longer active. But I'm not sure that is desirable in all situations. What do others think?

nsbgn avatar May 23 '24 17:05 nsbgn

But I'm not sure that is desirable in all situations. What do others think?

I guess in some cases it might be desirable to sent an event without the modifier active? I guess I lack experienced with keyd use cases to judge here…

But actually, now I experienced two issues: if I press slowly a followed by a key outside the layer arrows, say y, (this occurs sometimes when I'm not typing fast enough normal text) then it will print y but not a, while I would expect this to print ay. Is there a way to force this behavior?

tobiasBora avatar May 27 '24 13:05 tobiasBora

You would have to add bindings like y = macro(a y) inside the arrows layer: unbound keys do fall through other layers by default, but they still also have to effectively go back and add the key that activated the layer in the first place. Of course, this only works for overlaps of length 1, so even apart from the verbosity it's not perfect. I'll reference some previous issues regarding this later.

nsbgn avatar May 27 '24 16:05 nsbgn

Ok thanks! It's indeed not ideal, but I guess better than nothing…

tobiasBora avatar May 27 '24 16:05 tobiasBora

It just occurred to me that making an [empty] layer and binding y = swapm(empty, macro(a y)) would make it work for longer overlaps too. Still not ideal, but one problem down!

nsbgn avatar May 27 '24 18:05 nsbgn

Oh, I guess this behaves as a priority, where if control is already typed then it sends C-a instead of the overloadt. So I might want to do it for all modifiers.

Yes, exactly, that's how the solution works.

Ideally, I suppose you shouldn't need it: when overload is activated, whatever modifiers were active at the start of the keypress should be applied to the emitted macro when the overloaded key is released, even if that modifier is no longer active. But I'm not sure that is desirable in all situations. What do others think?

I think that's how it should work. I had the same problem with overloading "a" a = overloadi(a, overloadt2(<custom_layer>, a, 200), 150)

since i use tmux/screen a lot pressing C-a very quickly resulted in

leftcontrol down
leftcontrl up
a down
a up

however adding priority to [control] layer fixed this for me as well

zeteref avatar Jun 04 '24 13:06 zeteref

So to continue this issue, I realized that the priority solution does not work for the altgr modifier (or I can't make it work). I tried to add a section:

[rightalt]
a = G-a
f = G-f

without success: pressing quickly altgr+f (or actually e when in bépo mode) produces e instead of . Any idea why it works for all of them but this one?

Full code:

[ids]
*

[main]
capslock = layer(control)
f1+f2=capslock
# Without the dt version, typing 'at' really quickly would move the cursor instead of typing 'at'
a = overloadt(arrows, a, 200)
f = overloadt(numbers, f, 200)

# https://github.com/rvaiya/keyd/issues/756
[control]
a = C-a
f = C-f

[shift]
a = S-a
f = S-f

[rightalt]
a = G-a
f = G-f

[meta]
a = M-a
f = M-f

[leftalt]
a = A-a
f = A-f

#capslock = overload(control, capslock)
#a=lettermod(layer(arrows), a, 150, 200)
#a = overloadi(a, overloadt2(layer(arrows), a, 200), 150)
#a = overloadi(a, overloadt2(control, a, 200), 150)

[numbers]
space=kp0
m=kp1
,=kp2
.=kp3
j=kp4
k=kp5
l=kp6
u=kp7
i=kp8
o=kp9
;=oneshot(allLayers)

[allLayers]
f=oneshot(emojiLayer)

[emojiLayer]
j=😉

# Mapping:
#                       C-^
# C-backspace backspace  ^   delete C-delete 
# C-<             <      v     >       C->
# Pageup        Home    C-v  End     Pagedown
# This is not only super easy to remember, mimics the usual arrow shape, but also quite ergonomic. I tried to put before
# all arrows on the same line like in vim, but I ended up using the pinky way too much in
# a repetitive fashion, leading to some pain.
[arrows]
k=down
j=left
l=right
i=up
h=C-left
;=C-right
8=C-up
,=C-down
u=backspace
o=delete
y=C-backspace
p=C-delete
m=home
.=end
n=pageup
/=pagedown

tobiasBora avatar Jun 12 '24 16:06 tobiasBora

Oh, another related question: when I press a + x in a slow rollup motion, I have only x printed. I tried to add to the above configuration:

[arrows]
x=macro(a x)

This works… but it means that I need to repeat this for all letters that I often type in a rollup fashion… which is really tedious, especially when we have many layers. And it also only works when I know the key pressed to access the layer. A solution to this issue would be great!

tobiasBora avatar Jun 12 '24 17:06 tobiasBora

Arg, it seems like I'm missing something… So to continue my epic journey (that is actually very pleasant except for these minor issues), I noticed something different: if I press in a relatively slow motion something like a x, it only prints x instead of a x (note that I don't associate any special action for x)… I guess this is because once we switched to the arrow layout, keyd kind of forgets that we arrived there from a, but it is quite annoying. So then the solution is to write:

[main]
a = overloadt(arrows, a, 200)

[arrows]
x=macro(a x)
… repeat for all letters that are not bound to an action.

but this has multiple issues:

  • first it is really not elegant (who wants to write 15 lines for each layer?)
  • then, the layer needs to know how it is called (here by pressing a) so that we can write x=macro(a x)
  • most importantly, it has some annoying side effects, for instance when rolling aef (which is needed in bépo), it creates aeaf instead.

tobiasBora avatar Jul 04 '24 22:07 tobiasBora

Any idea why it works for all of them but this one?

rightalt is a key name. altgr is the corresponding layer name. So try [altgr] ;)

most importantly, it has some annoying side effects, for instance when rolling aef (which is needed in bépo), it creates aeaf instead.

Perhaps you can do:

[main]
a = overloadt(arrows, a, 200)

[empty]

[arrows]
x=swapm(empty, a x)
… repeat for all letters that are not bound to an action.

This would also deactivate the arrows layer as soon as you press a key that is not bound to an action.

I fear that the other issues are going to be solvable only with more additions to keyd that have been discussed elsewhere --- I agree that the current solution is not ideal. Though until then, it may be good to remember the include mechanism to avoid egregious repetitions.

nsbgn avatar Jul 06 '24 07:07 nsbgn

rightalt is a key name. altgr is the corresponding layer name. So try [altgr] ;)

Oh good point, it works, thanks a lot!

Perhaps you can do x=swapm(empty, a x)

Hum thanks… So it gets better, but still not 100% perfect (but it's starting to be fairly usable): doing x=swapm(empty, macro(a x)) (I guess your code was a typo, because if I use it the a gets removed when pressing a x slowly) works for rolling keys which are not themself lead keys. But if the 3rd key is a lead key (with overloadt as above), the last key is never printed. So I tried to change the empty layer into:

[empty]
a=a
b=b
c=c
d=d
e=e
f=f
g=g
h=h
i=i
j=j
k=k
l=l
m=m
n=n
o=o
p=p
q=q
r=r
s=s
t=t
u=u
v=v
w=w
x=x
y=y
z=z

Now, the third key is printed if I press the three keys and then release them like press a; press e; press f; release a; release e; release f, it prints aef as expected. But if I do press a; press e; release a; press f; release e; release f, it prints ae instead of aef. Don't know if it is possible to solve this in a clean way…

Though until then, it may be good to remember the include mechanism

Oh good to know. But is it really helping here? Cause the file is dependent on the key that was called before, so x=swapm(empty, a x) would be something else in another layer depending on how it is called.

tobiasBora avatar Jul 06 '24 21:07 tobiasBora

Could this be the same as #731 ?

AndydeCleyre avatar Apr 30 '25 17:04 AndydeCleyre