From 1892f0421135ed3c1dad675ceadfbbbcdc1f1520 Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Tue, 6 Oct 2020 13:17:12 -0700 Subject: [PATCH] Fix ctrl+c handling on windows In windows, it is necessary for the console mode to include the ENABLE_PROCESS_INPUT flag in order for ctrl+c to be treated as a signal rather than a character. In jline 2, the ENABLE_PROCESS_INPUT flag was preserved whenever the console mode was changed but in jline 3, it was not. It is easy enough to manually set the flag after entering and exiting raw mode and setting attributes (which are the apis that change the console mode on windows). --- .../src/main/scala/sbt/internal/util/JLine3.scala | 10 +++++++++- .../src/main/scala/sbt/internal/util/Terminal.scala | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala b/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala index 0b15d4dae..63784d148 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala @@ -23,6 +23,7 @@ import org.jline.utils.OSUtils import scala.collection.JavaConverters._ import scala.util.Try import java.util.concurrent.LinkedBlockingQueue +import org.fusesource.jansi.internal.WindowsSupport private[sbt] object JLine3 { private[util] val initialAttributes = new AtomicReference[Attributes] @@ -207,6 +208,12 @@ private[sbt] object JLine3 { term.setAttributes(newAttr) prvAttr } + // We need to set the ENABLE_PROCESS_INPUT flag for ctrl+c to be treated as a signal in windows + // https://docs.microsoft.com/en-us/windows/console/setconsolemode + private[this] val ENABLE_PROCESS_INPUT = 1 + private[util] def setEnableProcessInput(): Unit = if (Util.isWindows) { + WindowsSupport.setConsoleMode(WindowsSupport.getConsoleMode | ENABLE_PROCESS_INPUT) + } private[util] def enterRawMode(term: JTerminal): Unit = { val prevAttr = initialAttributes.get val newAttr = new Attributes(prevAttr) @@ -215,13 +222,14 @@ private[sbt] object JLine3 { newAttr.setLocalFlags(EnumSet.of(LocalFlag.ICANON, LocalFlag.IEXTEN, LocalFlag.ECHO), false) newAttr.setInputFlags(EnumSet.of(InputFlag.IXON, InputFlag.ICRNL, InputFlag.INLCR), false) term.setAttributes(newAttr) - () + setEnableProcessInput() } private[util] def exitRawMode(term: JTerminal): Unit = { val initAttr = initialAttributes.get val newAttr = new Attributes(initAttr) newAttr.setLocalFlags(EnumSet.of(LocalFlag.ICANON, LocalFlag.ECHO), true) term.setAttributes(newAttr) + setEnableProcessInput() } private[util] def toMap(jattributes: Attributes): Map[String, String] = { val result = new java.util.LinkedHashMap[String, String] diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala b/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala index a62bb50bb..839e41617 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala @@ -814,6 +814,7 @@ object Terminal { Try(JLine3.toMap(system.getAttributes)).getOrElse(Map.empty) override private[sbt] def setAttributes(attributes: Map[String, String]): Unit = { system.setAttributes(JLine3.attributesFromMap(attributes)) + JLine3.setEnableProcessInput() } override private[sbt] def setSize(width: Int, height: Int): Unit = system.setSize(new org.jline.terminal.Size(width, height))