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

Can't use Ctrl-c to kill currently running interactive process in terminal #532

Closed
marcdumais-work opened this issue Sep 21, 2017 · 23 comments
Labels
terminal issues related to the terminal
Milestone

Comments

@marcdumais-work
Copy link
Contributor

I think the browser's key mapping for "copy" conflicts with the terminal's "kill current process".

Work-around: instead do Ctrl-Z to put the process in background, find the process with "ps" and kill it. Or kill it in another instance of terminal.

@marcdumais-work marcdumais-work added the terminal issues related to the terminal label Sep 21, 2017
@hexa00
Copy link

hexa00 commented Sep 21, 2017

An idea would be to let ctrl-c go though when there's no selection ?

@simark
Copy link
Contributor

simark commented Oct 18, 2017

Here's what happens.

  • Theia installs a "capture" phase keydown handler on the whole document.
  • xterm.js installs a "bubble" phrase keydown handler on a textarea (that is in focus when the user clicks on the terminal).
  • When typing ctrl-c while a terminal is focused, Theia's handler is invoked. It finds that ctrl-c is bound to the "core.copy" command, and runs that command. It then calls event.stopPropagation(), so the handler of xterm.js is never invoked.

What we would want instead is that when a terminal is in focus:

  • The xterm.js handler should be invoked somehow.
  • The "core.copy" command (or whatever command associated to ctrl-c) should not be invoked.

I don't know how to change the architecture to achieve this, so some guidance would be appreciated.

One path might be to have the terminal module register a keybinding for ctrl-c, valid for when in the terminal context/focused on a terminal, and for the keybinding system to support some kind of priority. Because the focus would be in the terminal, the terminal's keybinding handler would be invoked first, taking precedence over the "global" one.

The terminal's handler could either:

  • Indicate to the keybinding system to not stop propagation of the event. The event would reach xterm.js's handler and do its thing.
  • Manually call xterm.js's keydown handler. This seems a bit hackier because we need to know the internals of xterm.js, but it could still work.

@svenefftinge
Copy link
Contributor

svenefftinge commented Nov 10, 2017

As described in #814 I think the terminal extension should register a keybinding for CTRL+C using a more specific keybinding context (i.e. 'terminalActive').

@hexa00
Copy link

hexa00 commented Nov 10, 2017

Note this approach should be generalized such that all keybinding of xterm are registered.

@hexa00
Copy link

hexa00 commented Nov 10, 2017

I think this needs more thinking... I'm not sure anymore that this is correct..

@hexa00
Copy link

hexa00 commented Nov 10, 2017

Seems like it would be better rebind the Copy in case the terminal is active to like Ctrl-Shift-C and let Ctrl-C go passthough

@simark
Copy link
Contributor

simark commented Nov 10, 2017

As described in #814 I think the terminal extension should register a keybinding for CTRL+C using a more specific keybinding context (i.e. 'terminalActive').

What in the keybinding code ensures that the keybinding of the terminal would take precedence over the copy keybinding? Last time I check the code (specifically keybinding.ts, method getKeybindingForKeyCode), I found that it would just pick the first handler and run that. I didn't see anything about priority, and didn't really understand how contexts fit into that.

@svenefftinge
Copy link
Contributor

Yes, the code is broken. It should do the context check from line https://github.com/theia-ide/theia/blob/master/packages/core/src/common/keybinding.ts#L195 in getKeybindingForKeyCode and getKeybindingForCommand.

@svenefftinge
Copy link
Contributor

Seems like it would be better rebind the Copy in case the terminal is active to like Ctrl-Shift-C and let Ctrl-C go passthough

You would simply register those two keybindings for the terminalContext and forward them to the appropriate commands.

@svenefftinge
Copy link
Contributor

I opened #819

@hexa00
Copy link

hexa00 commented Nov 10, 2017

You would simply register those two keybindings for the terminalContext and forward them to the appropriate commands.

I guess we could have a generic command that is just send that key... to the term.

And we could include things like C-a C-e etc.. (term navigation in there) + C-z , C-s ... would need to check for all others..

