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

Come up with good story for custom (non-xterm) keybindings support #487

Closed
Tyriar opened this issue Jan 17, 2017 · 25 comments
Closed

Come up with good story for custom (non-xterm) keybindings support #487

Tyriar opened this issue Jan 17, 2017 · 25 comments
Labels
out-of-scope type/enhancement Features or improvements to existing features

Comments

@Tyriar
Copy link
Member

Tyriar commented Jan 17, 2017

We currently support things like alt+arrow to jump words which is done by overriding what escape sequence we send to the pty. We should look at making this configurable with safe defaults so that consumer(s) can turn it off/configure if they desire.

@parisk
Copy link
Contributor

parisk commented Jan 18, 2017

This could be a keyMap like option, where we can map either key bindings or escape codes to terminal actions.

How does that sound?

@Tyriar
Copy link
Member Author

Tyriar commented Jan 18, 2017

Something like that is what I was thinking, however it gets tricky in the case like ctrl+v where I think the escape sequence we generate is the same as v

@Tyriar
Copy link
Member Author

Tyriar commented Jan 18, 2017

This is also the reason we can't use an ~/.inputrc file to get option+backspace to delete a word on Mac.

@mofux
Copy link
Contributor

mofux commented Jan 19, 2017

I've been thinking a lot about this recently, here is my idea (considering the many issues open on hyper related on this topic):

The main problem is, that accelerators of the app (e.g. hyper) collide with accelerators that the app running in the terminal wants to consume. To get around this problem, most apps introduce a meta key that helps to escape from the terminal. While this works in most cases, it is uncomfortable to use, because you need three fingers. So why don't we...

Use a keyboard gesture to escape the terminal
The idea is that if you double-tap a modifier key (ctrl, alt, shift, meta?), then the key will not be sent to the terminal, but will be forwarded to user, so his app can consume it. Without the double-tap, the key(s) will be consumed by the terminal.

Example: ctrl...ctrl+x or alt...alt+left will not be consumed by the terminal but forwarded as ctrl+x and alt+left to the user.

There are some edge cases that we have to consider:
Say you want to switch between tabs of an application, using ctrl+alt+left and ctrl+alt+right. Now, to jump to the left pane, you would press ctrl...ctrl+alt+left. But if you want to jump two panes to the left in a row, you don't want to press ctrl...ctrl+alt+left ctrl...ctrl+alt+left, you want to press ctrl...ctrl+alt+left left. This should be fairly easy to implement, but has to be considered.

In addition, for the very commonly used ctrl+c we should let it copy if text is selected, otherwise we should write the control sequence to the terminal.

Pasting can be done with ctrl...ctrl+v, middle or right mouse button.

@Tyriar
Copy link
Member Author

Tyriar commented Jan 19, 2017

@mofux for VS Code I introduced a commandsToSkipShell setting which lists off a bunch of commands whose keybindings will not be processed by xterm.js. So you should be able to intercept cases like this using Terminal.attachCustomKeydownHandler and handle it however you want at a higher level (ctrl+c + text selected -> copy, ctrl+c + no text selected -> send to xterm.js).

My personal thinking is this is more about having xterm.js handle the common keybindings that are not standard but generally desirable, but allowing consumers to opt out and/or handle it themselves.

@mofux
Copy link
Contributor

mofux commented Jan 19, 2017

Oh i see, having a map of actions (e.g. 'JUMP_WORD_LEFT') and a default but customisable keybinding for it would certainly make sense. Might be worth to have a mapping that looks like this:

{
  "COPY": { "mac": "cmd+c", "win": "ctrl+c", "default": "ctrl+c" },
  "JUMP_WORD_LEFT": { "default": "alt+left" }
}

default is the fallback if the binding for the current platform is not specified.

Hyper uses a lib called mousetrap to allow key strings like above to be interpreted.

@Tyriar
Copy link
Member Author

Tyriar commented Jan 19, 2017

Yeah something like that, I think this is the sort of information we need to encode:

"mac": {
  "alt+delete": "\x17"
}

Pressing alt+delete will send \x17 (^W) to the pty.

@Tyriar
Copy link
Member Author

Tyriar commented Jan 19, 2017

Which is similar to the format of an .inputrc file, but allows the actual key presses to be overridden in cases such as alt+delete where the where delete and alt+delete return the same escape sequences.

See #486 and http://stackoverflow.com/a/29773694/1156119

@parisk
Copy link
Contributor

parisk commented Jan 20, 2017

So, should we settle in an option named keyMap?

Would the following format also work?

{
  "all": {
    "ctrl+space": "\x00"
  },
  "mac": {
    "alt+delete": "\x17"
  },
  "win": {
    "ctrl-v": null
  }
}

@Tyriar
Copy link
Member Author

Tyriar commented Jan 20, 2017

Looks good, shall we construct the default keyMap first before going ahead and implementing to ensure it covers all the cases? Here's a start:

{
  "all": {
    "alt+left": "\x1b[1;5D",
    "alt+right": "\x1b[1;5C",
    "alt+up": "\x1b[1;5A",
    "alt+down": "\x1b[1;5B",
    "ctrl+backspace": "\x17"
  },
  "mac": {
    "alt+left": "\x1bb", // Mac use different escape sequences to Linux for jumping word
    "alt+right": "\x1bf",
    "alt+delete": "\x17"
  }
}

Writing this up there is the ctrl/shift+insert case which skips the terminal, should consumers now handle that if they want it via attachCustomKeydownHandler?

@parisk
Copy link
Contributor

parisk commented Jan 21, 2017

OK, I created this Git as my take on mac only key bindings, based on Terminal.app's configuration (which I have left to default):

