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

Not able to stop control+M from being an Enter #633

Closed
wags-1314 opened this issue Feb 22, 2022 · 6 comments
Closed

Not able to stop control+M from being an Enter #633

wags-1314 opened this issue Feb 22, 2022 · 6 comments

Comments

@wags-1314
Copy link

I am using crossterm to make a text editor of sorts. I am switching into raw mode and simply echoing the keypresses. Here is my code:

use std::time::Duration;

use crossterm::{
    event::{poll, read, KeyCode::Char, KeyEvent, KeyModifiers},
    terminal, Result,
};

fn print_events() -> Result<bool> {
    loop {
        if poll(Duration::from_millis(100))? {
            let ev = read()?;
            print!("{:?}\r\n", &ev);
            match ev {
                crossterm::event::Event::Key(KeyEvent {
                    code: Char(ch @ 'q'),
                    modifiers: KeyModifiers::CONTROL,
                }) => { print!("cntrl{{{}}}\r\n", ch); break; },
                crossterm::event::Event::Key(KeyEvent {
                    code: Char(ch),
                    modifiers: KeyModifiers::CONTROL,
                }) => print!("cntrl{{{}}}\r\n", ch),
                crossterm::event::Event::Key(KeyEvent {
                    code: Char(ch),
                    modifiers: KeyModifiers::ALT,
                }) => print!("{}\r\n", ch),
                crossterm::event::Event::Key(KeyEvent {
                    code: Char(ch),
                    modifiers: _,
                }) => print!("{} ({})\r\n", ch, ch as u8),
                _ => break,
            };

            print!("\r\n");
        }
    }

    Ok(true)
}

fn main() -> Result<()> {
    terminal::enable_raw_mode()?;
    print_events()?;
    terminal::disable_raw_mode()?;
    Ok(())
}

When I enter control+M I get Key(KeyEvent { code: Enter, modifiers: NONE }) instead of Key(KeyEvent { code: Char('m'), modifiers: CONTROL }). How do I make this happen?

@TimonPost
Copy link
Member

TimonPost commented Feb 22, 2022

What platform and terminal?

@markus-bauer
Copy link

I noticed this also. I'm using Ubuntu 21.10. It's not terminal dependent (same results in xterm, kitty, gnome-terminal, urxvt). Here are some results (I would like someone else to also test this):

Ctrl+m: KeyEvent { code: Enter,     modifiers: NONE }
Ctrl+c: KeyEvent { code: Char('c'), modifiers: CONTROL }
Ctrl+j: KeyEvent { code: Char('j'), modifiers: CONTROL }

Ctrl+1: KeyEvent { code: Char('1'), modifiers: NONE }
Ctrl+2: KeyEvent { code: Char(' '), modifiers: CONTROL }
Ctrl+3: KeyEvent { code: Esc,       modifiers: NONE }
Ctrl+4: KeyEvent { code: Char('4'), modifiers: CONTROL }
Ctrl+5: KeyEvent { code: Char('5'), modifiers: CONTROL }
Ctrl+6: KeyEvent { code: Char('6'), modifiers: CONTROL }
Ctrl+7: KeyEvent { code: Char('7'), modifiers: CONTROL }
Ctrl+8: KeyEvent { code: Backspace, modifiers: NONE }
Ctrl+9: KeyEvent { code: Char('9'), modifiers: NONE }
Ctrl+0: KeyEvent { code: Char('0'), modifiers: NONE }

I don't know much about terminals. My first reaction was, that it is related to ascii control codes (https://en.wikipedia.org/wiki/Control_character).

This also happens in any terminal application I tested, like ranger or vim. Try pressing Ctrl+M (Return) or Ctrl+8 (Backspace) in vim.

I was confused why Ctrl+m doesn't work, but Ctrl+j or Ctrl+c does. It might be related to: #371.
If I understand it correctly, this was fixed by ignoring /n in raw_mode.

// Issue #371: \n = 0xA, which is also the keycode for Ctrl+J. The only reason we get

@sharnoff
Copy link
Contributor

FWIW, I had originally fixed the Ctrl+J issue with #373. There's some information in the PR, as well as this link, which you may find particularly relevant, @wags-1314.

The basic problem is this:

The way that characters are encoded in terminal emulators means that Ctrl+J and '\n' are the same character -- it is not possible to distinguish them. AFAICT, the fix for #371 was just to reinterpret the byte sequence for '\n' as Ctrl+J, when we're in raw mode.

For Ctrl+J, this makes sense -- raw mode actually means that anything that would be a newline (i.e. enter) gets reported as such, so anything with the byte sequence for Ctrl+J must actually be Ctrl+J.

But for Ctrl+M, there isn't such a distinction. It is exactly the same as Enter -- that's why there aren't any terminal programs that are able to distinguish them.

So I don't know what crossterm should do. IMO, this behavior is the best it can be - (people more often want to check for Enter, not Ctrl+M, I think).

Also relevant: #569 - which IIRC would provide a way around this, for users of the kitty terminal.

@markus-bauer
Copy link

Related: #594
The kitty protocol is based on this (https://www.leonerd.org.uk/hacks/fixterms/):
https://sw.kovidgoyal.net/kitty/keyboard-protocol/

@stevenxxiu
Copy link

stevenxxiu commented Jun 19, 2022

WezTerm also supports Fix Terminals - Please.

@TimonPost
Copy link
Member

Closing in favor of #685.

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

5 participants