@marcdumais-work marcdumais-work added this to the Theia BETA milestone Nov 14, 2017
@svenefftinge
Copy link
Contributor

@simark I had a look at your approach to add ‘PassThroughKeybindings’. simark@eeab467#diff-d7170acc306571b2666d36a305f828ca

As I mentioned on gitter, we need to be able to serialize keybindings and allow users to change them using keymap files. Also, we want to allow to refer to a context per keybinding to resolve conflicts (e.g. CTRL+C in terminal).

So the KeybindingContextRegistry is meant to be used by extension developers to introduce contexts, e.g. 'terminalActive'. Users can then reference that context per id in the keymaps.

Although, the idea of pass-through would simplify configuration a bit, because we won't need to introduce commands for all the terminal commands, but it will also forbid to rebind a certain command to another keybinding. So I think it would be better to explicitly redeclare all the terminal commands and always require a command id for a keybinding.

P.S.: I am aware that the KeybindingContext is currently not working and is also conceptually lacking important things like e.g. a notion of context priority. We should work on that :)

@simark
Copy link
Contributor

simark commented Nov 20, 2017

At least with the terminal bindings that send control characters (ctrl-<key>), I don't think it makes sense to allow the user to rebind them. I don't know any terminal application that allows to do that, they are just baked in the vt100 emulation that we are all used to. That's why I preferred not to create commands for them, it greatly reduces the complexity. The more we do, the more we risk interfering with the expected terminal behavior. Our code would also have to find out which terminal instance is focused, find its associated Terminal object instance and "inject" a fake KeyboardEvent in it (I don't see how to do this with the current xterm.js API). That's basically doing the job of the browser.

I can imagine though that a user would want ctrl-p to pop open the command palette even when a terminal is in focus, because they never use ctrl-p in the terminal and they want to be able to access the command palette quickly. I guess for that we need a way to "disable" the passthrough keybinding.

In the end, if all the keybindings (including the ones shipped by default by Theia) appear in the user config file, they can just comment or remove the ctrl-p passthrough keybinding associated to the terminal. ctrl-p will then invoke the global one, opening the command palette.

On the other hand, if modules contribute default keybindings programmatically as we do today and the user keybinding config file only contains the user-defined/custom bindings, then we would need a way to "disable" the built-in terminal keybinding, so that the global one that triggers the command palette is invoked. The user could rebind ctrl-p to the command palette with a context with an even higher priority than the terminal, but it would be a bit obscure and I wouldn't expect a user to guess how to do that. Do you see a better way to do this? It often happens that users want to disable a keybinding, because they accidentally trigger it often and just want to get rid of it, without defining a new binding.

Note that this problem (how to disable a built-in keybinding) applies to all built-in keybindings, it's not related to the terminal or the concept of passthrough keybinding in particular.

As for the serialization, the concept of passthrough keybinding doesn't really matter, we can have an action field that says what to do when the keybinding is invoked. Something like:

[{
  key: "ctrl-c",
  context: "terminalActive",
  action: "passthrough"
}.
{
  key: "ctrl-c",
  action: "command",
  command: "core.copy"
}]

As for the keybinding context registry, what you said makes sense to me.

@svenefftinge
Copy link
Contributor

Note that this problem (how to disable a built-in keybinding) applies to all built-in keybindings, it's not related to the terminal or the concept of passthrough keybinding in particular.

Of course, but in general you want to have those commands

  • rebindable,
  • addable to menus and
  • show up in the command palette.

Just like we did for monaco commands.

If that all is not the case for terminal commands we might add the concept of pass-through as you suggest. It would be good if we don't encourage others to use it for the reasons I mentioned above, though. Also, Do you want to make 'disabling' and 'pass-through' behave the same? Shouldn't disable not consume the event?

@simark
Copy link
Contributor

simark commented Nov 20, 2017

I am not sure how disabling a built-in keybinding would work (how it would look in the config), but I don't think it would be the same as passthrough. Let's say you have two keybinding registered for the same keyboard sequence, both are registered programmatically by modules. Here they are, in order of priority:

  1. binding 1, context = foo
  2. binding 2, context = null (global)

