Tweaked input console setting for windows
This commit is contained in:
parent
f190a31c39
commit
aca4c493b0
@ -20,7 +20,7 @@ import java.io.IOException;
|
|||||||
public abstract
|
public abstract
|
||||||
class Terminal {
|
class Terminal {
|
||||||
|
|
||||||
public static final String CONSOLE_ERROR_INIT = "Unable to get input console mode.";
|
public static final String CONSOLE_ERROR_INIT = "Unable to initialize the input console.";
|
||||||
protected static final int DEFAULT_WIDTH = 80;
|
protected static final int DEFAULT_WIDTH = 80;
|
||||||
protected static final int DEFAULT_HEIGHT = 24;
|
protected static final int DEFAULT_HEIGHT = 24;
|
||||||
protected final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
|
protected final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());
|
||||||
@ -38,6 +38,7 @@ class Terminal {
|
|||||||
public abstract
|
public abstract
|
||||||
int getHeight();
|
int getHeight();
|
||||||
|
|
||||||
|
// NOT THREAD SAFE
|
||||||
public abstract
|
public abstract
|
||||||
void setEchoEnabled(final boolean enabled);
|
void setEchoEnabled(final boolean enabled);
|
||||||
|
|
||||||
|
@ -11,16 +11,21 @@
|
|||||||
*/
|
*/
|
||||||
package dorkbox.console.input;
|
package dorkbox.console.input;
|
||||||
|
|
||||||
|
import static dorkbox.console.util.windows.Kernel32.ASSERT;
|
||||||
|
import static dorkbox.console.util.windows.Kernel32.CloseHandle;
|
||||||
|
import static dorkbox.console.util.windows.Kernel32.GetConsoleMode;
|
||||||
import static dorkbox.console.util.windows.Kernel32.GetConsoleScreenBufferInfo;
|
import static dorkbox.console.util.windows.Kernel32.GetConsoleScreenBufferInfo;
|
||||||
|
import static dorkbox.console.util.windows.Kernel32.GetStdHandle;
|
||||||
import static dorkbox.console.util.windows.Kernel32.STD_INPUT_HANDLE;
|
import static dorkbox.console.util.windows.Kernel32.STD_INPUT_HANDLE;
|
||||||
import static dorkbox.console.util.windows.Kernel32.STD_OUTPUT_HANDLE;
|
import static dorkbox.console.util.windows.Kernel32.STD_OUTPUT_HANDLE;
|
||||||
|
import static dorkbox.console.util.windows.Kernel32.SetConsoleMode;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
|
||||||
import com.sun.jna.ptr.IntByReference;
|
import com.sun.jna.ptr.IntByReference;
|
||||||
|
|
||||||
import dorkbox.console.util.windows.CONSOLE_SCREEN_BUFFER_INFO;
|
import dorkbox.console.util.windows.CONSOLE_SCREEN_BUFFER_INFO;
|
||||||
import dorkbox.console.util.windows.ConsoleMode;
|
|
||||||
import dorkbox.console.util.windows.HANDLE;
|
import dorkbox.console.util.windows.HANDLE;
|
||||||
import dorkbox.console.util.windows.INPUT_RECORD;
|
import dorkbox.console.util.windows.INPUT_RECORD;
|
||||||
import dorkbox.console.util.windows.KEY_EVENT_RECORD;
|
import dorkbox.console.util.windows.KEY_EVENT_RECORD;
|
||||||
@ -32,6 +37,24 @@ import dorkbox.console.util.windows.Kernel32;
|
|||||||
public
|
public
|
||||||
class WindowsTerminal extends Terminal {
|
class WindowsTerminal extends Terminal {
|
||||||
|
|
||||||
|
// Console mode constants copied <tt>wincon.h</tt>.
|
||||||
|
// There are OTHER options, however they DO NOT work with unbuffered input or we just don't care about them.
|
||||||
|
/**
|
||||||
|
* CTRL+C is processed by the system and is not placed in the input buffer. If the input buffer is being read by ReadFile or
|
||||||
|
* ReadConsole, other control keys are processed by the system and are not returned in the ReadFile or ReadConsole buffer. If the
|
||||||
|
* ENABLE_LINE_INPUT mode is also enabled, backspace, carriage return, and linefeed characters are handled by the system.
|
||||||
|
*/
|
||||||
|
private static final int PROCESSED_INPUT = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ReadFile or ReadConsole function returns only when a carriage return character is read. If this mode is disable, the functions
|
||||||
|
* return when one or more characters are available.
|
||||||
|
*/
|
||||||
|
private static final int ENABLE_LINE_INPUT = 2;
|
||||||
|
|
||||||
|
// output stream for "echo" to goto
|
||||||
|
private static final PrintStream OUT = System.out;
|
||||||
|
|
||||||
private final HANDLE console;
|
private final HANDLE console;
|
||||||
private final HANDLE outputConsole;
|
private final HANDLE outputConsole;
|
||||||
|
|
||||||
@ -40,37 +63,30 @@ class WindowsTerminal extends Terminal {
|
|||||||
private final IntByReference reference = new IntByReference();
|
private final IntByReference reference = new IntByReference();
|
||||||
|
|
||||||
private volatile int originalMode;
|
private volatile int originalMode;
|
||||||
|
private boolean echoEnabled = false;
|
||||||
|
|
||||||
public
|
public
|
||||||
WindowsTerminal() throws IOException {
|
WindowsTerminal() throws IOException {
|
||||||
console = Kernel32.GetStdHandle(STD_INPUT_HANDLE);
|
console = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
if (console == HANDLE.INVALID_HANDLE_VALUE) {
|
if (console == HANDLE.INVALID_HANDLE_VALUE) {
|
||||||
throw new IOException("Unable to get input console handle.");
|
throw new IOException("Unable to get input console handle.");
|
||||||
}
|
}
|
||||||
|
|
||||||
outputConsole = Kernel32.GetStdHandle(STD_OUTPUT_HANDLE);
|
outputConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
if (outputConsole == HANDLE.INVALID_HANDLE_VALUE) {
|
if (outputConsole == HANDLE.INVALID_HANDLE_VALUE) {
|
||||||
throw new IOException("Unable to get output console handle.");
|
throw new IOException("Unable to get output console handle.");
|
||||||
}
|
}
|
||||||
|
|
||||||
IntByReference mode = new IntByReference();
|
IntByReference mode = new IntByReference();
|
||||||
if (Kernel32.GetConsoleMode(console, mode) == 0) {
|
if (GetConsoleMode(console, mode) == 0) {
|
||||||
throw new IOException(CONSOLE_ERROR_INIT);
|
throw new IOException(CONSOLE_ERROR_INIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.originalMode = mode.getValue();
|
this.originalMode = mode.getValue();
|
||||||
|
|
||||||
int newMode = this.originalMode |
|
int newMode = 0; // this is raw everything, not ignoring ctrl-c
|
||||||
ConsoleMode.ENABLE_LINE_INPUT.code |
|
|
||||||
ConsoleMode.ENABLE_ECHO_INPUT.code |
|
|
||||||
ConsoleMode.ENABLE_PROCESSED_INPUT.code |
|
|
||||||
ConsoleMode.ENABLE_WINDOW_INPUT.code;
|
|
||||||
|
|
||||||
// Disable input echo
|
ASSERT(SetConsoleMode(console, newMode), Terminal.CONSOLE_ERROR_INIT);
|
||||||
newMode = newMode & ~ConsoleMode.ENABLE_ECHO_INPUT.code;
|
|
||||||
|
|
||||||
// Must set these four modes at the same time to make it work fine.
|
|
||||||
Kernel32.SetConsoleMode(console, newMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,11 +96,10 @@ class WindowsTerminal extends Terminal {
|
|||||||
@Override
|
@Override
|
||||||
public final
|
public final
|
||||||
void restore() throws IOException {
|
void restore() throws IOException {
|
||||||
// restore the old console mode
|
ASSERT(SetConsoleMode(console, this.originalMode), Terminal.CONSOLE_ERROR_INIT);
|
||||||
Kernel32.SetConsoleMode(console, this.originalMode);
|
|
||||||
|
|
||||||
Kernel32.CloseHandle(console);
|
CloseHandle(console);
|
||||||
Kernel32.CloseHandle(outputConsole);
|
CloseHandle(outputConsole);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -106,37 +121,26 @@ class WindowsTerminal extends Terminal {
|
|||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setEchoEnabled(final boolean enabled) {
|
void setEchoEnabled(final boolean enabled) {
|
||||||
IntByReference mode = new IntByReference();
|
// only way to do this, console modes DO NOT work
|
||||||
Kernel32.GetConsoleMode(console, mode);
|
echoEnabled = enabled;
|
||||||
|
|
||||||
int newMode;
|
|
||||||
if (enabled) {
|
|
||||||
// Enable Ctrl+C
|
|
||||||
newMode = mode.getValue() | ConsoleMode.ENABLE_ECHO_INPUT.code;
|
|
||||||
} else {
|
|
||||||
// Disable Ctrl+C
|
|
||||||
newMode = mode.getValue() & ~ConsoleMode.ENABLE_ECHO_INPUT.code;
|
|
||||||
}
|
|
||||||
|
|
||||||
Kernel32.SetConsoleMode(console, newMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public
|
public
|
||||||
void setInterruptEnabled(final boolean enabled) {
|
void setInterruptEnabled(final boolean enabled) {
|
||||||
IntByReference mode = new IntByReference();
|
IntByReference mode = new IntByReference();
|
||||||
Kernel32.GetConsoleMode(console, mode);
|
GetConsoleMode(console, mode);
|
||||||
|
|
||||||
int newMode;
|
int newMode;
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
// Enable Ctrl+C
|
// Enable Ctrl+C
|
||||||
newMode = mode.getValue() | ConsoleMode.ENABLE_PROCESSED_INPUT.code;
|
newMode = mode.getValue() | PROCESSED_INPUT;
|
||||||
} else {
|
} else {
|
||||||
// Disable Ctrl+C
|
// Disable Ctrl+C
|
||||||
newMode = mode.getValue() & ~ConsoleMode.ENABLE_PROCESSED_INPUT.code;
|
newMode = mode.getValue() & ~PROCESSED_INPUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kernel32.SetConsoleMode(console, newMode);
|
ASSERT(SetConsoleMode(console, newMode), Terminal.CONSOLE_ERROR_INIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -144,18 +148,18 @@ class WindowsTerminal extends Terminal {
|
|||||||
int read() {
|
int read() {
|
||||||
int input = readInput();
|
int input = readInput();
|
||||||
|
|
||||||
// if (Console.ENABLE_ECHO) {
|
if (echoEnabled) {
|
||||||
// char asChar = (char) input;
|
char asChar = (char) input;
|
||||||
// if (asChar == '\n') {
|
if (asChar == '\n') {
|
||||||
// System.out.println();
|
OUT.println();
|
||||||
// }
|
}
|
||||||
// else {
|
else {
|
||||||
// System.out.print(asChar);
|
OUT.print(asChar);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// // have to flush, otherwise we'll never see the chars on screen
|
// have to flush, otherwise we'll never see the chars on screen
|
||||||
// System.out.flush();
|
OUT.flush();
|
||||||
// }
|
}
|
||||||
|
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
@ -178,6 +182,8 @@ class WindowsTerminal extends Terminal {
|
|||||||
if (uChar == '\r') {
|
if (uChar == '\r') {
|
||||||
// we purposefully swallow input after \r, and substitute it with \n
|
// we purposefully swallow input after \r, and substitute it with \n
|
||||||
return '\n';
|
return '\n';
|
||||||
|
} else if (uChar == '\n') {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return uChar;
|
return uChar;
|
||||||
|
Loading…
Reference in New Issue
Block a user