keyd icon indicating copy to clipboard operation
keyd copied to clipboard

Feature request: oneshot swap

Open lobre opened this issue 1 year ago • 9 comments

After having read the manual page and parts of the code, I don’t find any way of doing this. Please let me know if I missed something.

I do have a base layer and I have the [altgr] layer that I can activate on hold with my right thumb.

From here (and while maintaining my right thumb held), I would like to swap just for one key (oneshot) to another layer which contains numbers, and that I activate by tapping the left Alt with my left thumb.

I cannot use a regular oneshot, as it will layer it on top of my [altgr] layer. And then the effect on the [altgr] will be applied to my number layer. So I want to swap/replace the current layer (which is [altgr]) just for one key.

Is that doable?

lobre avatar Feb 24 '24 18:02 lobre

Funny, I was just considering a oneshot+swap action this week too, because I wanted the swap to apply for at least one key and until the activating key is released (but eventually think I will settle on plain swap since I realised that I tend to keep holding the activating key anyway).

Your request is slightly different, though: if I understand correctly, you just want a oneshot --- the fact that you're also holding the activating key (rightalt) is only relevant insofar as it has the undesirable side-effect of keeping both layers (and associated modifiers) active. If you would really also swap the layers, that would deactive altgr but also have the effect that your number layer would stay active until you release rightalt, which is explicitly not what you want, right?

If the above is correct, consider using oneshot but defining your number layer as a composite layer:

[altgr]
leftalt = oneshot(your_layer)

[your_layer]
[your_layer+altgr]
a = 1
s = 2
# etcetera

This way, you explicitly override the situation where both layers are active. Does that work?

For posterity, here's a related issue for general combined actions: https://github.com/rvaiya/keyd/issues/590

nsbgn avatar Feb 24 '24 20:02 nsbgn

that would deactivate altgr but also have the effect that your number layer would stay active until you release rightalt, which is explicitly not what you want, right?

If you mean this:

[altgr]
leftalt = swap(mynumberlayer)

[mynumberlayer]
a = 1
s = 2
...

Yes, effectively, it would stay active until I release my right thumb, but this is actually what I want and what I was using before trying a oneshot.

To try to rephrase in simpler words, here is what I have today. I have a layer on top of [base] that I activate on AltGr hold. This layer is either my regular [altgr] layer or a number layer and this switch between the two is triggered by a tap on the left alt.

This way, I just need a single layer key on the base layer to fan out into two different layers without having to hold two layer keys, if that makes sense. Here is a picture to help understand.

shapes at 24-02-26 09 32 57

And by the way, my [altgr] layer contains programming symbols.

Now I created this issue to try to alter/improve this workflow. In programming, it is often that you need a single number in between symbols (e.g. ([0]), < 1), += 2;, ...).

So when the altgr key is held, and after having typed a few symbols, I want to single tap alt (as before), but instead of swapping/toggling, I want the number layer swapped only for one number, and then it should go back to the [altgr] layer automatically (hence a "oneshot swap"). Here is the above picture modified to represent this.

shapes at 24-02-26 09 49 08

I have tested your composite solution. And it effectively works, thank you. However, it feels a bit like a hack and is more cumbersome to configure, as this [number] layer needs to be defined twice, once for the regular layer, and also for this composite layer.

Another solution could be to have a way of removing the effect of a modifier for a whole layer. Something such as [number:-G] for instance. But not sure how it would work with the current codebase.

I think that it would be nicer to have a proper "oneshot swap" though.

lobre avatar Feb 26 '24 09:02 lobre

I also just noticed that the composite solution prevents me from doing also the opposite behavior.

On top of having this system where I can type a single number between symbols, I also have the usecase of wanting to type a single symbol between numbers. One simple example is arithmetic operations such as 21+23.

On the base layer, the leftalt is bound to my number layer on hold. And on this layer, I want to be able to single tap the rightalt to swap for a oneshot symbol such as +. Here is the picture.

shapes at 24-02-26 11 04 56

So the behavior is the same but reversed/mirrored.

The thing is, now that I use a composite, this same composite [num+altgr] will be activated either if I am:

  1. holding rightalt and single tapping leftalt (to enter symbols followed by a oneshot number),
  2. or holding leftalt and single tapping rightalt (to enter numbers followed by a oneshot symbol).

If my composite is defined as:

[num+altgr]
a = 1
s = 2
...

I will only be able to do 1. and not 2. Or said differently, only one of the two will have two be chosen.

lobre avatar Feb 26 '24 10:02 lobre

Yes, I would also use this.

