hyper: Hyperterm doesn't handle Alt key combinations correctly

  • I am on the latest Hyper.app version
  • I have searched the issues of this repo and believe that this is not a duplicate
  • OS version and name: macOS 10.12.2
  • Hyper.app version: 1.0.1
  • The issue is reproducible in vanilla Hyper.app: Added modifierKeys: { altIsMeta: true } to otherwise stock .hyper.js

Issue

Issue: when trying to do Alt key combinations (ie. Alt+Left_arrow, Alt+backspace), Hyperterm doesn’t interpret this as a command (such as skipping back/forward a word or deleting an entire word). When using Alt+arrow keys, Hyper places [D or [C, etc. and when using Alt+delete, it deletes two words instead of one. Alt+delete also causes multiple lines of text to be erased in emacs.

Relevant info: using zsh shell + ohmyzsh, only modification to .hyper.js is modifierKeys: { altIsMeta: true } to get Alt to work at all.

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 30
  • Comments: 16 (1 by maintainers)

Most upvoted comments

I’ve been tearing my hair out trying to figure out the relationship between alt, meta and escape, and why some things seem to work in iTerm but not in Hyper. I believe I’ve understood what’s going on and figured I’d post here for anybody who is as frustrated as I was:

TLDR: iTerm and Hyper mean different things by “treating alt as meta”. Hyper also appears to have an issue with feeding escape-prefixed bytes to the shell.

In the past, many keyboards had meta keys. Traditionally, terminals interpreted the meta modifier to set the most significant bit on a byte. ASCII is a 7-bit code in which the most significant bit is always unset. ASCII with meta turns this into a full 8-bit (1 byte) code. Shells and other terminal programs allowed you to bind these metafied bytes. For example, in zsh bindkey "\M-x" kill-word binds the ASCII byte code for x, with its most significant bit set, to the kill-word widget. Let us refer to bytes with their most significant bit set as “metafied”.

However, at some point meta keys started disappearing from keyboards. Because it is better for terminals to function consistently across different keyboards, many terminals started to change their interpretation of meta. Now, rather than setting the most significant bit, an additional escape (^[) byte was prepended. Thus pressing meta no longer expressed functionality that was impossible for metaless keyboards, since simultaneously pressing meta and x had the same effect as pressing Esc followed by x. Let us refer to bytes preceded by an Esc as “escape-prefixed”.

Unfortunately established software was quite slow to change. Shells and other terminal programs like vim continue to reference meta in their configuration. Some key on the modern keyboard had to be chosen to map to this functionality, and alt became the choice. Thus in macOS Terminal.app there is an option to “Use Option as Meta key”. In iTerm2, you can set each option to one of three settings: Normal Meta or Esc+. And in Hyper, you can set altIsMeta: true.

Now, what is extremely confusing about the above is that Meta does not mean the same thing in these three apps. Notice that Terminal and Hyper allow only two options for alt, whereas iTerm allows three. That is because, in both Terminal and Hyper, “use option as meta” means “holding alt generates escape-prepended bytes”. You can confirm this by setting this option, going into the respecting terminal, and pressing Ctrl-k Alt-k (Ctrl-k will bypass shell interpretation for the following character, allowing you to insert it directly). In both cases, you should see ^[k, which is an escape character followed by k. Thus, Hyper and Terminal restrict the user to this escape-prefixing behavior and don’t seem to expose any way to metafy bytes, which means that you can’t target zsh bindings like \M-x in Hyper or Terminal. In contrast, “Meta” in iTerm means “metafy this byte” and “Esc+” means “escape-prefix this byte”

Even more confusingly, many terminal programs treat escape-prefixed and metafied bytes as completely different, whereas others treat them the same. In zsh for instance, bindkey "\M-x" maps to metafied ASCII x, and bindkey "^[x" (or `bindkey “\ex”) maps to escape-prefixed x. Meanwhile, other programs contain a layer that automatically translates metafied bytes (most significant bit set) into their escape-prefixed siblings. Thus, some terminal programs will work differently depending on whether the terminal is performing metafication or escape-prefixing, whereas others will work the same.

Finally, Hyper in particular seems to have a problem with feeding escape-prefixed bytes to the shell. I have bindkey -M viins "\en" history-substring-search-up in my zsh config. In Terminal, with alt set to behave as meta (i.e. perform escape-prefixing), this works fine. However, in Hyper, with altIsMeta: true it doesn’t work despite the fact that the same escape-prefixing behavior is performed. Instead, alt+n puts me out of viins (vim-insert) mode and into normal mode. What this tells me is that for some reason the leading escape byte is being processed separately from the following n byte, which is triggering the switch out of insert mode. I suspect this is related to #1877 since they both involve Hyper feeding text to the shell.

Is there any update on this issue ? This issue is killing Hyper for any use. Cannot use the ALT key at all, it gets mapped to ctrl sequences in vim and well anything. Tried setting altIsMeta to true and false yet it does nothing.

I too am having this problem and can reproduce correctly.

Default behaviour of <kbd>Alt</kbd> + <kbd>Delete</kbd> key combination seems to do nothing.

Setting modifierKeys: { altIsMeta: true } explicitly in the configuration will allow the simultaneous deletion of two words instead of the expected behaviour of only deleting one word.

alt + arrow keys for tmux shortcuts not working as well

I fixed Alt+. for my setup by adding a command which is invoked with the Alt+. combination and sends the same escape sequence as xterm. See: https://github.com/iimog/hyper/commit/b603f13900b79968f5519f1ee9bbab8f69a22611

Only tested for linux (only modified keymaps/linux.json) with Hyper version 2.0.0-canary.9, running zsh.

I assume that this way to fix it is not sufficiently generic for all the other Alt key combinations. I’ll try to wrap things into a mini plugin to make it work without re-building hyper.

@chabou for future reference, I don’t think xterm.js has an option for alt as meta atm, here is the relevant function such an option would affect though https://github.com/sourcelair/xterm.js/blob/1c84881d00e381f9f1b4fde235149ffc13296734/src/xterm.js#L1494

Also this is kind of related: https://github.com/sourcelair/xterm.js/issues/487