When the user triggers the keybinding, we invoke binding 1. Let's say the user doesn't care about binding 1, and wants the key sequence to always invoke binding 2 (even when in context foo). Disabling it would mean that when looking for a handler, we would skip binding 1 and invoke binding 2. Or maybe binding 1 would be removed from the keybindings data structures entirely. But in the end binding 2 would be invoked.

Passthrough would not be the same. If binding 1 is a passthrough, we would not invoke binding 2. We would just return and let the event propagate in the browser.

If there is a single keybinding defined for a keysequence, then disabling and passthrough would end up the same, since if we don't find a matching keybinding, we let the event propagate.

@simark
Copy link
Contributor

simark commented Nov 22, 2017

As for serialization/deserialization, I guess that we'll need to write some code that convert the objects to and from the JSON representation, when we implement the keybinding configuration file, but that shouldn't be hard.

@akosyakov
Copy link
Member

akosyakov commented Nov 23, 2017

Regarding serialization: It is not only about keymaps, right now keybindings API is overly verbose. We want to simplify it to:

registry.registerKeybinding({
    command: ElectronCommands.RELOAD.id,
    key: "R+CmdCtrl"
});

Ideally to use the same format as for keymaps.

@simark
Copy link
Contributor

simark commented Nov 23, 2017

I am not sure I understant what is the difference between keymaps and keybindings, can you clarify?

@epatpol
Copy link
Contributor

epatpol commented Nov 23, 2017

I think keymaps refers to custom keybindings. I think we decided to stick with keymaps from custom keybindings along the way when referring to custom keyboard shortcuts.

@simark
Copy link
Contributor

simark commented Nov 24, 2017

I had a chat with @epatpol, and there does not seem to be anything in my design that is a problem for him.

@hexa00
Copy link

hexa00 commented Nov 24, 2017

@simark
I think we could have special commands like PassThrough / Disable

This would keep the interface simple while allowing what we need.

And they're won't be that much special commands like that so there's no need to encode this is object oriented design a simple if/else/switch would do.

WDTY?

@simark
Copy link
Contributor

simark commented Nov 24, 2017

After discussing with @hexa00, what he means is that we could have:

{
  key: "ctrl-c",
  command: "passthrough",
}

I initially thought of adding a proper passthrough command, and have do nothing, but return a code to mean that the keystroke should not be swallowed by Theia. The problem is that commands know nothing about keybindings, so it doesn't really make sense to have in the commands API that is related to keybindings.

But after discussing with @hexa00, we think that we can probably just handle the special case in KeybindingRegistry.run, like:

if (binding.commandId == "passthrough") {
    // do nothing
} else {
  // invoke command as usual
  // prevent keystroke event propagation
}

As @hexa00 said, there won't be many special cases like this, so it should stay simple and clear.

simark pushed a commit that referenced this issue Nov 24, 2017
Currently, typing ctrl-c in the terminal does not yield the expected
result, which is sending a SIGINT to the running process.  The problem
is that a Theia keybinding is registered for ctrl-c (to copy).  Theia
catches it and thinks you want to copy.

When the focus is on a terminal, we don't want Theia to handle the event
itself, but rather let the event propagate.  xterm.js' keyboard event
handler will catch it, and things will work as usual.  To that end,
this patch introduces the concept of passthrough keybindings.  When
the user invokes such a keybinding, Theia does nothing and lets the
event propagate.  To specify a passthrough keybinding, one needs to use
"passthrough" as the command id, which is treated in a special way by
the KeybindingRegistry.

However, we also need the concept of event priority, to make sure that
when we are in a terminal context, that keybinding will take precedence
over the global one.  As a simple approximation, I made the
KeybindingRegistry consider bindings that specify a context before those
that don't.

The terminal module registers passthrough commands for all the key
combination xterm.js recognizes right now:

  https://github.com/xtermjs/xterm.js/blob/v3/src/Terminal.ts#L1684

