rbreaves / kinto

Mac-style shortcut keys for Linux & Windows.
http://kinto.sh
GNU General Public License v2.0
4.51k stars 216 forks source link

Multi-modifiers behavior - Shrinking selection to behave the same as on macos #512

Open one-cyber-camel opened 3 years ago

one-cyber-camel commented 3 years ago

First of all, thanks for this great tool, it's making my life on linux so much easier.

I have a question, don't know if it is a bug. I am coming from macos, using kinto on linux.

On macos it behaves like this:

  1. set cursor at start line
  2. CMD + SHIFT + RIGHT -> The whole line gets selected
  3. release CMD, still holding SHIFT + LEFT -> selection shrinks per character
  4. still holding SHIFT, add OPTION + LEFT -> selection shrinks per word

Same goes for the other way around, starting at end of line, selecting whole line then shrinking to the right.

The behaviour on linux is:

  1. set cursor at start line
  2. CMD + SHIFT + RIGHT -> The whole line gets selected
  3. release CMD, still holding SHIFT + LEFT -> selection disappears (shrinks back to start of line)
  4. still holding SHIFT, add OPTION + LEFT -> selection disappears (shrinks back to start of line)

The only way it will work is if I first release SHIFT and then use SHIFT again to do the shrinking.

Doesn't sound like an issue, but years of muscle memory makes text editing quite a chore.

Any idea how to fix this? It's mainly an issue for me in VSCode

rbreaves commented 3 years ago

Hmmm.. that is a very interesting scenario I had not tested for actually.. I literally never think about switching between per character and per word but does make sense.

I think this issue likely exists on the xkeysnail side of things and would need to be addressed on my fork of it and I have no ETA right now on when I will be able to address this specific behavior right now. It does need to be addressed at some point however. My fork exists in general though because without the modifications I had made the behavior of holding modifiers doesn't work at all as it would emit them briefly instead. What you are saying you really need is true 1 to 1 held modifiers versus what is happening right now which is the releasing of a single modifier ends up releasing all modifiers.

I am wondering if I had fixed that already at one time but may have had to roll it back due to an unexpected behavior but I don't recall the details. Regardless it needs to be implemented better to cover this. I can confirm that this behavior is working under Windows with Kinto's Autohotkey implementation just fine ๐Ÿ˜….

For now though the work around is probably to release all modifiers and then hold down the shift key again to continue on with a per letter highlighting. If you are confident w/ python however then please take a look at my fork of xkeysnail and I will accept any PR that comes my way that resolves the issue. Upstreaming it to xkeysnail may be difficult as they pulled my hold keys PR awhile back due to conflicts with other features - it needs to be implemented as its own function or with a parameter.

Some xkeysnail users only want or desire the emitting hotkey remapping behavior and explicitly do not want held modifiers to be a thing at all.

mkoorn commented 3 years ago

Hi, thanks for your answer, I fully understand regarding ETA, only so much time in a day ๐Ÿ˜ƒ

I never knew I was doing these key combinations so often until I started to work on linux and it didnโ€™t work. Unfortunately my python skills are abysmal.

Indeed there is a workaround so Iโ€™ll work on my muscle memory. ๐Ÿ˜…

Thanks again and keep up the good work. As I stated before, this is making my transition to linux so much easier. ๐Ÿ‘๐Ÿป

joshgoebel commented 2 years ago

On macos it behaves like this:

This is exactly the behavior I get on my fork of xkeysnail mainline... so I'd assume this also works in xkeysnail mainline and that this issue is a result of kinto.sh's patch to allow Cmd-tab to function properly... that it's holding/releasing keys in expected ways that breaks this behavior.

ehaynes99 commented 2 years ago

I spent a lot of time trying to crack this one, but I don't really see a good way to handle it without reorganizing how xkeysnail is designed. If you replace rbreaves/xkeysnail with the current mooz/xkeysnail, all of these kinds of issues go away. Here is the culprit: https://github.com/rbreaves/xkeysnail/blob/51c369084e0045a8410d227bab52411bf84fb65b/xkeysnail/transform.py#L428-L431

if str(key) != "Key.LEFT_SHIFT" and str(key) != "Key.RIGHT_SHIFT":
    for output_key in output_mods:
        update_pressed_modifier_keys(output_key, action)
        send_key_action(output_key, action)

By default in xkeysnail, when you fire a key combo, it:

  1. lifts up any modifier keys that are NOT in the combo mapping
  2. presses any modifier keys that in the combo mapping that were not already pressed
  3. press the non-modifier key
  4. release the non-modifier key
  5. release any modifiers pressed for the combo
  6. press all of the modifier keys that were removed

However, this causes a problem, most obviously with alt+tab and alt+tilde. This is what @rbreaves was attempting to fix. The window switcher requires you to hold down the modifier keys and repeatedly press tab to cycle through others in order of most recent focus. If you release the modifier key, it "resets", and now the window you just left is the most recent. This means that kinto remapping to cmd+tab as a combo resets every time, and you can only cycle back and forth between the 2 most recent, never the 3rd+ options. This is what the above was designed to fix.


