Open lobre opened 7 months ago
Thanks for the clear exposition, it makes discussing the issue much easier :).
An intrinsic part of adding time based disambiguation to a key involves severing the relationship between the physical keystroke and the actual input event.
The crux of your issue seems to be that there is a discrepancy between the physical sequence:
<control down> <x down> <control up> <x up>
and the produced logical sequence:
<control down> <control up> <x down> <x up>
While your particular use case would benefit from the modifier present during the physical event propagating through to the logical sequence, there are probably actions and use cases for which it would be undesirable.
timeout()
is a very simple action, it simply executes the supplied action on either side of the timeout once the action can be disambiguated, so it is arguably doing its job.
One way to solve your particular issue would be to explicitly overload x
in the control layer:
E.g
[main]
x = timeout(x, 1000, C-M-x)
[control]
x = timeout(C-x, 1000, C-M-x)
granted this is a bit ugly and potentially cumbersome given a large enough set of bindings. Consider however that it is at least possible to achieve (and relatively easy to comprehend). Making this default behaviour would make the reverse impossible.
This is also consistent with keyd's general view that bindings are resolved by physical events, but their consequences can be downstream of those physical events.
The goal of keyd is to provide as simple (but no simpler) a set of primitives that can be used to implement most useful behaviour, but some problems are inherently tricky and require the user to grok the problem domain.
Having said that, I am more inclined to view this as a possible bug in the overloadt*
set of actions, since those are more intimately tied to the goal of letter overloading, and are thus more constrained (one of the arguments must always be a layer). However a similar solution as above can also be deployed in those cases and I haven't considered all of the implications of propagating modifier state.
P.S
Sorry for taking so long to address this. I am slowly working my way through the large backlog of issues.
[main] x = timeout(x, 1000, C-M-x)
Is there a mistake here and did you mean M-x
solely?
Otherwise, I like the way you framed the problem. It is a different and broader view than mine, and I also like that you guide your design with simplicity, avoiding any behaviour that would sound a bit "magic".
I still struggle to have a complete understanding of the impacts of answering the problem the way I imagine. I guess it makes more sense for you as you have worked in this domain space for longer. I do have the feeling that changing the behaviour to what I propose could potentially break a lot of other workflows, but those are unknown to me. I only have a clear view of my own workflow as I have thought about it for quite some time now. So I can only trust you.
Each time I post an issue about what I don't manage to do, there is always an existing "solution" that is more or less clean. I did not see this one coming as I thought it was something tricky. But I do like the proposed solution, except for the high verbosity it will require.
If we had a way to abstract the configuration somehow and create templates/functions or whatever we want to call them, this would help a lot for all of those.
Here, I posted my example for control
, but in my current configuration, I do have two other cases where this problem happens. One for altgr
, and one for my number
layout. I cannot imagine the size of my configuration if I decide to override each of the 30 keys in each layer to implement that correctly (without talking about the readability). Because as you said, each person will have to leverage basic building blocks and have a precise knowledge of the problem space to implement "correct" solutions. More verbosity makes understanding what happens more difficult.
Do you already have leads about this verbosity problem? (I saw it coming back in different issues).
Thank you for taking the time to answer.
I think I also got bitten by this same bug.
If I do:
g = overloadt(arrows, g, 1000)
to create a mod key (same bug with the other variations of overload), and press:
press altgr, press g, release g, release altgr
I get what I would expect, i.e. altgr-g (i.e. '
in bépo).
But if I do it in a rolling way, i.e.:
press altgr, press g, release altgr, release g
then it actually sends g
instead (i.e. ,
in bépo).
I would love to see this fixed, as it makes me basically unable to use this key as a lead key since I'm really used to type it in a rolling way.
Thanks!
Sorry again for that title that is really hard to grasp at first sight.
I realize that each time I come across a weird behavior in keyd, I struggle to frame it correctly and give a name that would allow anybody to quickly understand the problem at a glance. I guess it is because details matter a lot in such software. Anyway, let me explain my problem.
First and as always, here is an example:
What I want is rather simple in that example. I want
x
to givex
is held less than 1 second, and if held more, I want themeta
version ofx
.Now let’s try to combine that with
ctrl
. If I take the example ofz
, which does not have any specific behavior attached. When I holdctrl
and then pressz
,ctrl-z
is directly sent at press (and not at release).Now, let’s try to do it with
x
instead. As there is atimeout
, keyd cannot know at press if it should sendctrl-x
orctrl-meta-x
. So it has to act differently this time and wait for the release event, to be able to compute the amount of time spent holding the key.Let me show in this asci art what it means (it should be read from left to right).
Here,
ctrl
gets sent, thenx
gets pressed but nothing happens yet. Within 250 ms,x
gets released and here, keyd understands that the user wants to sendctrl-x
. Finally,ctrl
gets released.All that context to be able to demonstrate the behavior that I think is weird. Let’s alter slightly the previous example to say that
ctrl
is released beforex
has been released.Here is again the asci art.
Here you can quickly see that
ctrl
gets released beforex
. As we are still under 1 second, we still don’t want themeta
version ofx
. However, as a result, onlyx
is sent, instead ofctrl-x
. Whether this is normal is debatable.I personally think that if the key cannot be determined at press, the modifier version of the key should still apply even if the modifier gets released in the meantime, before the actual key. Mentally, the user thinks that the modifier is applied when pressing the second key. So if he releases the modifier before in a fast motion, it is obvious to me that he does not want to type the key itself.
What do you think about this? This might also apply to other key overloading mechanisms besides
timeout
.