helix-editor / helix

A post-modern modal text editor.
https://helix-editor.com
Mozilla Public License 2.0
33.77k stars 2.51k forks source link

bug: normal mode hardcoded with english layout #133

Closed whoizit closed 7 months ago

whoizit commented 3 years ago

this bug is thousands of years old, it is present in vi / vim / nvim / any vim-like editors I have tried and in the post-modern editor it is also present. This is super sad.

It must use key-codes, not key-chars or key-chars must be translated to key-codes on the fly.

Affected any national non-English and non-CJK layouts

idoric commented 1 year ago

I have read this discussion carefully, and I would like to add my personal testimony. Like @gagbo I'm using the bépo layout (some kind of french dvorak), and I want to give it a try to helix. After thinking about it, I came to the conclusion that the easiest way for me was to use the qwerty us layout in normal mode, and the bépo layout in insert mode¹. Since there's no equivalent of Vim's langmap, I wanted to remap all the commands (from documentation keymap page) to simulate a qwerty us keyboard under the [keys.normal] section of config.toml. Unfortunately I soon found that this wasn't possible to do it in a consistent way, starting with the basic command "repeat last insert", which cannot be remapped. But there's worse: at the place of the y on the qwerty us there is a dead key (which doesn't generate a character by itself) on the bépo.

(Moreover, in the case of the dot to repeat the last insertion, it is also very annoying in azerty, the most widespread keyboard in France, because the dot is not directly accessible, you have to press shift in same time.)

¹ For the more curious, I let you see where the h, j, k and l keys are on a bépo keyboard: https://bepo.fr/ (the layout is displayed at the top of the home page). And that's far from the only difficulty, you can also search for [ and ] as a second example.

soloturn commented 1 year ago

to be honest i would prefer for the command mode to use the scancode or keyid instead of remappings. swiss german or swiss french keyboards have a dead key on the english ] position.

something in the lines of this tiny library. https://crates.io/crates/keyboard_query

HealsCodes commented 1 year ago

to be honest i would prefer for the command mode to use the scancode or keyid instead of remappings. swiss german or swiss french keyboards have a dead key on the english ] position.

something in the lines of this tiny library. https://crates.io/crates/keyboard_query

Scancodes don't work well at all for anything that is not a level-zero (direct input) key as you don't have an easy way to infere what scancode + modifier (shift, alt, ctrl, super, meta, option) maps to because that's something the OS keyboard layout is responsible for. And this doesn't even account for modifier combinations or the famous ISO-Level3 shift (alt-gr) that German and so many of our European languages have and which are the only way to access things like {[]}@.

EDIT in addition to this it also completely ignores the idea of being able to remap some keys but not all - going by scancodes entering Insert mode on a dvorak layout would - for example - require pressing 'c' (which is the physical 'i' key) and that makes mnemonics completely useless.

soloturn commented 1 year ago

Scancodes don't work well at all for anything that is not a level-zero (direct input) key as you don't have an easy way to infere what scancode + modifier (shift, alt, ctrl, super, meta, option) maps to because that's something the OS keyboard layout is

the beautiful thing with helix, vi is that it does NOT use modified keys on the command mode. for entering text a different mode is used fortunately, i am happy how it behaves now. remapping scancodes should be as well possible, it is just a parameter?

EDIT in addition to this it also completely ignores the idea of being able to remap some keys but not all - going by scancodes entering _I_nsert mode on a dvorak layout would - for example - require pressing 'c' (which is the physical 'i' key) and that makes mnemonics completely useless.

vi / helix command mode reminds me on a terminal game - easy to type - and this is good so :) i d love to see the person first, who uses dvorak and insists on mnemonics. true, the i - insert mnemonics is gone on a dvorak, for others like the "hjkl" key navigation mnemonics was always the terminal game mnemonics. that one is masochistic to type on dvorak btw.

@geieredgar , as you have experience with game engines as well and editors. what woudl you recommend? how do games handle different keyboard layouts, to have a simple and easy to remember setting, ideally with a default which needs no configuration for most?

HealsCodes commented 1 year ago

