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

Ctrl-Z does not work in Windows #19914

Closed
lifthrasiir opened this issue Dec 16, 2014 · 14 comments
Closed

Ctrl-Z does not work in Windows #19914

lifthrasiir opened this issue Dec 16, 2014 · 14 comments
Labels
E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. O-windows Operating system: Windows

Comments

@lifthrasiir
Copy link
Contributor

fn main() {
    for l in std::io::stdin().lock().lines() { println!("{}", l.map(|s| s.escape_unicode())); }
}

As of rustc 0.13.0-nightly (126db549b 2014-12-15 00:07:35 +0000) this does not work: pressing Ctrl-Z then Return (a standard EOF sequence in Windows) simply prints Ok(\x1a\x0d\x0a), and pressing Ctrl-C immediately terminates the process while printing a panic! message.

This is apparently a regression of #3948. According to the relevant code from CPython, ReadConsoleW may return an error ERROR_OPERATION_ABORTED in both cases, and msvcrt (I think) will additionally issue a SIGINT for Ctrl-C within milliseconds. The current code handles none of them.

@kmcallister kmcallister added the O-windows Operating system: Windows label Dec 19, 2014
@blindley
Copy link

I ran into this issue as well. Although lifthrasiir's code does not compile for me in the current version (rustc 1.0.0-nightly (f4f10dba2 2015-01-17 20:31:08 +0000)), I used this code instead.

fn main() {
    for line in std::io::stdin().lock().lines() {
        match line {
            Ok(line) => println!("{:?}", line.as_bytes()),
            Err(e) => panic!("{}", e),
        }
    }
}

@steveklabnik
Copy link
Member

Triage: i do not have access to Windows to test this, but here's updated code that compiles:

use std::io::BufRead;

fn main() {
    let stdin = std::io::stdin();
    for line in stdin.lock().lines() {
        match line {
            Ok(line) => println!("{:?}", line.as_bytes()),
            Err(e) => panic!("{}", e),
        }
    }
}

@shepmaster
Copy link
Member

i do not have access to Windows

I use a modern.ie VM.

c:\rust\ctrlzed>cargo run
     Running `target\debug\ctrlzed.exe`
^Z
[26]
^C
c:\rust\ctrlzed>

That is, control-Z followed by enter does not terminate the program, but prints out [26]. Control-C terminates the program without a panic.

@alexcrichton
Copy link
Member

This should be a pretty easy bug to knock out, so marking as E-easy and E-mentor as I'm willing to mentor it.

This'll involve poking around src/libstd/sys/windows/stdio.rs and looking specifically at the call to ReadConsole. The usage of try! there will likely need to be eschewed in favor of manually checking the Result returned from cvt.

I'm unfortunately not sure of a great way to add an automated test for this, but manual testing should work just fine!

@alexcrichton alexcrichton added E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. labels Jan 11, 2016
@Xinayder
Copy link
Contributor

Can I pick this up?

@alexcrichton
Copy link
Member

@RockyTV sure! Just let me know if you need any help!

@Xinayder
Copy link
Contributor

@alexcrichton I started working on this today, and I'm not sure what to do. I'd like to know what should I do if I remove the try! call: should I use a match, and if so, what do I do with the value of Some? Do I assign it to a variable, or do I call another function?

@alexcrichton
Copy link
Member

Yeah you'll probably want to remove this try! and then match the result explicitly, checking the error and taking appropriate action depending on what it says

@pravic
Copy link
Contributor

pravic commented Apr 6, 2016

As I understand, there are two problems here: CTRL+Z and CTRL+C.

On CTRL+C ReadConsole returns TRUE with empty buffer and with last error ERROR_OPERATION_ABORTED (source). So, it can be handled easily here.

CTRL+Z on Windows works like CTRL+D on Unix, but Windows console functions doesn't handle it.

ReadFile (which can read from console too actually) has naive checking just for the first character of readed buffer about CTRLZ, but it doesnt know anything about line endings.

fgets treats CTRLZ as EOF when it found at start of line and this is default behavior for windows programs.

Thus, Rust must handle CTRLZ at some higher level, when processing the lines, I think.

Any thoughts?

@pravic
Copy link
Contributor

pravic commented Apr 6, 2016

cc @retep998

@retep998
Copy link
Member

retep998 commented Apr 6, 2016

ReadFile suffers from doing the read in the current narrow code page which is almost never what you want (and especially does not work when using a multi byte encoding and it encounters a multi byte sequence).

Ctrl + C should simply invoke the current console ctrl handler, whatever it is, which by default terminates the process, although it can be configured via SetConsoleCtrlHandler.

I don't have any strong opinions on what we should do for Ctrl + Z.

nabijaczleweli added a commit to nabijaczleweli/mcp-mapping-transposer that referenced this issue Apr 7, 2016
Need to check for Ctrl+D explicitly because of
rust-lang/rust#19914
nabijaczleweli added a commit to nabijaczleweli/mcp-mapping-transposer that referenced this issue Apr 7, 2016
Need to check for Ctrl+D explicitly because of
rust-lang/rust#19914
@brson brson removed the E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. label Jun 27, 2016
@brson
Copy link
Contributor

brson commented Jun 27, 2016

I removed the easy tag since there appear to be outstanding questions about what to do here.

elahn added a commit to elahn/rust that referenced this issue Dec 9, 2016
Windows.
Fixes rust-lang#19914.
Fixes read(), read_to_string(), read_to_end(), etc.
bors added a commit that referenced this issue Dec 26, 2016
Ctrl-Z returns from Stdin.read() when reading from the console on Windows

Fixes #19914.
Fixes read(), read_to_string(), read_to_end(), etc.

r? @alexcrichton
@elahn
Copy link
Contributor

elahn commented Dec 27, 2016

Fixed in #38274 when running from native Windows (cmd/PowerShell/etc).

When running a Windows exe from Mintty (MSYS/Cygwin TTY), stdin & stdout are piped from/to Mintty. ReadFile() is used to read the stdin pipe and there seems to be no way to detect EOF, i.e. it doesn't return zero bytes when the user presses Ctrl+D.

This is a known issue in Mintty. User workaround: $ winpty app.exe

Since winpty solves it, it's obviously possible. It would involve detecting Mintty, setting raw terminal mode and parsing the input. Alternatively, this post refers to hacks in git and ruby, but I don't understand what's happening there.

Should implement this? If so, I'm happy to help with implementing and testing it on Windows, but I'll need a C guru to hold my hand.

@alexcrichton
Copy link
Member

@elahn I'm not 100% privvy to all the issues in play here but if the handling code is reasonably small enough seems fine to put in the standard library. If it becomes quite large, however, or invasive, then we may wish to punt those issues to an external crate for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
E-mentor Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion. O-windows Operating system: Windows
Projects
None yet
Development

No branches or pull requests