The fix that I attempted to make was to take the 6 steps above, but defer the last two actions until one of the modifiers currently pressed was release. This, wouldn't work, however, because you could make a mapping that DOES NOT have modifier keys that maps to a Combo that DOES have modifier keys. In such a case, there would never be a modifier key released (I ended up in a state where I had to hard reset my machine a couple of times due modifiers being permanently held).


To fix it, xkeysnail would need a better concept of the actual keys pressed. Effectively, it has a 3 stage process:

output.py has some independent tracking of actual and mapped keys, but it's not enough. There is an internal distinction between "regular" key mappings and "combo" mappings, and they are handled differently. transform.py does the translation, but when it sends a combo to output.py, the Combo class used to represent this contains only the mapped output, so there's no effective means of backtracking. In fact, at some point, someone in the upstream xkeysnail actually made transform.py access the internals of output.py to check if a key was currently down. This is totally backwards, and asking for trouble IMO.

What this really needs is a continually tracked pair of physical input to mapped output. Each time a physical key is pressed or released, a new mapping would be created, and the logic in steps 1-3 above to press/release keys would take place. It would be a pretty major overhaul, though, and I couldn't devote the time to it.


Tangent, but another side effect of this behavior is that it's impossible to hold down a combo, so you can't rely on key repeat. E.g. normally, if you hold ctrl+v, it will keep pasting the same thing over and over, but since xkeysnail releases the key, it won't. The stack behavior would fix that as well.

rbreaves commented 2 years ago

@ehaynes99 That is a very long reply and I already have a headache atm.. so apologies on not reading it all the way through.. regardless of what "the issue" with xkeysnail or kinto may or may not be the real issue is Electron and how it handles the Alt key in general. The fix is to simply define the keybindings in this file here keybindings.json & import the Sublime Text keymaps imo, although maybe the sublime text keymaps aren't actually needed & I just always add them any ways.

keybindings.json https://gist.github.com/rbreaves/6a3ed3d5b56ef07cb0332a64dac0a7b2

If you do import Sublime keymaps via the vscode extension here is the preferences files Preferences.sublime-settings - Windows https://gist.github.com/rbreaves/83347564c66c2817e4e4e15f09e20c58 Preferences.sublime-settings - Linux https://gist.github.com/rbreaves/b530e9d231035c6d33d7477e9417e1d7

And you probably do want the one associated with your OS as the remapper is designed for that one, not the macOS settings file.

Also update ~/.config/kinto/kinto.py in 3 areas.


...
mscodes = ["code","vscodium"]
codeStr = "|".join(str('^'+x+'$') for x in mscodes)

sublimes   = ["Sublime_text","subl","code","vscodium"]
sublimeStr = "|".join(str('^'+x+'$') for x in sublimes)
...

...
# Keybindings for VS Code
define_keymap(re.compile("342342ssfsadfdsafsaddfa", re.IGNORECASE),{
...

...
# Keybindings for Sublime Text
define_keymap(re.compile(sublimeStr, re.IGNORECASE),{
...

That last one is actually not a change if you are on the latest Kinto.

@ehaynes99 @joshgoebel @mkoorn @one-cyber-camel

Ultimately there is no discernible issue with having this type of shrinking selection behavior imo once the hotkeys are properly defined in VSCode - but I consider this to be a limitation and issue with VSCode on Linux specifically. Regardless this method works so well I tend to do something very similar on Windows even though Electron under WIndows does not exhibit the same issue from what I recall.

Happy hunting and fixing everyone, I am close this issue as I believe this to be a duplicate any ways & some of this info I posted above already explained but perhaps not in this level of detail, so I will likely be linking back to this post a bit going forward.

rbreaves commented 2 years ago

Re-opening.. it must be late, realizing this was explaining the nuance of dual modifiers being held type of think and yea @ehaynes99 is right, fundamental differences in how xkeysnail or my fork works will need to happen.

ehaynes99 commented 2 years ago

No worries. Didn't mean for you to have to reply immediately, just tried to gather it all together, as it's a bit of a game of whack-a-mole. I know you spent a lot of effort trying to fix it in the upstream. I read through those threads a while back and forget why mooz reverted them, but I tried working on it 3 different times hoping I could contribute a fix and couldn't come up with something that didn't have at least some other potential problem.

joshgoebel commented 2 years ago

@ehaynes99 You should look at my new fork, it's largely rewritten, solves many of the original and Kinto xkeysnail problems. It's getting close to solid. https://github.com/joshgoebel/keyszer It handles Cmb-tab in an entirely different fashion and only engages that for the specific key combos that need it (that are explicitly tagged to work in that fashion). It solves misfires by "suspending" input until it knows a users intention... leaving one super annoying issue https://github.com/joshgoebel/keyszer/issues/9 because of Cmd-click...

That's the big puzzle piece that I haven't cracked yet, and I worry there may not be a great solution (for everyone).