Scancodes don't work well at all for anything that is not a level-zero (direct input) key as you don't have an easy way to infere what scancode + modifier (shift, alt, ctrl, super, meta, option) maps to because that's something the OS keyboard layout is

the beautiful thing with helix, vi is that it does NOT use modified keys on the command mode. for entering text a different mode is used fortunately, i am happy how it behaves now. remapping scancodes should be as well possible, it is just a parameter?

Well using keycodes for input mode but scancodes for everything else sounds like a great mess and rather complicated to implement requiring two models of requesting input from the OS for each platform helix runs on..

vi / helix command mode reminds me on a terminal game - easy to type - and this is good so :) i d love to see the person first, who uses dvorak and insists on mnemonics. true, the i - insert mnemonics is gone on a dvorak, for others like the "hjkl" key navigation mnemonics was always the terminal game mnemonics. that one is masochistic to type on dvorak btw.

Well you found one.. and honestly, mnemonics are key for all modal editors like vi, vim, nvim, helix and kakoune unless you are one of the persons that constantly looks at the letters written on the keys while typing. Call me wrong but 'c' doesn't really associate mentally with 'Insert', does it? Or 'uh' for 'go home / start of line', neither would ',' make sense to move words or 'e' for "delete" or 'q' to select the current line - all of these rely on mnemonics and don't work with scancode-based command modes unless you remap every key at which point you don't need scancodes anymore.

(P.S. all of these examples are the scancodes that correspond to 'i', 'gh', 'w', 'd' and 'x' respectively when typing on a dvorak-DE layout. All of these work as expected with something like langmap / langnoremap in vim and nvim without needing scancodes)

ZabejAga commented 1 year ago

There is a solution for the (n)vim/kak/VScodeVIM editors : plugins like im-select. It will change layout to defined (i.e. 'US') when you change mode to normal. Would be nice to have such solution here as it solves(at least part of) the issue.

HealsCodes commented 1 year ago

There is a solution for the (n)vim/kak/VScodeVIM editors : plugins like im-select. It will change layout to defined (i.e. 'US') when you change mode to normal. Would be nice to have such solution here as it solves(at least part of) the issue.

Sadly also only a workaround at best - as a foreign keyboard layout user you'd probably still only want to remap certain keys to the "intended places" (think where hjkl is) but keep the others where your layout has them so you can blind type the mnemonics without having to switch your brain back and forth between two layouts.

One workaround I've found that works for my DVORAK-DE layout - but it's wanting as it takes away some of the Alt+Key combinations - is to use Alt + H/D/R/N (the layout keys I get when pressing the physical h/j/k/l) and remap them to the cursor move and selection commands like this, but it's more of a hack than a real fix :|

# workaround for ALT + phys h/j/k/l movement on DVORAK-DE (just a sample)
[keys.normal]
"A-h" = "move_char_left"
"A-d" = "move_line_down"
"A-r" = "move_line_up"
"A-n" = "move_char_right"

[keys.select]
"A-h" = "extend_char_left"
"A-d" = "extend_visual_line_down"
"A-r" = "extend_visual_line_up"
"A-n" = "extend_char_right"

That way does provide movement my holding the left alt key and pressing the physical h/j/k/l but it also uses up those alt+key combos. The one advantage over a complete layout change this has is that I can still use 'd' to 'd'elete while alt+d (which is the physical 'j' key) moves my cursor etc.

ZabejAga commented 1 year ago

Sadly also only a workaround at best - as a foreign keyboard layout user you'd probably still only want to remap certain keys to the "intended places" (think where hjkl is) but keep the others where your layout has them so you can blind type the mnemonics without having to switch your brain back and forth between two layouts.

im-select is helpful when you mostly use non-latin layouts (I'm not programmer but notetaker).

One workaround I've found that works for my DVORAK-DE layout - but it's wanting as it takes away some of the Alt+Key combinations - is to use Alt + H/D/R/N (the layout keys I get when pressing the physical h/j/k/l) and remap them to the cursor move and selection commands like this, but it's more of a hack than a real fix :|

for such case I use remapped CAPSLOCk to Hyper and 'Hyper + ' as arrows. It works everywhere in PC )

eugenesvk commented 1 year ago

