diff --git a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/win/JansiWinSysTerminal.java b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/win/JansiWinSysTerminal.java index b59c32dbd..f9b903450 100644 --- a/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/win/JansiWinSysTerminal.java +++ b/terminal-jansi/src/main/java/org/jline/terminal/impl/jansi/win/JansiWinSysTerminal.java @@ -11,6 +11,7 @@ import java.io.BufferedWriter; import java.io.IOError; import java.io.IOException; +import java.io.Writer; import java.nio.charset.Charset; import java.util.function.IntConsumer; @@ -23,6 +24,7 @@ import org.jline.terminal.Size; import org.jline.terminal.impl.AbstractWindowsTerminal; import org.jline.utils.InfoCmp; +import org.jline.utils.Log; import static org.fusesource.jansi.internal.Kernel32.GetConsoleScreenBufferInfo; import static org.fusesource.jansi.internal.Kernel32.GetStdHandle; @@ -30,18 +32,37 @@ public class JansiWinSysTerminal extends AbstractWindowsTerminal { + private static final int ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004; + public JansiWinSysTerminal(String name, boolean nativeSignals) throws IOException { this(name, null, 0, nativeSignals, SignalHandler.SIG_DFL); } public JansiWinSysTerminal(String name, Charset encoding, int codepage, boolean nativeSignals, SignalHandler signalHandler) throws IOException { - super(new WindowsAnsiWriter(new BufferedWriter(new JansiWinConsoleWriter())), + super(createAnsiWriter(new BufferedWriter(new JansiWinConsoleWriter())), name, encoding, codepage, nativeSignals, signalHandler); // Start input pump thread pump.start(); } + private static Writer createAnsiWriter(Writer writer) throws IOException { + long console = GetStdHandle(STD_OUTPUT_HANDLE); + + int[] mode = new int[1]; + if (Kernel32.GetConsoleMode(console, mode) == 0) { + throw new IOException("Failed to get console mode: " + WindowsSupport.getLastErrorMessage()); + } + + if (Kernel32.SetConsoleMode(console, mode[0] | ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0) { + return writer; + } + + Log.debug("Unable to enable virtual terminal processing, using AnsiWriter instead: " + WindowsSupport.getLastErrorMessage()); + return new WindowsAnsiWriter(writer); + } + + @Override protected int getConsoleOutputCP() { return Kernel32.GetConsoleOutputCP(); diff --git a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java index eacf3ea97..a08b7ffad 100644 --- a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java +++ b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/win/JnaWinSysTerminal.java @@ -10,15 +10,18 @@ import java.io.BufferedWriter; import java.io.IOException; +import java.io.Writer; import java.nio.charset.Charset; import java.util.function.IntConsumer; +import com.sun.jna.LastErrorException; import com.sun.jna.Pointer; import com.sun.jna.ptr.IntByReference; import org.jline.terminal.Cursor; import org.jline.terminal.Size; import org.jline.terminal.impl.AbstractWindowsTerminal; import org.jline.utils.InfoCmp; +import org.jline.utils.Log; public class JnaWinSysTerminal extends AbstractWindowsTerminal { @@ -30,7 +33,7 @@ public JnaWinSysTerminal(String name, boolean nativeSignals) throws IOException } public JnaWinSysTerminal(String name, Charset encoding, int codepage, boolean nativeSignals, SignalHandler signalHandler) throws IOException { - super(new WindowsAnsiWriter(new BufferedWriter(new JnaWinConsoleWriter(consoleOut)), consoleOut), + super(createAnsiWriter(new BufferedWriter(new JnaWinConsoleWriter(consoleOut))), name, encoding, codepage, nativeSignals, signalHandler); strings.put(InfoCmp.Capability.key_mouse, "\\E[M"); @@ -38,6 +41,20 @@ public JnaWinSysTerminal(String name, Charset encoding, int codepage, boolean na pump.start(); } + private static Writer createAnsiWriter(Writer writer) throws IOException { + IntByReference mode = new IntByReference(); + Kernel32.INSTANCE.GetConsoleMode(consoleOut, mode); + + try { + Kernel32.INSTANCE.SetConsoleMode(consoleOut, mode.getValue() | Kernel32.ENABLE_VIRTUAL_TERMINAL_PROCESSING); + return writer; + } catch (LastErrorException e) { + Log.debug("Unable to enable virtual terminal processing, using AnsiWriter instead", e); + } + + return new WindowsAnsiWriter(writer, consoleOut); + } + @Override protected int getConsoleOutputCP() { return Kernel32.INSTANCE.GetConsoleOutputCP(); diff --git a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/win/Kernel32.java b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/win/Kernel32.java index b893a9244..c62903419 100644 --- a/terminal-jna/src/main/java/org/jline/terminal/impl/jna/win/Kernel32.java +++ b/terminal-jna/src/main/java/org/jline/terminal/impl/jna/win/Kernel32.java @@ -27,6 +27,7 @@ interface Kernel32 extends StdCallLibrary { int STD_OUTPUT_HANDLE = -11; int STD_ERROR_HANDLE = -12; + // Input modes int ENABLE_PROCESSED_INPUT = 0x0001; int ENABLE_LINE_INPUT = 0x0002; int ENABLE_ECHO_INPUT = 0x0004; @@ -36,6 +37,9 @@ interface Kernel32 extends StdCallLibrary { int ENABLE_QUICK_EDIT_MODE = 0x0040; int ENABLE_EXTENDED_FLAGS = 0x0080; + // Output modes + int ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004; + int RIGHT_ALT_PRESSED = 0x0001; int LEFT_ALT_PRESSED = 0x0002; int RIGHT_CTRL_PRESSED = 0x0004;