Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exit insert mode on key hold #1494

Closed
eugenesvk opened this issue Jan 12, 2022 · 16 comments
Closed

Exit insert mode on key hold #1494

eugenesvk opened this issue Jan 12, 2022 · 16 comments
Labels
A-gui Area: Helix gui improvements C-enhancement Category: Improvements E-hard Call for participation: Experience needed to fix: Hard / a lot

Comments

@eugenesvk
Copy link

Given the high frequency of exiting various modes it makes sense to find the easiest keybind way possible to switch back
Helix has a helpful suggestion:

[keys.insert]
"A-x" = "normal_mode" # Maps Alt-X to enter normal mode
j = { k = "normal_mode" } # Maps `jk` to exit insert mode

However, the first requires a modifier and the second introduces a typing delay (j isn't shown after j is pressed until the next key is pressed)
(likewise, binding Esc to Caps is a pinky move, so not that great either)

I think an even better alternative would be to get rid of a useless letter repetition (if only for a single letter) to have an "on hold" normal_mode command so that you could hold an extremely convenient home row key, e.g., a for 0.5 seconds and that would switch back to normal mode (and, importantly, not execute any normal mode commands bound to a until it's released) instead of typing aaa

(you might also need to delay the first a character before exiting after an "on hold" event to avoid typing delays and also avoid extraneous a)

@eugenesvk eugenesvk added the C-enhancement Category: Improvements label Jan 12, 2022
@NNBnh
Copy link
Contributor

NNBnh commented Jan 12, 2022

Cool but due to the limitation of the terminal, I don't think this is even possible...

@eugenesvk
Copy link
Author

limitation of the terminal, I don't think this is even possible

Sure thing, maybe this could only work in a proper GUI whenever Helix gets one, though why not? Helix is able to see char a being sent to it 5 times in a row in 0.5 seconds, that's not something that would ever happen "organically", or would it?

@pickfire
Copy link
Contributor

Terminal I think it is possible, but it might be incorrect, it depends on the user settings on key repeat, if user key does not repeat then can't detect, but if user key repeat at very slow pace then the timing may be off, this is best implemented on GUI.

Closing this for now since it's GUI related, can reopen when we have GUI later. Or if you think otherwise can still reopen.

@pickfire pickfire added the A-gui Area: Helix gui improvements label Jan 12, 2022
@eugenesvk
Copy link
Author

but it might be incorrect, it depends on the user settings on key repeat, if user key does not repeat then can't detect

ok, let's call it "on repeat" instead of "on hold", then it will be correct — if a user changed his keyboard behavior not to repeat, then he simply won't be able to use the "on repeat" functionality as he has no repeat :)

key repeat at very slow pace then the timing may be off

Unless you read it from a config and let the user set whatever value he likes? Even in the future GUI the timing should be configurable as there is no value that fits everyone due to individual typing preferences

@pickfire
Copy link
Contributor

Unless you read it from a config and let the user set whatever value he likes? Even in the future GUI the timing should be configurable as there is no value that fits everyone due to individual typing preferences

We can't do anything about user setting the speed and even if user provide a value in config we can't set the user typematic speed as well so not really a useful method.

But GUI on the other hand, we get know how long a user hold unlike in the terminal, which the keys will repeat at a constant pace, the other issue is that some of the user set the initial delay to a high amount, so it will take very long for the key to start repeat and we don't know if the user did repeat the key or did not.

@eugenesvk
Copy link
Author

We can't do anything about user setting the speed and even if user provide a value in config we can't set the user typematic speed as well so not really a useful method.

You don't need to set anything — let the user pass the values that work with whatever his system typing configs / typematic speed etc. are.

Similarly

the other issue is that some of the user set the initial delay to a high amount, so it will take very long for the key to start repeat and we don't know if the user did repeat the key or did not.

Then the user will just enter a very long timeout to fit his very long repeat start

You are basically asking a user for 3 values in his Helix config:

  • repeatable key trigger (a)
  • number of repeats (3)
  • total duration/timeout (3 sec)

Then if you get a key passed to Helix by the terminal, you start a timer and if within the next 3 seconds:

  • you get any other key/command, you stop the timer and do nothing
  • you get nothing, the timer expires and you do nothing
  • you get 2 more as (so, 3 total), you trigger the "on repeat" function (delete 3 as, go to normal mode)

If a user has system settings of 1 second delay before repeat and a repeat rate of 1 per second, this will work (he'll send 3 keys per 2 seconds)
If he has a 1 second delay before repeat and a slower repeat rate of 1 per 2 seconds, this will fail (he'll send 2 keys per 3 seconds, so the timer will run out).
Well, if he wants it to work, he'll just have to tweak the config values above to match his delay/repeat rate settings

@pickfire
Copy link
Contributor

One issue I see is we probably don't want user to add 3 config to get this working.

I myself won't find this useful, but if you are interested to work on it (since I doubt others find this useful), feel free to give this a try and submit a pull request, then I can help you look into it.

archseer suggested https://docs.qmk.fm/#/tap_hold, maybe you can look into that.

@pickfire pickfire added the E-hard Call for participation: Experience needed to fix: Hard / a lot label Jan 13, 2022
@archseer
Copy link
Member

I think this type of stuff is best addressed in keyboard firmware where you can have full control over the keys (i.e. https://docs.qmk.fm/#/tap_hold).

The behavior will vary depending on the terminal emulator, and it becomes problematic if I intend to type a and simply tap it once: we don't have enough information to know yet if the key was tapped or held, so the input now has to be delayed until a timeout is reached. This is also why we don't support vim's feature where both g and ge can be mapped to a command, and g will execute after a timeout. There's all sorts of questions out there "why is my command slow" and suggestions to set timeoutlen to 0

@eugenesvk
Copy link
Author

I think this type of stuff is best addressed in keyboard firmware where you can have full control over the keys (i.e. https://docs.qmk.fm/#/tap_hold).

But the firmware doesn't know what mode Helix is in! Firmware might not even know what application is running (also, way too many keyboards don't have it, so it'd a very limited solution)

the input now has to be delayed until a timeout is reached

nope, you just pass the input through and then clean it up

I similar software-based text input functions like showing a symbol selection picker when you hold a button in a text editor and I don't introduce input delay, the first key press always types a letter right away!, but rather add a simple cleaning-an-extra-symbol routine (it's just one symbol since I can block further repeats), it's just fine (granted, Helix can't block further repeats, but it can still easily clean everything up — it knows how many as it has received and can delete all of them after an "on repeat" condition is met).
However, the challenge is the same as with firmware based solutions — it has no knowledge of such intricacies like Helix modality (though software can be made aware of what application is running, not 100% sure, but likely with extra challenges even of a terminal-based app)

That's why Helix is unforunately the only place to add such a bomb of a feature (mode switching is frequent enough to need the easy way to do it), and it would work just fine even in a terminal without a GUI

This is also why we don't support vim's feature where both g and ge can be mapped to a command, and g will execute after a timeout. There's all sorts of questions out there "why is my command slow" and suggestions to set timeoutlen to 0

That strikes me more like just bad defaults, the users wishing to have such compex conflicting keybinds should suffer and tweak the delays to whatever suits them, not everyone!
But again, there is no input delay in the suggested solution and it won't affect anyone by default, a special command chain syntax (or something) would be needed to start timers on a key press, so Helix wouldn't have these issues either

@eugenesvk
Copy link
Author

One issue I see is we probably don't want user to add 3 config to get this working.

Why not? The timing challenges are real, they are user hardware/software/preference specific, so user is the only person able to provide such information

archseer suggested https://docs.qmk.fm/#/tap_hold, maybe you can look into that.

As I mentioned above, firmware lacks the software knowledge to implement this

I myself won't find this useful, but if you are interested to work on it (since I doubt others find this useful), feel free to give this a try and submit a pull request, then I can help you look into it.

Yeah, that might be a challenge, I don't know any Rust and only implemented such a solution in AutoHokey, and your E-Hard label doesn't give be a boost of confidence either :)

Meanwhile, could you please reopen the issue as it's not really GUI-dependent? Also might help someone else see it and appreciate the beauty of this mode-switching-without-leaving-home-row solution enough to help with the implementation :)

@pickfire
Copy link
Contributor

Yeah, that might be a challenge, I don't know any Rust and only implemented such a solution in AutoHokey, and your E-Hard label doesn't give be a boost of confidence either :)

The complexity is not related to the language of the project but due to the limitation of the terminal. Please do try it out and prove me wrong, I put E-Hard because I think it is hard to implement but that does not mean it is hard for everyone, the experience needed is relative to the developer.

Meanwhile, could you please reopen the issue as it's not really GUI-dependent? Also might help someone else see it and appreciate the beauty of this mode-switching-without-leaving-home-row solution enough to help with the implementation :)

Yes, it is not GUI-dependent, but it is not suitable for terminal either due to terminal limitations. Since it is not that relevant, I think it is better to leave it close (open issue does not mean anyone is working on it either), if anyone is interested to take up the issue can post here and I assign the issue then submit the pull request, in the meantime I think this should remain closed.

@eugenesvk
Copy link
Author

The complexity is not related to the language of the project

Of course it is, the AutoHotkey solution is two simple functions

  • send the key right away to avoid any input lag
  • set a key waiting timer, then match the result do what you want depending on a match (e.g. on hold longer than 1 second send to delete the single typed character and j, k to exit to normal mode (or whatever the key sequence is))

And it already works in Helix in a terminal, but then of course it messes up the normal mode since AutoHotkey doesn't know the difference, so holding the key fires it up regardless of the mode, and I'd have to lose the whole key (make it no_op) in all modes but Insert to make it work and avoid accidents
And that's only Windows, so there is that

Would that be of comparable simplicity within this project?

but due to the limitation of the terminal

Which one? The limitations you raised above were about the inability to guess the timings a user might want, which is fine, let the user give the needed timing in a config

open issue does not mean anyone is working on it either

but it does mean it's more visible, so this

if anyone is interested to take up the issue

has a higher chance of happening

@archseer
Copy link
Member

Of course it is, the AutoHotkey solution is two simple functions

Yes, but AutoHotkey is a framework specifically built for these types of keybinds.

Other features such as changing a two-finger tap to some other button event is not supported at all in libinput. This effectively comes down to cost. You see, whenever you write "it's just 5 lines of code to make this an option", what I think is "once the patch is reviewed and applied, I'll spend two days to write test cases and documentation. I'll need to handle any bug reports related to this, and I'm expected to make sure this option works indefinitely. Any addition of another feature may conflict with this option, so I need to make sure the right combination is possible and test cases are written." So your work ends after writing a 5 line patch, my work as maintainer merely starts. And unless it pays off long-term, the effort is not worth it. Some features make that cut, others don't if they are too much of a niche feature.

https://who-t.blogspot.com/2016/04/why-libinput-doesnt-have-lot-of-config.html

@eugenesvk
Copy link
Author

Yes, but AutoHotkey is a framework specifically built for these types of keybinds.

That's precisely why this "The complexity is not related to the language of the project" is false!
A related question: do you think there can be some good mechanism for a terminal editor to "broadcast" its current mode that other processes could read? Because if there were, then maybe it'd be a more productive way — then at least on some platforms you could indeed handle key input in more advanced frameworks
I've seen the window title issue, though that's a bit too crude and hinges on there being a window title, which some prefer not to use for terminals

The point of the second quote eludes me, where was I saying that it'd be "just 5 lines of code" in Helix???
Also, the quote offers no practical guidance, any feature can end up in either bucket of "Some features make that cut, others don't if they are too much of a niche feature.", you'd actually have to do (the impossible) calculation of future maintenance costs and benefits to pick a bucket (besides, there are plenty of examples of Linux projects "handling any bug reports" just fine by ignoring them for years; also, deprecation and breaking configs are a common thing, so it fails even on those theoretical points)

But are you now implying that you wouldn't want to have "on repeat" functionality in Helix at all even if someone else implemented it because it doesn't "pay off long-term"?

@dead10ck
Copy link
Member

@eugenesvk let it go. This is approaching harassment. Unless you are going to be the person doing the work to implement this feature, and then maintaining its functionality for the foreseeable future, you really don't get an opinion on whether it's worth it or not.

@eugenesvk
Copy link
Author

don't get an opinion on whether it's worth it or not

please quote me where I've expressed one

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-gui Area: Helix gui improvements C-enhancement Category: Improvements E-hard Call for participation: Experience needed to fix: Hard / a lot
Projects
None yet
Development

No branches or pull requests

5 participants