https://gist.github.com/parisk/f2d7eb8bd5584d9969c2449eee9d052c

The two questions I have in mind right now are:

  • Should we keep keymap(s) in .js file(s) in order to be able to add comments next to each line?
  • Should we only send strings to the terminal or should we be able to "instruct" it to run a semantic "command" (e.g. Instruct it to insert a line feed)

@Tyriar
Copy link
Member Author

Tyriar commented Jan 21, 2017

We could have a KeyMap.ts/Options.ts which exported the default one so it's nicely separated.

I think sending strings is the best option. Apps built on top could be clever if they want to add aliases but including it here may be overkill for this project and cause bloat that not many use?

@Tyriar
Copy link
Member Author

Tyriar commented Jan 21, 2017

From @LeviticusMB in microsoft/vscode#11314 (comment)

Essentials: Arrow keys, backspace, d (delete current word), c (capitalize), l (lowercase), u (uppercase) but see https://en.wikipedia.org/wiki/GNU_Readline and http://www.aboutlinux.info/2005/08/bash-shell-shortcuts.html.

@parisk parisk self-assigned this Jan 30, 2017
@parisk
Copy link
Contributor

parisk commented Jan 30, 2017

@Tyriar does Gnome3 have any particular bindings worth sharing, besides the ones listed in the comment above?

@Tyriar
Copy link
Member Author

Tyriar commented Feb 2, 2017

Not that I'm aware of

@Tyriar
Copy link
Member Author

Tyriar commented May 16, 2017

From @peabnuts123 in microsoft/vscode#11314 (comment)

On OSX "Use Option as Meta Key" is a setting in the default Terminal app. All this does is change the functionality of Option to send the Meta key instead (as opposed to typing in special characters such as ∂, not very useful on a Terminal IMO). The Meta key is then used for whatever by whatever application you run within it. A List of Features that the Option key "should do" is not really the right solution for this. For example, when using tmux, I have Meta-Z bound as my prefix for commands; so to split a pane I first press Option-Z (Meta-Z) and then \. This does not work in the VSCode integrated terminal, and no amount of feature documenting is going to fix that.

I think that the change that is needed here is a similar option for the Integrated terminal on OSX to support the Meta key within the terminal. I realise this may be an issue with the underlying terminal library itself, however.

@Tyriar
Copy link
Member Author

Tyriar commented Dec 12, 2017

The more I've thought about this the more I think it should be handled at a higher level than xterm.js. Most embedders have some keybinding system that is far more featureful than what xterm.js would be able to offer (Hyper and VS Code for example), especially if we were trying to minimize bloat. As such I suggest we close this off and instruct embedders to handle this themselves, perhaps setting up a FAQ on the website too?

@saamalik
Copy link
Contributor

Hi @Tyriar -- could you please advice what changes are necessary for Mac OSX users to be able to just alt as a meta. Using the awesome Hyper terminal, which of course is using this really cool underlying library.

Here is the corresponding bug on Hyper: vercel/hyper#2578. Any recommendations or hints on what config to change would be much appreciated.

@Tyriar
Copy link
Member Author

Tyriar commented Jan 19, 2018

@saamalik the "alt as meta feature" on macOS needs support added to xterm.js, then Hyper would get it when they upgrade. It will involve hooking up a new option here:

const DEFAULT_OPTIONS: ITerminalOptions = {

export interface ITerminalOptions {

And then using the option where the escape sequences are built from keystrokes:

protected _evaluateKeyEscapeSequence(ev: KeyboardEvent): {cancel: boolean, key: string, scrollLines: number} {

@saamalik
Copy link
Contributor

@Tyriar added. Let me know if you'd like me to make any changes! Also not sure if we're supposed to checkin package-lock?

@Tyriar
Copy link
Member Author

Tyriar commented Jan 19, 2018

@saamalik best leave package-lock.json out, I just added it in #1214 so I'm not sure why it has so many changes for you 😕

@saamalik
Copy link
Contributor

@Tyriar ok removed package-lock.json.

@Tyriar
Copy link
Member Author

Tyriar commented Oct 7, 2019

Closing this as out of scope. Embedders will generally have their own keybindings system which would be better that the small one we would want to do for this, it would be better to leave this up to them rather than include another one that just adds bloat.

@krishnautpala
Copy link

krishnautpala commented Sep 9, 2020

Also is there a simple way to update the key mappings? Like we generally do in Xdefaults, a single json file which can take in configs and override them with default will be good.
I am new to xterm but I am looking for this specifically to overwrite F1-F24 keys. Any advice here?
@Tyriar

@Tyriar
Copy link
Member Author

Tyriar commented Sep 9, 2020

@krishnautpala we decided on letting you the user of xterm.js come up with your own system for handling keybindings since most terminals/ides would have their own system anyway. If you need to override the F keys, use this API to handle the keys manually and cancel them before they get to xterm.js by returning false in the handler:

xterm.js/typings/xterm.d.ts

Lines 726 to 735 in 3504e2e

/**
* Attaches a custom key event handler which is run before keys are
* processed, giving consumers of xterm.js ultimate control as to what keys
* should be processed by the terminal and what keys should not.
* @param customKeyEventHandler The custom KeyboardEvent handler to attach.
* This is a function that takes a KeyboardEvent, allowing consumers to stop
* propagation and/or prevent the default action. The function returns
* whether the event should be processed by xterm.js.
*/
attachCustomKeyEventHandler(customKeyEventHandler: (event: KeyboardEvent) => boolean): void;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
out-of-scope type/enhancement Features or improvements to existing features
Projects
None yet
Development

No branches or pull requests

5 participants