Some improvements should be made for Mac though.  To match xterm.js'
behavior, the alt-<key> combinations should only be registered on
non-Mac computers, but I don't know how to do that.  Also, I suppose
that on Mac, the ctrl-<key> bindings should be registered with the M4
modifier?  Finally, there's the cmd-A shortcut registered specifically
for Mac.  It would be nice if somebody that has access to a Mac could
improve that.

Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
simark pushed a commit that referenced this issue Nov 25, 2017
Currently, typing ctrl-c in the terminal does not yield the expected
result, which is sending a SIGINT to the running process.  The problem
is that a Theia keybinding is registered for ctrl-c (to copy).  Theia
catches it and thinks you want to copy.

When the focus is on a terminal, we don't want Theia to handle the event
itself, but rather let the event propagate.  xterm.js' keyboard event
handler will catch it, and things will work as usual.  To that end,
this patch introduces the concept of passthrough keybindings.  When
the user invokes such a keybinding, Theia does nothing and lets the
event propagate.  To specify a passthrough keybinding, one needs to use
"passthrough" as the command id, which is treated in a special way by
the KeybindingRegistry.

However, we also need the concept of event priority, to make sure that
when we are in a terminal context, that keybinding will take precedence
over the global one.  As a simple approximation, I made the
KeybindingRegistry consider bindings that specify a context before those
that don't.

The terminal module registers passthrough commands for all the key
combination xterm.js recognizes right now:

  https://github.com/xtermjs/xterm.js/blob/v3/src/Terminal.ts#L1684

Some improvements should be made for Mac though.  To match xterm.js'
behavior, the alt-<key> combinations should only be registered on
non-Mac computers, but I don't know how to do that.  Also, I suppose
that on Mac, the ctrl-<key> bindings should be registered with the M4
modifier?  Finally, there's the cmd-A shortcut registered specifically
for Mac.  It would be nice if somebody that has access to a Mac could
improve that.

Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
simark pushed a commit that referenced this issue Nov 27, 2017
Currently, typing ctrl-c in the terminal does not yield the expected
result, which is sending a SIGINT to the running process.  The problem
is that a Theia keybinding is registered for ctrl-c (to copy).  Theia
catches it and thinks you want to copy.

When the focus is on a terminal, we don't want Theia to handle the event
itself, but rather let the event propagate.  xterm.js' keyboard event
handler will catch it, and things will work as usual.  To that end,
this patch introduces the concept of passthrough keybindings.  When
the user invokes such a keybinding, Theia does nothing and lets the
event propagate.  To specify a passthrough keybinding, one needs to use
"passthrough" as the command id, which is treated in a special way by
the KeybindingRegistry.

However, we also need the concept of event priority, to make sure that
when we are in a terminal context, that keybinding will take precedence
over the global one.  As a simple approximation, I made the
KeybindingRegistry consider bindings that specify a context before those
that don't.

The terminal module registers passthrough commands for all the key
combination xterm.js recognizes right now:

  https://github.com/xtermjs/xterm.js/blob/v3/src/Terminal.ts#L1684

Some improvements should be made for Mac though.  To match xterm.js'
behavior, the alt-<key> combinations should only be registered on
non-Mac computers, but I don't know how to do that.  Also, I suppose
that on Mac, the ctrl-<key> bindings should be registered with the M4
modifier?  Finally, there's the cmd-A shortcut registered specifically
for Mac.  It would be nice if somebody that has access to a Mac could
improve that.

Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
simark pushed a commit that referenced this issue Nov 27, 2017
Currently, typing ctrl-c in the terminal does not yield the expected
result, which is sending a SIGINT to the running process.  The problem
is that a Theia keybinding is registered for ctrl-c (to copy).  Theia
catches it and thinks you want to copy.

When the focus is on a terminal, we don't want Theia to handle the event
itself, but rather let the event propagate.  xterm.js' keyboard event
handler will catch it, and things will work as usual.  To that end,
this patch introduces the concept of passthrough keybindings.  When
the user invokes such a keybinding, Theia does nothing and lets the
event propagate.  To specify a passthrough keybinding, one needs to use
"passthrough" as the command id, which is treated in a special way by
the KeybindingRegistry.

