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

Handle a "modifier+bare key" key combination #151

Open
hcpl opened this issue Aug 22, 2017 · 9 comments
Open

Handle a "modifier+bare key" key combination #151

hcpl opened this issue Aug 22, 2017 · 9 comments

Comments

@hcpl
Copy link
Contributor

hcpl commented Aug 22, 2017

Description

Cannot process a "modifier+bare key" key combination, only a "bare key".

Configuration

$ uname -srm
Linux 4.2.0-42-generic x86_64
$ rustc --version
rustc 1.18.0 (03fc9d622 2017-06-06)
$ gnome-terminal --version
GNOME Terminal 3.6.2

Cursive version 0.6.4, the issue is relevant to all backends except BearLibTerminal which I didn't test.

Expected behaviour

Print on the upper-left corner:

  • ctrl+enter on Ctrl+Enter;
  • shift+enter on Shift+Enter;
  • alt+enter on Alt+Enter.

Actual behaviour

Nothing happens.

Code to reproduce

extern crate cursive;

use cursive::{Cursive, Printer};
use cursive::event::{Event, EventResult, Key};
use cursive::vec::Vec2;
use cursive::view::View;


struct Foo {
    info: &'static str,
}

impl View for Foo {
    fn draw(&self, printer: &Printer) {
        printer.print((0, 0), self.info);
    }

    fn required_size(&mut self, constraint: Vec2) -> Vec2 {
        Vec2::from((self.info.len(), 1)).or_min(constraint)
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        self.info = match event {
            //Event::Key(Key::Enter) => "enter",
            Event::Ctrl(Key::Enter) => "ctrl+enter",
            Event::Shift(Key::Enter) => "shift+enter",
            Event::Alt(Key::Enter) => "alt+enter",
            _ => return EventResult::Ignored,
        };

        EventResult::Consumed(None)
    }
}


fn main() {
    let mut siv = Cursive::new();
    siv.add_fullscreen_layer(Foo { info: "" });
    siv.run();
}

P.S. If the Event::Key(Key::Enter) => "enter" part is uncommented, the program will print enter for all 4 cases.

UPD: Add gnome-terminal as the terminal used and its version.

@hcpl hcpl changed the title Document key events' priority Handle a "modifier+bare key" key combination Aug 22, 2017
@gyscos
Copy link
Owner

gyscos commented Aug 23, 2017

Hi, and thanks for the report!

The "Enter" key is a special one, and isn't very well supported with modifier keys - terminals just don't send the complete information to the application. Ctrl-Enter and Shift-Enter are just sent as simple Enter event; though Alt+Enter should be detectable with some modification to the input system. If you try with another key, like Home, it should work better.

Now, there seems to be some problem detecting this modifier. Apparently Ctrl-Home is detected as Ctrl-Shift-Home, and some other confusion, so I'll need to have a look at that part. :S

As a note, you can use the key_codes example to see the event generated by a key press.

@hcpl
Copy link
Contributor Author

hcpl commented Aug 23, 2017

Oh, I missed the example, thanks for pointing out.

Since ncurses does not support new features of modern terminals I already knew that keyboard handling is messy, but I never thought it's that messy. So I came up with a table:

No modifiers Shift Ctrl Alt Ctrl+Shift Ctrl+Alt Alt+Shift Ctrl+Alt+Shift
Enter Key(Enter) Key(Enter) Key(Enter) Key(Esc) Key(Enter) Key(Enter) Key(Esc) Key(Enter) Key(Esc) Key(Enter) Key(Esc) Key(Enter)
Home Key(Home) Nothing Key(Home) Key(Home) Nothing Key(Home) Nothing Nothing
End Key(End) Nothing Key(End) Key(End) Nothing Key(End) Nothing Nothing
PageUp Key(PageUp) Nothing CtrlAlt(PageDown) Ctrl(PageDown) Nothing AltShift(PageUp) Nothing Nothing
PageDown Key(PageDown) Nothing CtrlAlt(Left) Ctrl(Left) Nothing AltShift(PageDown) Nothing Nothing
Left Key(Left) Shift(Left) CtrlAlt(Ins) Ctrl(Ins) Alt(Left) AltShift(Left) Unknown([31, 2, 0, 0]) Key(Esc) Char('[') Char('1') Char(';') Char('8') Char('D')
Right Key(Right) Shift(Right) CtrlAlt(PageUp) Ctrl(PageUp) Alt(Right) AltShift(Right) CtrlShift(PageUp) Key(Esc) Char('[') Char('1') Char(';') Char('8') Char('C')
Up Key(Up) Shift(Up) Unknown([53, 2, 0, 0]) CtrlShift(Right) Nothing AltShift(Up) CtrlAlt(Right) Nothing
Down Key(Down) Shift(Down) Unknown([12, 2, 0, 0]) CtrlShift(Del) Nothing AltShift(Down) Unknown([11, 2, 0, 0]) Nothing

