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-C doesn't work in Windows when in raw mode #822

Closed
bitspittle opened this issue Jan 31, 2023 · 3 comments · Fixed by #834
Closed

Ctrl-C doesn't work in Windows when in raw mode #822

bitspittle opened this issue Jan 31, 2023 · 3 comments · Fixed by #834
Labels
Milestone

Comments

@bitspittle
Copy link

bitspittle commented Jan 31, 2023

When using jline3 on Unix, I can use ctrl-C to exit my application. But I noticed it wasn't working on Windows, so I tried to dig in a bit.

I'm slightly worried this is report is user error, that maybe I'm doing something wrong without realizing it, but I'll file this repro case just in case.

Repro steps

  • Make sure jansi-1.18.jar is bundled in your final jar, for Windows support
    • (I tested this with jna as well and this also happened with jna)
  • Run the following code on Windows 10 (written in Kotlin but shouldn't be hard to write in Java if necessary)
val terminal = TerminalBuilder.builder()
    .system(true)
    .jansi(true).jna(false) // Important: jansi-1.18.jar required
    .dumb(false)
    .build()

terminal.enterRawMode()

terminal.writer().println("Type characters, which will be echoed to the terminal. Q will also exit this example.")
terminal.writer().println()
terminal.writer().flush()

while (true) {
    val c = terminal.reader().read(16)
    if (c >= 0) {
        terminal.writer().write(c)
        terminal.writer().flush()

        // Use "q" to quit early, since otherwise this can't be easily exited on windows
        if (c == 81 || c == 113) break
    } else {
        if (c == -1) break // Got EOF
    }
}

terminal.close()
  • While running, type some characters (except q, which will quit the program) to ensure it's working
  • Press Ctrl-C

Expected: The program terminates, having been interrupted
Actual: Nothing, the program continues uninterrupted.

Side Note 1: I tried this with jna and also with nativeSignals(true) set. Neither changed the outcome.

Side Note 2: If you comment out enterRawMode then windows will show a "Terminate Batch Job (Y/N)" question when you press Ctrl-C. And otherwise the non-raw-mode experience on Windows seems to work fine. But commenting out "enterRawMode" on Linux totally breaks the experience, causing duplicate text to show up when you press ENTER.


To solve this problem in my own code, I'm thinking of a few choices:

  • There's simply a bug here, which will get fixed in a future version of JLine3, and if so I could wait for it
  • I should register my own interrupt handler, but I'm still looking for sample code around how to do that. It scares me a little to override that behavior without knowing what I'm doing.
  • I should check for Windows mode. If Windows, don't enter raw mode. I'm a little nervous about this -- does this approach hold across other versions of Windows?

so if there's any advice anyone could share here, that would be appreciated.

@bitspittle
Copy link
Author

Not sure if this is the right way, but the way I'm handling this for now is:

terminal.enterRawMode()
terminal.handle(Signal.INT) { exitProcess(130) } // 130 == 128+2, where 2 == SIGINT

No idea if this is the wrong way but it seems to be working for now, until I know if there's a better solution.

@gnodet
Copy link
Member

gnodet commented Mar 2, 2023

There is most probably a bug in JLine.

The Ctrl+C behaviour on windows is controlled using the ENABLE_PROCESSED_INPUT flag of the console mode, see https://learn.microsoft.com/en-us/windows/console/ctrl-c-and-ctrl-break-signals.
However, JLine's windows terminal does not set it when updating attributes, meaning that the first time the setAttributes is called, the ENABLE_PROCESSED_INPUT will be removed from the console mode. This happens when calling enterRawMode(), which explains the behaviour you see.

I'll try to investigate a fix.

@gnodet gnodet added the bug label Mar 2, 2023
@bitspittle
Copy link
Author

Thanks for the explanation!

Since I have a workaround, it's not urgent on my end. However, if you are able to get a fix in, I'll update my dependency and remove the workaround.

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

Successfully merging a pull request may close this issue.

2 participants