However, we also need the concept of event priority, to make sure that
when we are in a terminal context, that keybinding will take precedence
over the global one.  As a simple approximation, I made the
KeybindingRegistry consider bindings that specify a context before those
that don't.

The terminal module registers passthrough commands for all the key
combination xterm.js recognizes right now:

  https://github.com/xtermjs/xterm.js/blob/v3/src/Terminal.ts#L1684

Some improvements should be made for Mac though.  To match xterm.js'
behavior, the alt-<key> combinations should only be registered on
non-Mac computers, but I don't know how to do that.  Also, I suppose
that on Mac, the ctrl-<key> bindings should be registered with the M4
modifier?  Finally, there's the cmd-A shortcut registered specifically
for Mac.  It would be nice if somebody that has access to a Mac could
improve that.

Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
simark pushed a commit that referenced this issue Nov 27, 2017
Currently, typing ctrl-c in the terminal does not yield the expected
result, which is sending a SIGINT to the running process.  The problem
is that a Theia keybinding is registered for ctrl-c (to copy).  Theia
catches it and thinks you want to copy.

When the focus is on a terminal, we don't want Theia to handle the event
itself, but rather let the event propagate.  xterm.js' keyboard event
handler will catch it, and things will work as usual.  To that end,
this patch introduces the concept of passthrough keybindings.  When
the user invokes such a keybinding, Theia does nothing and lets the
event propagate.  To specify a passthrough keybinding, one needs to use
"passthrough" as the command id, which is treated in a special way by
the KeybindingRegistry.

However, we also need the concept of event priority, to make sure that
when we are in a terminal context, that keybinding will take precedence
over the global one.  As a simple approximation, I made the
KeybindingRegistry consider bindings that specify a context before those
that don't.

The terminal module registers passthrough commands for all the key
combination xterm.js recognizes right now:

  https://github.com/xtermjs/xterm.js/blob/v3/src/Terminal.ts#L1684

Some improvements should be made for Mac though.  To match xterm.js'
behavior, the alt-<key> combinations should only be registered on
non-Mac computers, but I don't know how to do that.  Also, I suppose
that on Mac, the ctrl-<key> bindings should be registered with the M4
modifier?  Finally, there's the cmd-A shortcut registered specifically
for Mac.  It would be nice if somebody that has access to a Mac could
improve that.

Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
simark pushed a commit that referenced this issue Nov 27, 2017
Currently, typing ctrl-c in the terminal does not yield the expected
result, which is sending a SIGINT to the running process.  The problem
is that a Theia keybinding is registered for ctrl-c (to copy).  Theia
catches it and thinks you want to copy.

When the focus is on a terminal, we don't want Theia to handle the event
itself, but rather let the event propagate.  xterm.js' keyboard event
handler will catch it, and things will work as usual.  To that end,
this patch introduces the concept of passthrough keybindings.  When
the user invokes such a keybinding, Theia does nothing and lets the
event propagate.  To specify a passthrough keybinding, one needs to use
"passthrough" as the command id, which is treated in a special way by
the KeybindingRegistry.

However, we also need the concept of event priority, to make sure that
when we are in a terminal context, that keybinding will take precedence
over the global one.  As a simple approximation, I made the
KeybindingRegistry consider bindings that specify a context before those
that don't.

The terminal module registers passthrough commands for all the key
combination xterm.js recognizes right now:

  https://github.com/xtermjs/xterm.js/blob/v3/src/Terminal.ts#L1684

Some improvements should be made for Mac though.  To match xterm.js'
behavior, the alt-<key> combinations should only be registered on
non-Mac computers, but I don't know how to do that.  Also, I suppose
that on Mac, the ctrl-<key> bindings should be registered with the M4
modifier?  Finally, there's the cmd-A shortcut registered specifically
for Mac.  It would be nice if somebody that has access to a Mac could
improve that.

Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
@simark
Copy link
Contributor

simark commented Nov 27, 2017

Fixed by #887.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
terminal issues related to the terminal
Projects
None yet
Development

No branches or pull requests

6 participants