I will try to be brief and split this up in 2 posts so as not to make this thread too overwhelming; this first one is just for @lobre.

Yes, effectively, it would stay active until I release my right thumb, but this is actually what I want and what I was using before trying a oneshot.

I want the number layer swapped only for one number, and then it should go back to the [altgr] layer automatically

These two statements seem mutually exclusive unless you're talking about two different behaviours, which I'm going to assume is the case :P

I will only be able to do 1. and not 2. Or said differently, only one of the two will have two be chosen.

You could just make multiple differently-named layers that are the same except for this behaviour --- ie [altgr1+num1], etcetera. I realize that is very hacky and cumbersome, but it's worth a mention for the time being.

nsbgn avatar Mar 28 '24 13:03 nsbgn

To summarize and to make sure we agree on what we want, do you agree with the following behaviour:

[main]
leftalt = layer(layerA)

[layerA]
a = oneshotswap(layerB)

[layerB]
  • While holding leftalt, then as soon as we keydown a: deactivate layerA and activate layerB for at least the first subsequent keydown, and otherwise for as long as a continues to be held. Afterwards, swap back layerB for layerA.
  • If leftalt is released at any point, immediately deactivate layerA or its swapped layerB (even if the oneshot is still waiting for a keypress).

My own use case

I would like to oneshot modifier layers from another layer:

[main]
leftalt = overload(fn, esc)

[fn]
c = oneshotswap(control)

A simple c = swap(control) works for the most part, but I have fn active a lot of the time and when I enter a modifier layer through it, I have to consciously remind myself to let go and reactivate leftalt to get back to fn.

Issues with current solutions

Beyond the exponential duplication, my issue with the composite approach is that it cannot be used when switching layouts (unless layouts become accepted as constituents in composite layers or #651/#705 is implemented).

Another advantage over oneshot for modifier layers, in this context, is that you can simulate a bare press of the modifier by simply letting go of the activating key.

All that said, if it ever becomes possible to combine arbitrary actions, we probably don't need a oneshotswap. So, if that is likely to work out (cf. https://github.com/rvaiya/keyd/issues/590#issuecomment-1858927685), perhaps we should hold off on feature-requesting all too eagerly :)

nsbgn avatar Mar 28 '24 13:03 nsbgn

These two statements seem mutually exclusive unless you're talking about two different behaviours, which I'm going to assume is the case :P

You are right. I wanted to say that I first tried with a regular swap, and it was working, and then decided to try to replace it with a oneshot swap. But not using both statements at the same time.

To summarize and to make sure we agree on what we want, do you agree with the following behaviour

I agree, this behavior is exactly the one in which I am also interested.

All that said, if it ever becomes possible to combine arbitrary actions, we probably don't need a oneshotswap.

I am not sure to see how the combination of actions could answer the current issue. Can you please explain with a pseudo example what it would mean and how you think it could work?

lobre avatar Apr 04 '24 11:04 lobre

I am not sure to see how the combination of actions could answer the current issue. Can you please explain with a pseudo example what it would mean and how you think it could work?

The solution that I mentioned previously (using composite layers) can then be used without the duplicate configuration, since we could just activate multiple layers at once to trigger a specific composite layer. It is still a bit non-obvious and (unless #717 or #705 is added) doesn't allow for modifiers to be associated with the layer, so dedicated support is probably still preferable.

nsbgn avatar May 02 '24 08:05 nsbgn

Understood, thanks.

Definitely, this feature (combination of actions, or whatever we want to call it) is desired in every use-case that I come across it seems ^^.

But I agree, for this one, maybe having a oneshotswap() could be worth it.

lobre avatar May 03 '24 20:05 lobre

Update: In https://github.com/rvaiya/keyd/issues/673#issuecomment-2025149627, I said that the swapped layer should immediately be deactived upon release of the key that activated the original layer. I still think that makes sense when the original layer was activated by layer or overload, but if it was itself also activated via oneshot, it would make more sense to keep the swapped layer active.

Modifying the original example to illustrate:

[main]
leftalt = oneshot(layerA)

[layerA]
a = oneshotswap(layerB)

[layerB]

After pressing leftalt, as soon as we keydown a: deactivate layerA and activate layerB for at least the first subsequent keydown, and otherwise for as long as a continues to be held. Afterwards, if leftalt is still held, reactivate layerA for as long as that remains the case.

These subtly different behaviours could either be implemented with two variants of oneshotswap, or by modifying the behaviour based on the activating key. I intuitively prefer the latter, but I worry that it's a bit complicated to understand (and that I've missed other use cases). What do you think?

nsbgn avatar May 20 '24 14:05 nsbgn