This shows that there are many cases where one modifier set is recognized as another one, some send an escape sequence, some are not recognized by Cursive and others are trapped entirely, though I don't know what exactly in keyboard OS event chain should be blamed for trapping.

Also your observation

Apparently Ctrl-Home is detected as Ctrl-Shift-Home

contradicts with mine: it's detected as plain Home. I think that's because of difference in keyboard layouts, either (or even both) in hardware and in software (I am using i3wm with modifier key bound on Alt but to fill this table I temporarily switched it off).

@gyscos
Copy link
Owner

gyscos commented Aug 23, 2017

Another note: the terminal used has a large impact on the events actually delivered to the application.

I just pushed a1737ca, which at least fixes most modifier+key input on my computer for the ncurses backend. I tested it locally with gnome-terminal and konsole. Not all key combinations work on both, but I didn't see any Unknown or mislabeled event (except for Ctrl+Shift+Alt+Key, those are a bit trickier for now). If this work for you, I'll update the pancurses backend to work the same.

If this doesn't work for you, then it means the key codes are different between multiple systems (could be terminfo version, terminal used, ...), which would be a bit of a pain...

Notes:

  • As said above, modifiers + Enter rarely work.
  • Shift+Insert actually pastes the clipboard content in many applications. That said, Konsole at least can properly detect Alt+Shift+Insert. Gnome-terminal doesn't.
  • PageUp/Down is often used for scrolling/changing tabs, especially with modifiers. On gnome-terminal, only Ctrl+Shift+PageUp/Down does not work. On konsole, in addition, Shift+PageUp/Down and Alt+Shift+PageUp/Down do not work.

For these reasons, I used to have in the Readme a compatibility table of the events available on various terminals, but it ended up being out-of-date, it depended on the backend used, and was overall too much work to maintain.

@hcpl
Copy link
Contributor Author

hcpl commented Aug 23, 2017

Yeah, I only tested on gnome-terminal. I also have xterm and urxvt installed, so I'll test your commit against them too.

@gyscos
Copy link
Owner

gyscos commented Nov 20, 2017

After realizing that the actual key <=> code mapping was changing between ncurses versions, I understood hard-coding this table wasn't going anywhere. So now it should detect this mapping at runtime. This include the (Alt, AltShift, Ctrl, CtrlShift and CtrlAlt) modifiers, for the (Del, Insert, Home, End, PageUp/Down` and the arrow keys).

@mx-shift
Copy link

mx-shift commented Jan 9, 2018

I'm seeing incorrect mapping with macOS Terminal and the default backend. For example, Alt(Left) appears to be an escape code of Key(Esc) Char('b'). When I get some time, I'll dig into the code to see what can be done.

@ghost
Copy link

ghost commented Feb 3, 2018

What's the future of this task?
Is it doable?

@gyscos
Copy link
Owner

gyscos commented Feb 19, 2018

TLDR: Shift+Enter and Ctrl+Enter are probably impossible to differentiate from Enter, because the terminal sends the same code to the application.

Input encoding depends on the terminal used, and those can vary a lot. Recognizing the encoding scheme and parsing the input appropriately is a huge task, and ncurses is supposed to do exactly that. As much as possible, I'd like to leave most of the $TERM-dependent work to the backend library (or, if needed, the backend module).

That being said, parsing the output from ncurses itself isn't always trivial; many key codes are correctly parsed, but the returned code isn't documented, and the actual value depends on the ncurses version. This is what can be improved here - for instance, confusing CtrlAlt(Ins) and Ctrl(Left) results from wrongly parsing ncurses' own output, and should be correctable. Receiving Key(Esc) and Char('b') instead of Alt(Left) means ncurses is not parsing the escape sequence for this particular terminal, and is trickier to fix here.

Regarding macOS compatibility, I don't have a machine to test; #206 may be of interest.

Regarding variations for the Enter key, most terminals simply send the same code even if Shift or Ctrl is pressed, so cursive cannot tell the difference.

As for the termion backend, it doesn't currently check the current terminal, but there's an issue for that (https://github.com/ticki/termion/issues/106).

@massimo79m
Copy link

Same behaviour on macos terminal. i need the ctrl-enter but it does not work.

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

No branches or pull requests

4 participants