--- /dev/null 2015-04-26 06:51:08.003313989 -0700
+++ new/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/WindowsTerminal.java 2015-07-02 08:21:31.167661104 -0700
@@ -0,0 +1,546 @@
+/*
+ * Copyright (c) 2002-2012, the original author or authors.
+ *
+ * This software is distributable under the BSD license. See the terms of the
+ * BSD license in the documentation provided with this software.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ */
+package jdk.internal.jline;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import jdk.internal.jline.internal.Configuration;
+import jdk.internal.jline.internal.Log;
+//import org.fusesource.jansi.internal.WindowsSupport;
+//import org.fusesource.jansi.internal.Kernel32;
+//import static org.fusesource.jansi.internal.Kernel32.*;
+
+import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_ECHO_INPUT;
+import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_LINE_INPUT;
+import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_PROCESSED_INPUT;
+import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_WINDOW_INPUT;
+
+/**
+ * Terminal implementation for Microsoft Windows. Terminal initialization in
+ * {@link #init} is accomplished by extracting the
+ * jline_version.dll, saving it to the system temporary
+ * directoy (determined by the setting of the java.io.tmpdir System
+ * property), loading the library, and then calling the Win32 APIs SetConsoleMode and
+ * GetConsoleMode to
+ * disable character echoing.
+ *
+ *
+ * By default, the {@link #wrapInIfNeeded(java.io.InputStream)} method will attempt
+ * to test to see if the specified {@link InputStream} is {@link System#in} or a wrapper
+ * around {@link FileDescriptor#in}, and if so, will bypass the character reading to
+ * directly invoke the readc() method in the JNI library. This is so the class
+ * can read special keys (like arrow keys) which are otherwise inaccessible via
+ * the {@link System#in} stream. Using JNI reading can be bypassed by setting
+ * the jline.WindowsTerminal.directConsole
system property
+ * to false
.
+ *
+ *
+ * @author Marc Prud'hommeaux
+ * @author Jason Dillon
+ * @since 2.0
+ */
+public class WindowsTerminal
+ extends TerminalSupport
+{
+ public static final String DIRECT_CONSOLE = WindowsTerminal.class.getName() + ".directConsole";
+
+ public static final String ANSI = WindowsTerminal.class.getName() + ".ansi";
+
+ private boolean directConsole;
+
+ private int originalMode;
+
+ public WindowsTerminal() throws Exception {
+ super(true);
+ }
+
+ @Override
+ public void init() throws Exception {
+ super.init();
+
+// setAnsiSupported(Configuration.getBoolean(ANSI, true));
+ setAnsiSupported(false);
+
+ //
+ // FIXME: Need a way to disable direct console and sysin detection muck
+ //
+
+ setDirectConsole(Configuration.getBoolean(DIRECT_CONSOLE, true));
+
+ this.originalMode = getConsoleMode();
+ setConsoleMode(originalMode & ~ENABLE_ECHO_INPUT.code);
+ setEchoEnabled(false);
+ }
+
+ /**
+ * Restore the original terminal configuration, which can be used when
+ * shutting down the console reader. The ConsoleReader cannot be
+ * used after calling this method.
+ */
+ @Override
+ public void restore() throws Exception {
+ // restore the old console mode
+ setConsoleMode(originalMode);
+ super.restore();
+ }
+
+ @Override
+ public int getWidth() {
+ int w = getWindowsTerminalWidth();
+ return w < 1 ? DEFAULT_WIDTH : w;
+ }
+
+ @Override
+ public int getHeight() {
+ int h = getWindowsTerminalHeight();
+ return h < 1 ? DEFAULT_HEIGHT : h;
+ }
+
+ @Override
+ public void setEchoEnabled(final boolean enabled) {
+ // Must set these four modes at the same time to make it work fine.
+ if (enabled) {
+ setConsoleMode(getConsoleMode() |
+ ENABLE_ECHO_INPUT.code |
+ ENABLE_LINE_INPUT.code |
+ ENABLE_PROCESSED_INPUT.code |
+ ENABLE_WINDOW_INPUT.code);
+ }
+ else {
+ setConsoleMode(getConsoleMode() &
+ ~(ENABLE_LINE_INPUT.code |
+ ENABLE_ECHO_INPUT.code |
+ ENABLE_PROCESSED_INPUT.code |
+ ENABLE_WINDOW_INPUT.code));
+ }
+ super.setEchoEnabled(enabled);
+ }
+
+ /**
+ * Whether or not to allow the use of the JNI console interaction.
+ */
+ public void setDirectConsole(final boolean flag) {
+ this.directConsole = flag;
+ Log.debug("Direct console: ", flag);
+ }
+
+ /**
+ * Whether or not to allow the use of the JNI console interaction.
+ */
+ public Boolean getDirectConsole() {
+ return directConsole;
+ }
+
+
+ @Override
+ public InputStream wrapInIfNeeded(InputStream in) throws IOException {
+ if (directConsole && isSystemIn(in)) {
+ return new InputStream() {
+ private byte[] buf = null;
+ int bufIdx = 0;
+
+ @Override
+ public int read() throws IOException {
+ while (buf == null || bufIdx == buf.length) {
+ buf = readConsoleInput();
+ bufIdx = 0;
+ }
+ int c = buf[bufIdx] & 0xFF;
+ bufIdx++;
+ return c;
+ }
+ };
+ } else {
+ return super.wrapInIfNeeded(in);
+ }
+ }
+
+ protected boolean isSystemIn(final InputStream in) throws IOException {
+ if (in == null) {
+ return false;
+ }
+ else if (in == System.in) {
+ return true;
+ }
+ else if (in instanceof FileInputStream && ((FileInputStream) in).getFD() == FileDescriptor.in) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public String getOutputEncoding() {
+ int codepage = getConsoleOutputCodepage();
+ //http://docs.oracle.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
+ String charsetMS = "ms" + codepage;
+ if (java.nio.charset.Charset.isSupported(charsetMS)) {
+ return charsetMS;
+ }
+ String charsetCP = "cp" + codepage;
+ if (java.nio.charset.Charset.isSupported(charsetCP)) {
+ return charsetCP;
+ }
+ Log.debug("can't figure out the Java Charset of this code page (" + codepage + ")...");
+ return super.getOutputEncoding();
+ }
+
+ //
+ // Original code:
+ //
+// private int getConsoleMode() {
+// return WindowsSupport.getConsoleMode();
+// }
+//
+// private void setConsoleMode(int mode) {
+// WindowsSupport.setConsoleMode(mode);
+// }
+//
+// private byte[] readConsoleInput() {
+// // XXX does how many events to read in one call matter?
+// INPUT_RECORD[] events = null;
+// try {
+// events = WindowsSupport.readConsoleInput(1);
+// } catch (IOException e) {
+// Log.debug("read Windows console input error: ", e);
+// }
+// if (events == null) {
+// return new byte[0];
+// }
+// StringBuilder sb = new StringBuilder();
+// for (int i = 0; i < events.length; i++ ) {
+// KEY_EVENT_RECORD keyEvent = events[i].keyEvent;
+// //Log.trace(keyEvent.keyDown? "KEY_DOWN" : "KEY_UP", "key code:", keyEvent.keyCode, "char:", (long)keyEvent.uchar);
+// if (keyEvent.keyDown) {
+// if (keyEvent.uchar > 0) {
+// // support some C1 control sequences: ALT + [@-_] (and [a-z]?) => ESC
+// // http://en.wikipedia.org/wiki/C0_and_C1_control_codes#C1_set
+// final int altState = KEY_EVENT_RECORD.LEFT_ALT_PRESSED | KEY_EVENT_RECORD.RIGHT_ALT_PRESSED;
+// // Pressing "Alt Gr" is translated to Alt-Ctrl, hence it has to be checked that Ctrl is _not_ pressed,
+// // otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
+// final int ctrlState = KEY_EVENT_RECORD.LEFT_CTRL_PRESSED | KEY_EVENT_RECORD.RIGHT_CTRL_PRESSED;
+// if (((keyEvent.uchar >= '@' && keyEvent.uchar <= '_') || (keyEvent.uchar >= 'a' && keyEvent.uchar <= 'z'))
+// && ((keyEvent.controlKeyState & altState) != 0) && ((keyEvent.controlKeyState & ctrlState) == 0)) {
+// sb.append('\u001B'); // ESC
+// }
+//
+// sb.append(keyEvent.uchar);
+// continue;
+// }
+// // virtual keycodes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
+// // just add support for basic editing keys (no control state, no numpad keys)
+// String escapeSequence = null;
+// switch (keyEvent.keyCode) {
+// case 0x21: // VK_PRIOR PageUp
+// escapeSequence = "\u001B[5~";
+// break;
+// case 0x22: // VK_NEXT PageDown
+// escapeSequence = "\u001B[6~";
+// break;
+// case 0x23: // VK_END
+// escapeSequence = "\u001B[4~";
+// break;
+// case 0x24: // VK_HOME
+// escapeSequence = "\u001B[1~";
+// break;
+// case 0x25: // VK_LEFT
+// escapeSequence = "\u001B[D";
+// break;
+// case 0x26: // VK_UP
+// escapeSequence = "\u001B[A";
+// break;
+// case 0x27: // VK_RIGHT
+// escapeSequence = "\u001B[C";
+// break;
+// case 0x28: // VK_DOWN
+// escapeSequence = "\u001B[B";
+// break;
+// case 0x2D: // VK_INSERT
+// escapeSequence = "\u001B[2~";
+// break;
+// case 0x2E: // VK_DELETE
+// escapeSequence = "\u001B[3~";
+// break;
+// default:
+// break;
+// }
+// if (escapeSequence != null) {
+// for (int k = 0; k < keyEvent.repeatCount; k++) {
+// sb.append(escapeSequence);
+// }
+// }
+// } else {
+// // key up event
+// // support ALT+NumPad input method
+// if (keyEvent.keyCode == 0x12/*VK_MENU ALT key*/ && keyEvent.uchar > 0) {
+// sb.append(keyEvent.uchar);
+// }
+// }
+// }
+// return sb.toString().getBytes();
+// }
+//
+// private int getConsoleOutputCodepage() {
+// return Kernel32.GetConsoleOutputCP();
+// }
+//
+// private int getWindowsTerminalWidth() {
+// return WindowsSupport.getWindowsTerminalWidth();
+// }
+//
+// private int getWindowsTerminalHeight() {
+// return WindowsSupport.getWindowsTerminalHeight();
+// }
+
+ //
+ // Native Bits
+ //
+ static {
+ System.loadLibrary("le");
+ initIDs();
+ }
+
+ private static native void initIDs();
+
+ private native int getConsoleMode();
+
+ private native void setConsoleMode(int mode);
+
+ private byte[] readConsoleInput() {
+ KEY_EVENT_RECORD keyEvent = readKeyEvent();
+
+ return convertKeys(keyEvent).getBytes();
+ }
+
+ public static String convertKeys(KEY_EVENT_RECORD keyEvent) {
+ if (keyEvent == null) {
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder();
+
+ if (keyEvent.keyDown) {
+ if (keyEvent.uchar > 0) {
+ // support some C1 control sequences: ALT + [@-_] (and [a-z]?) => ESC
+ // http://en.wikipedia.org/wiki/C0_and_C1_control_codes#C1_set
+ final int altState = KEY_EVENT_RECORD.ALT_PRESSED;
+ // Pressing "Alt Gr" is translated to Alt-Ctrl, hence it has to be checked that Ctrl is _not_ pressed,
+ // otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
+ final int ctrlState = KEY_EVENT_RECORD.CTRL_PRESSED;
+
+ boolean handled = false;
+
+ if ((keyEvent.controlKeyState & ctrlState) != 0) {
+ switch (keyEvent.keyCode) {
+ case 0x43: //Ctrl-C
+ sb.append("\003");
+ handled = true;
+ break;
+ }
+ }
+
+ if ((keyEvent.controlKeyState & KEY_EVENT_RECORD.SHIFT_PRESSED) != 0) {
+ switch (keyEvent.keyCode) {
+ case 0x09: //Shift-Tab
+ sb.append("\033\133\132");
+ handled = true;
+ break;
+ }
+ }
+
+ if (!handled) {
+ if (((keyEvent.uchar >= '@' && keyEvent.uchar <= '_') || (keyEvent.uchar >= 'a' && keyEvent.uchar <= 'z'))
+ && ((keyEvent.controlKeyState & altState) != 0) && ((keyEvent.controlKeyState & ctrlState) == 0)) {
+ sb.append('\u001B'); // ESC
+ }
+
+ sb.append(keyEvent.uchar);
+ }
+ } else {
+ // virtual keycodes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
+ // just add support for basic editing keys (no control state, no numpad keys)
+ String escapeSequence = null;
+ switch (keyEvent.keyCode) {
+ case 0x21: // VK_PRIOR PageUp
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[5~", "\u001B[5;%d~");
+ break;
+ case 0x22: // VK_NEXT PageDown
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[6~", "\u001B[6;%d~");
+ break;
+ case 0x23: // VK_END
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[4~", "\u001B[4;%d~");
+ break;
+ case 0x24: // VK_HOME
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[1~", "\u001B[1;%d~");
+ break;
+ case 0x25: // VK_LEFT
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[D", "\u001B[1;%dD");
+ break;
+ case 0x26: // VK_UP
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[A", "\u001B[1;%dA");
+ break;
+ case 0x27: // VK_RIGHT
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[C", "\u001B[1;%dC");
+ break;
+ case 0x28: // VK_DOWN
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[B", "\u001B[1;%dB");
+ break;
+ case 0x2D: // VK_INSERT
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[2~", "\u001B[2;%d~");
+ break;
+ case 0x2E: // VK_DELETE
+ escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[3~", "\u001B[3;%d~");
+ break;
+ default:
+ break;
+ }
+ if (escapeSequence != null) {
+ for (int k = 0; k < keyEvent.repeatCount; k++) {
+ sb.append(escapeSequence);
+ }
+ }
+ }
+ } else {
+ // key up event
+ // support ALT+NumPad input method
+ if (keyEvent.keyCode == 0x12/*VK_MENU ALT key*/ && keyEvent.uchar > 0) {
+ sb.append(keyEvent.uchar);
+ }
+ }
+ return sb.toString();
+ }
+
+ private static String escapeSequence(int controlKeyState, String noControlSequence, String withControlSequence) {
+ int controlNum = 1;
+
+ if ((controlKeyState & KEY_EVENT_RECORD.SHIFT_PRESSED) != 0) {
+ controlNum += 1;
+ }
+
+ if ((controlKeyState & KEY_EVENT_RECORD.ALT_PRESSED) != 0) {
+ controlNum += 2;
+ }
+
+ if ((controlKeyState & KEY_EVENT_RECORD.CTRL_PRESSED) != 0) {
+ controlNum += 4;
+ }
+
+ if (controlNum > 1) {
+ return String.format(withControlSequence, controlNum);
+ } else {
+ return noControlSequence;
+ }
+ }
+
+ private native KEY_EVENT_RECORD readKeyEvent();
+
+ public static class KEY_EVENT_RECORD {
+ public final static int ALT_PRESSED = 0x3;
+ public final static int CTRL_PRESSED = 0xC;
+ public final static int SHIFT_PRESSED = 0x10;
+ public final boolean keyDown;
+ public final char uchar;
+ public final int controlKeyState;
+ public final int keyCode;
+ public final int repeatCount;
+
+ public KEY_EVENT_RECORD(boolean keyDown, char uchar, int controlKeyState, int keyCode, int repeatCount) {
+ this.keyDown = keyDown;
+ this.uchar = uchar;
+ this.controlKeyState = controlKeyState;
+ this.keyCode = keyCode;
+ this.repeatCount = repeatCount;
+ }
+
+ }
+
+ private native int getConsoleOutputCodepage();
+
+ private native int getWindowsTerminalWidth();
+
+ private native int getWindowsTerminalHeight();
+
+ /**
+ * Console mode
+ *
+ * Constants copied wincon.h.
+ */
+ public static enum ConsoleMode
+ {
+ /**
+ * 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.
+ */
+ ENABLE_LINE_INPUT(2),
+
+ /**
+ * Characters read by the ReadFile or ReadConsole function are written to
+ * the active screen buffer as they are read. This mode can be used only if
+ * the ENABLE_LINE_INPUT mode is also enabled.
+ */
+ ENABLE_ECHO_INPUT(4),
+
+ /**
+ * 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.
+ */
+ ENABLE_PROCESSED_INPUT(1),
+
+ /**
+ * User interactions that change the size of the console screen buffer are
+ * reported in the console's input buffee. Information about these events
+ * can be read from the input buffer by applications using
+ * theReadConsoleInput function, but not by those using ReadFile
+ * orReadConsole.
+ */
+ ENABLE_WINDOW_INPUT(8),
+
+ /**
+ * If the mouse pointer is within the borders of the console window and the
+ * window has the keyboard focus, mouse events generated by mouse movement
+ * and button presses are placed in the input buffer. These events are
+ * discarded by ReadFile or ReadConsole, even when this mode is enabled.
+ */
+ ENABLE_MOUSE_INPUT(16),
+
+ /**
+ * When enabled, text entered in a console window will be inserted at the
+ * current cursor location and all text following that location will not be
+ * overwritten. When disabled, all following text will be overwritten. An OR
+ * operation must be performed with this flag and the ENABLE_EXTENDED_FLAGS
+ * flag to enable this functionality.
+ */
+ ENABLE_PROCESSED_OUTPUT(1),
+
+ /**
+ * This flag enables the user to use the mouse to select and edit text. To
+ * enable this option, use the OR to combine this flag with
+ * ENABLE_EXTENDED_FLAGS.
+ */
+ ENABLE_WRAP_AT_EOL_OUTPUT(2),;
+
+ public final int code;
+
+ ConsoleMode(final int code) {
+ this.code = code;
+ }
+ }
+
+}