By the way, before Helix does the proper thing and implements a more convenient native support for alternative keyboard layouts you could use a couple of Python scripts to extend/replace your config to an alternative keymap

https://github.com/helix-editor/helix/discussions/7097

eugenesvk commented 1 year ago

There is a solution for the (n)vim/kak/VScodeVIM editors : plugins like im-select

But that's not a solution, e.g., if you have a visible keyboard selection indicator, it will constantly flash despite the fact that you don't really change any layout

eugenesvk commented 1 year ago

Call me wrong but 'c' doesn't really associate mentally with 'Insert', does it?

neither does h associate with left. Mnemonics aren't useful for such frequent keys as cursor movements or switching to insert mode, your muscle memory will very quickly map it to a finger, not a keycap (thus it's best to use a better key position), so being able to have consistent physical mappings is a plus of scancodes

But you're right that it should be flexible so that people who value mnemonics over physical location could continue to do so

By the way, WezTerm has this cool feature that allows you to pick the mode on a per-key basis

You can explicitly assign using the physical position by adding a phys: prefix to the value, for example: key="phys:A". This will match key presses for the key that would be in the position of the A key on an ANSI US keyboard.

https://wezfurlong.org/wezterm/config/keys.html#physical-vs-mapped-key-assignments

HealsCodes commented 1 year ago

Well the point of h/j/k/l is indeed to become "muscle memory" but it also mirrors the layout of arrow keys on older terminal keyboards and is mainly intended to keep your right hand on the homerow instead of having to move it all the time.

However literally all other keys are mnemonics matching the action they perform. The whole reason being that it helps you learn the action by deducing the keys from what you want to do.

Not using keys in your native layout is extremely crippling to your muscle memory training because it forms from associating things like "Insert" or "Go Home" or "Delete" - an action with a matching letter - with a muscle movement. Things which you sabotage by having zero relation between the key, and the action it triggers.

Alas.. we're derailing the topic.

eugenesvk commented 1 year ago

mainly intended to keep your right hand on the homerow instead

Same principle - you chose a more convenient location instead of relying on a keycap match

Not using keys in your native layout is extremely crippling to your muscle memory training because it forms from associating things like "Insert" or "Go Home" or "Delete" - an action with a matching letter - with a muscle movement.

you're not crippling it for the same reason jkl does not - keycap associations don't provide much over repetition, which is plenty for these commonly used keys like Insert. And then there are too many commands that start with some letter for you to have a unique association (how does D delete, left or right? with or without yank, where would decrement command go?)

Things which you sabotage by having zero relation between the key, and the action it triggers.

The relation is not zero, it's just not keycap-based. For example, H is positioned to the left, and home is positioned to the left, so here is your association - you move your finger off home keys to the left to move further left (or I'm using h as backspace with a similar direction-based mnemonic)

Alas.. we're derailing the topic.

Well, scan codes are a solution to this very topic, and they are a better solution than the workaround I've posted above since they also work for symbol keys and don't pollute the popup window, but you're arguing against them based on the value of keycap-based mnemonics

alexeymuranov commented 8 months ago

An idea: #9896.

HealsCodes commented 8 months ago

An idea: #9896.

While this is a valid idea it would still require that 'minor' normal mode to use scancode based input or translate the keys to scancodes on the fly in order to be able to act on key positions instead of the received character.

Otherwise youre asking to provide a mapping for every possible keyboard layout in existence and any that might crop up in the future or are in use by people that make their own.

That's pretty much exactly why ViM has langmap which was suggested a number of times already.. it allows you to switch an arbitrary number of pairs of keys but only while normal mode is active.

alexeymuranov commented 8 months ago

@HealsCodes, I would not mind some kind of configured automated langmap for both my 'major' and 'minor' normal modes. As long as it works. (Which is not the case in Vim: vim/issues/3018, vim/issues/5147.)

HealsCodes commented 8 months ago

"not the case" is a wide stretch - I've been using it in ViM for over a decade and it works in combination with langnoremap. Not surprised it wasn't implemented with multibyte characters back in the day (you have to account for the age of ViM, proper unicode support came way after).

If you were to implement this feature in recent days you would probably use unicode-codepoints or actual scancodes for the langmap syntax to begin with ^^'