< prev index next >

jdk/src/jdk.jline/share/classes/jdk/internal/jline/WindowsTerminal.java

Print this page


   1 /*
   2  * Copyright (c) 2002-2012, the original author or authors.
   3  *
   4  * This software is distributable under the BSD license. See the terms of the
   5  * BSD license in the documentation provided with this software.
   6  *
   7  * http://www.opensource.org/licenses/bsd-license.php
   8  */
   9 package jline;
  10 
  11 import java.io.FileDescriptor;
  12 import java.io.FileInputStream;
  13 import java.io.IOException;
  14 import java.io.InputStream;
  15 
  16 import jline.internal.Configuration;
  17 import jline.internal.Log;
  18 import org.fusesource.jansi.internal.WindowsSupport;
  19 import org.fusesource.jansi.internal.Kernel32;
  20 import static org.fusesource.jansi.internal.Kernel32.*;
  21 
  22 import static jline.WindowsTerminal.ConsoleMode.ENABLE_ECHO_INPUT;
  23 import static jline.WindowsTerminal.ConsoleMode.ENABLE_LINE_INPUT;
  24 import static jline.WindowsTerminal.ConsoleMode.ENABLE_PROCESSED_INPUT;
  25 import static jline.WindowsTerminal.ConsoleMode.ENABLE_WINDOW_INPUT;
  26 import static jline.internal.Preconditions.checkNotNull;
  27 
  28 /**
  29  * Terminal implementation for Microsoft Windows. Terminal initialization in
  30  * {@link #init} is accomplished by extracting the
  31  * <em>jline_<i>version</i>.dll</em>, saving it to the system temporary
  32  * directoy (determined by the setting of the <em>java.io.tmpdir</em> System
  33  * property), loading the library, and then calling the Win32 APIs <a
  34  * href="http://msdn.microsoft.com/library/default.asp?
  35  * url=/library/en-us/dllproc/base/setconsolemode.asp">SetConsoleMode</a> and
  36  * <a href="http://msdn.microsoft.com/library/default.asp?
  37  * url=/library/en-us/dllproc/base/getconsolemode.asp">GetConsoleMode</a> to
  38  * disable character echoing.
  39  * <p/>
  40  * <p>
  41  * By default, the {@link #wrapInIfNeeded(java.io.InputStream)} method will attempt
  42  * to test to see if the specified {@link InputStream} is {@link System#in} or a wrapper
  43  * around {@link FileDescriptor#in}, and if so, will bypass the character reading to
  44  * directly invoke the readc() method in the JNI library. This is so the class
  45  * can read special keys (like arrow keys) which are otherwise inaccessible via
  46  * the {@link System#in} stream. Using JNI reading can be bypassed by setting


  48  * to <code>false</code>.
  49  * </p>
  50  *
  51  * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
  52  * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
  53  * @since 2.0
  54  */
  55 public class WindowsTerminal
  56     extends TerminalSupport
  57 {
  58     public static final String DIRECT_CONSOLE = WindowsTerminal.class.getName() + ".directConsole";
  59 
  60     public static final String ANSI = WindowsTerminal.class.getName() + ".ansi";
  61 
  62     private boolean directConsole;
  63 
  64     private int originalMode;
  65 
  66     public WindowsTerminal() throws Exception {
  67         super(true);

  68     }
  69 
  70     @Override
  71     public void init() throws Exception {
  72         super.init();
  73 
  74         setAnsiSupported(Configuration.getBoolean(ANSI, true));

  75 
  76         //
  77         // FIXME: Need a way to disable direct console and sysin detection muck
  78         //
  79 
  80         setDirectConsole(Configuration.getBoolean(DIRECT_CONSOLE, true));
  81 
  82         this.originalMode = getConsoleMode();
  83         setConsoleMode(originalMode & ~ENABLE_ECHO_INPUT.code);
  84         setEchoEnabled(false);
  85     }
  86 
  87     /**
  88      * Restore the original terminal configuration, which can be used when
  89      * shutting down the console reader. The ConsoleReader cannot be
  90      * used after calling this method.
  91      */
  92     @Override
  93     public void restore() throws Exception {
  94         // restore the old console mode


 181         return false;
 182     }
 183 
 184     @Override
 185     public String getOutputEncoding() {
 186         int codepage = getConsoleOutputCodepage();
 187         //http://docs.oracle.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
 188         String charsetMS = "ms" + codepage;
 189         if (java.nio.charset.Charset.isSupported(charsetMS)) {
 190             return charsetMS;
 191         }
 192         String charsetCP = "cp" + codepage;
 193         if (java.nio.charset.Charset.isSupported(charsetCP)) {
 194             return charsetCP;
 195         }
 196         Log.debug("can't figure out the Java Charset of this code page (" + codepage + ")...");
 197         return super.getOutputEncoding();
 198     }
 199 
 200     //











































































































 201     // Native Bits
 202     //
 203     private int getConsoleMode() {
 204         return WindowsSupport.getConsoleMode();
 205     }
 206 
 207     private void setConsoleMode(int mode) {
 208         WindowsSupport.setConsoleMode(mode);
 209     }
 210 
 211     private byte[] readConsoleInput() {
 212         // XXX does how many events to read in one call matter?
 213         INPUT_RECORD[] events = null;
 214         try {
 215             events = WindowsSupport.readConsoleInput(1);
 216         } catch (IOException e) {
 217             Log.debug("read Windows console input error: ", e);
 218         }
 219         if (events == null) {
 220             return new byte[0];


 221         }

 222         StringBuilder sb = new StringBuilder();
 223         for (int i = 0; i < events.length; i++ ) {
 224             KEY_EVENT_RECORD keyEvent = events[i].keyEvent;
 225             //Log.trace(keyEvent.keyDown? "KEY_DOWN" : "KEY_UP", "key code:", keyEvent.keyCode, "char:", (long)keyEvent.uchar); 
 226             if (keyEvent.keyDown) {
 227                 if (keyEvent.uchar > 0) {
 228                     // support some C1 control sequences: ALT + [@-_] (and [a-z]?) => ESC <ascii>
 229                     // http://en.wikipedia.org/wiki/C0_and_C1_control_codes#C1_set
 230                     final int altState = KEY_EVENT_RECORD.LEFT_ALT_PRESSED | KEY_EVENT_RECORD.RIGHT_ALT_PRESSED;
 231                     // Pressing "Alt Gr" is translated to Alt-Ctrl, hence it has to be checked that Ctrl is _not_ pressed,
 232                     // otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
 233                     final int ctrlState = KEY_EVENT_RECORD.LEFT_CTRL_PRESSED | KEY_EVENT_RECORD.RIGHT_CTRL_PRESSED;






















 234                     if (((keyEvent.uchar >= '@' && keyEvent.uchar <= '_') || (keyEvent.uchar >= 'a' && keyEvent.uchar <= 'z'))
 235                         && ((keyEvent.controlKeyState & altState) != 0) && ((keyEvent.controlKeyState & ctrlState) == 0)) {
 236                         sb.append('\u001B'); // ESC
 237                     }
 238 
 239                     sb.append(keyEvent.uchar);
 240                     continue;
 241                 }

 242                 // virtual keycodes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
 243                 // just add support for basic editing keys (no control state, no numpad keys)
 244                 String escapeSequence = null;
 245                 switch (keyEvent.keyCode) {
 246                 case 0x21: // VK_PRIOR PageUp
 247                     escapeSequence = "\u001B[5~";
 248                     break;
 249                 case 0x22: // VK_NEXT PageDown
 250                     escapeSequence = "\u001B[6~";
 251                     break;
 252                 case 0x23: // VK_END
 253                     escapeSequence = "\u001B[4~";
 254                     break;
 255                 case 0x24: // VK_HOME
 256                     escapeSequence = "\u001B[1~";
 257                     break;
 258                 case 0x25: // VK_LEFT
 259                     escapeSequence = "\u001B[D";
 260                     break;
 261                 case 0x26: // VK_UP
 262                     escapeSequence = "\u001B[A";
 263                     break;
 264                 case 0x27: // VK_RIGHT
 265                     escapeSequence = "\u001B[C";
 266                     break;
 267                 case 0x28: // VK_DOWN
 268                     escapeSequence = "\u001B[B";
 269                     break;
 270                 case 0x2D: // VK_INSERT
 271                     escapeSequence = "\u001B[2~";
 272                     break;
 273                 case 0x2E: // VK_DELETE
 274                     escapeSequence = "\u001B[3~";
 275                     break;
 276                 default:
 277                     break;
 278                 }
 279                 if (escapeSequence != null) {
 280                     for (int k = 0; k < keyEvent.repeatCount; k++) {
 281                         sb.append(escapeSequence);
 282                     }
 283                 }

 284             } else {
 285                 // key up event
 286                 // support ALT+NumPad input method
 287                 if (keyEvent.keyCode == 0x12/*VK_MENU ALT key*/ && keyEvent.uchar > 0) {
 288                     sb.append(keyEvent.uchar);
 289                 }
 290             }












 291         }
 292         return sb.toString().getBytes();


 293     }
 294 
 295     private int getConsoleOutputCodepage() {
 296         return Kernel32.GetConsoleOutputCP();


 297     }



 298 
 299     private int getWindowsTerminalWidth() {
 300         return WindowsSupport.getWindowsTerminalWidth();














 301     }
 302 
 303     private int getWindowsTerminalHeight() {
 304         return WindowsSupport.getWindowsTerminalHeight();
 305     }
 306 






 307     /**
 308      * Console mode
 309      * <p/>
 310      * Constants copied <tt>wincon.h</tt>.
 311      */
 312     public static enum ConsoleMode
 313     {
 314         /**
 315          * The ReadFile or ReadConsole function returns only when a carriage return
 316          * character is read. If this mode is disable, the functions return when one
 317          * or more characters are available.
 318          */
 319         ENABLE_LINE_INPUT(2),
 320 
 321         /**
 322          * Characters read by the ReadFile or ReadConsole function are written to
 323          * the active screen buffer as they are read. This mode can be used only if
 324          * the ENABLE_LINE_INPUT mode is also enabled.
 325          */
 326         ENABLE_ECHO_INPUT(4),


   1 /*
   2  * Copyright (c) 2002-2012, the original author or authors.
   3  *
   4  * This software is distributable under the BSD license. See the terms of the
   5  * BSD license in the documentation provided with this software.
   6  *
   7  * http://www.opensource.org/licenses/bsd-license.php
   8  */
   9 package jdk.internal.jline;
  10 
  11 import java.io.FileDescriptor;
  12 import java.io.FileInputStream;
  13 import java.io.IOException;
  14 import java.io.InputStream;
  15 
  16 import jdk.internal.jline.internal.Configuration;
  17 import jdk.internal.jline.internal.Log;
  18 //import org.fusesource.jansi.internal.WindowsSupport;
  19 //import org.fusesource.jansi.internal.Kernel32;
  20 //import static org.fusesource.jansi.internal.Kernel32.*;
  21 
  22 import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_ECHO_INPUT;
  23 import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_LINE_INPUT;
  24 import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_PROCESSED_INPUT;
  25 import static jdk.internal.jline.WindowsTerminal.ConsoleMode.ENABLE_WINDOW_INPUT;

  26 
  27 /**
  28  * Terminal implementation for Microsoft Windows. Terminal initialization in
  29  * {@link #init} is accomplished by extracting the
  30  * <em>jline_<i>version</i>.dll</em>, saving it to the system temporary
  31  * directoy (determined by the setting of the <em>java.io.tmpdir</em> System
  32  * property), loading the library, and then calling the Win32 APIs <a
  33  * href="http://msdn.microsoft.com/library/default.asp?
  34  * url=/library/en-us/dllproc/base/setconsolemode.asp">SetConsoleMode</a> and
  35  * <a href="http://msdn.microsoft.com/library/default.asp?
  36  * url=/library/en-us/dllproc/base/getconsolemode.asp">GetConsoleMode</a> to
  37  * disable character echoing.
  38  * <p/>
  39  * <p>
  40  * By default, the {@link #wrapInIfNeeded(java.io.InputStream)} method will attempt
  41  * to test to see if the specified {@link InputStream} is {@link System#in} or a wrapper
  42  * around {@link FileDescriptor#in}, and if so, will bypass the character reading to
  43  * directly invoke the readc() method in the JNI library. This is so the class
  44  * can read special keys (like arrow keys) which are otherwise inaccessible via
  45  * the {@link System#in} stream. Using JNI reading can be bypassed by setting


  47  * to <code>false</code>.
  48  * </p>
  49  *
  50  * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
  51  * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
  52  * @since 2.0
  53  */
  54 public class WindowsTerminal
  55     extends TerminalSupport
  56 {
  57     public static final String DIRECT_CONSOLE = WindowsTerminal.class.getName() + ".directConsole";
  58 
  59     public static final String ANSI = WindowsTerminal.class.getName() + ".ansi";
  60 
  61     private boolean directConsole;
  62 
  63     private int originalMode;
  64 
  65     public WindowsTerminal() throws Exception {
  66         super(true);
  67         System.loadLibrary("jline");
  68     }
  69 
  70     @Override
  71     public void init() throws Exception {
  72         super.init();
  73 
  74 //        setAnsiSupported(Configuration.getBoolean(ANSI, true));
  75         setAnsiSupported(false);
  76 
  77         //
  78         // FIXME: Need a way to disable direct console and sysin detection muck
  79         //
  80 
  81         setDirectConsole(Configuration.getBoolean(DIRECT_CONSOLE, true));
  82 
  83         this.originalMode = getConsoleMode();
  84         setConsoleMode(originalMode & ~ENABLE_ECHO_INPUT.code);
  85         setEchoEnabled(false);
  86     }
  87 
  88     /**
  89      * Restore the original terminal configuration, which can be used when
  90      * shutting down the console reader. The ConsoleReader cannot be
  91      * used after calling this method.
  92      */
  93     @Override
  94     public void restore() throws Exception {
  95         // restore the old console mode


 182         return false;
 183     }
 184 
 185     @Override
 186     public String getOutputEncoding() {
 187         int codepage = getConsoleOutputCodepage();
 188         //http://docs.oracle.com/javase/6/docs/technotes/guides/intl/encoding.doc.html
 189         String charsetMS = "ms" + codepage;
 190         if (java.nio.charset.Charset.isSupported(charsetMS)) {
 191             return charsetMS;
 192         }
 193         String charsetCP = "cp" + codepage;
 194         if (java.nio.charset.Charset.isSupported(charsetCP)) {
 195             return charsetCP;
 196         }
 197         Log.debug("can't figure out the Java Charset of this code page (" + codepage + ")...");
 198         return super.getOutputEncoding();
 199     }
 200 
 201     //
 202     // Original code:
 203     //
 204 //    private int getConsoleMode() {
 205 //        return WindowsSupport.getConsoleMode();
 206 //    }
 207 //
 208 //    private void setConsoleMode(int mode) {
 209 //        WindowsSupport.setConsoleMode(mode);
 210 //    }
 211 //
 212 //    private byte[] readConsoleInput() {
 213 //        // XXX does how many events to read in one call matter?
 214 //        INPUT_RECORD[] events = null;
 215 //        try {
 216 //            events = WindowsSupport.readConsoleInput(1);
 217 //        } catch (IOException e) {
 218 //            Log.debug("read Windows console input error: ", e);
 219 //        }
 220 //        if (events == null) {
 221 //            return new byte[0];
 222 //        }
 223 //        StringBuilder sb = new StringBuilder();
 224 //        for (int i = 0; i < events.length; i++ ) {
 225 //            KEY_EVENT_RECORD keyEvent = events[i].keyEvent;
 226 //            //Log.trace(keyEvent.keyDown? "KEY_DOWN" : "KEY_UP", "key code:", keyEvent.keyCode, "char:", (long)keyEvent.uchar);
 227 //            if (keyEvent.keyDown) {
 228 //                if (keyEvent.uchar > 0) {
 229 //                    // support some C1 control sequences: ALT + [@-_] (and [a-z]?) => ESC <ascii>
 230 //                    // http://en.wikipedia.org/wiki/C0_and_C1_control_codes#C1_set
 231 //                    final int altState = KEY_EVENT_RECORD.LEFT_ALT_PRESSED | KEY_EVENT_RECORD.RIGHT_ALT_PRESSED;
 232 //                    // Pressing "Alt Gr" is translated to Alt-Ctrl, hence it has to be checked that Ctrl is _not_ pressed,
 233 //                    // otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
 234 //                    final int ctrlState = KEY_EVENT_RECORD.LEFT_CTRL_PRESSED | KEY_EVENT_RECORD.RIGHT_CTRL_PRESSED;
 235 //                    if (((keyEvent.uchar >= '@' && keyEvent.uchar <= '_') || (keyEvent.uchar >= 'a' && keyEvent.uchar <= 'z'))
 236 //                        && ((keyEvent.controlKeyState & altState) != 0) && ((keyEvent.controlKeyState & ctrlState) == 0)) {
 237 //                        sb.append('\u001B'); // ESC
 238 //                    }
 239 //
 240 //                    sb.append(keyEvent.uchar);
 241 //                    continue;
 242 //                }
 243 //                // virtual keycodes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
 244 //                // just add support for basic editing keys (no control state, no numpad keys)
 245 //                String escapeSequence = null;
 246 //                switch (keyEvent.keyCode) {
 247 //                case 0x21: // VK_PRIOR PageUp
 248 //                    escapeSequence = "\u001B[5~";
 249 //                    break;
 250 //                case 0x22: // VK_NEXT PageDown
 251 //                    escapeSequence = "\u001B[6~";
 252 //                    break;
 253 //                case 0x23: // VK_END
 254 //                    escapeSequence = "\u001B[4~";
 255 //                    break;
 256 //                case 0x24: // VK_HOME
 257 //                    escapeSequence = "\u001B[1~";
 258 //                    break;
 259 //                case 0x25: // VK_LEFT
 260 //                    escapeSequence = "\u001B[D";
 261 //                    break;
 262 //                case 0x26: // VK_UP
 263 //                    escapeSequence = "\u001B[A";
 264 //                    break;
 265 //                case 0x27: // VK_RIGHT
 266 //                    escapeSequence = "\u001B[C";
 267 //                    break;
 268 //                case 0x28: // VK_DOWN
 269 //                    escapeSequence = "\u001B[B";
 270 //                    break;
 271 //                case 0x2D: // VK_INSERT
 272 //                    escapeSequence = "\u001B[2~";
 273 //                    break;
 274 //                case 0x2E: // VK_DELETE
 275 //                    escapeSequence = "\u001B[3~";
 276 //                    break;
 277 //                default:
 278 //                    break;
 279 //                }
 280 //                if (escapeSequence != null) {
 281 //                    for (int k = 0; k < keyEvent.repeatCount; k++) {
 282 //                        sb.append(escapeSequence);
 283 //                    }
 284 //                }
 285 //            } else {
 286 //                // key up event
 287 //                // support ALT+NumPad input method
 288 //                if (keyEvent.keyCode == 0x12/*VK_MENU ALT key*/ && keyEvent.uchar > 0) {
 289 //                    sb.append(keyEvent.uchar);
 290 //                }
 291 //            }
 292 //        }
 293 //        return sb.toString().getBytes();
 294 //    }
 295 //
 296 //    private int getConsoleOutputCodepage() {
 297 //        return Kernel32.GetConsoleOutputCP();
 298 //    }
 299 //
 300 //    private int getWindowsTerminalWidth() {
 301 //        return WindowsSupport.getWindowsTerminalWidth();
 302 //    }
 303 //
 304 //    private int getWindowsTerminalHeight() {
 305 //        return WindowsSupport.getWindowsTerminalHeight();
 306 //    }
 307 
 308     //
 309     // Native Bits
 310     //
 311     private native int getConsoleMode();


 312 
 313     private native void setConsoleMode(int mode);


 314 
 315     private byte[] readConsoleInput() {
 316         KEY_EVENT_RECORD keyEvent = readKeyEvent();
 317 
 318         return convertKeys(keyEvent).getBytes();



 319     }
 320 
 321     public static String convertKeys(KEY_EVENT_RECORD keyEvent) {
 322         if (keyEvent == null) {
 323             return "";
 324         }
 325 
 326         StringBuilder sb = new StringBuilder();
 327 


 328         if (keyEvent.keyDown) {
 329             if (keyEvent.uchar > 0) {
 330                 // support some C1 control sequences: ALT + [@-_] (and [a-z]?) => ESC <ascii>
 331                 // http://en.wikipedia.org/wiki/C0_and_C1_control_codes#C1_set
 332                 final int altState = KEY_EVENT_RECORD.ALT_PRESSED;
 333                 // Pressing "Alt Gr" is translated to Alt-Ctrl, hence it has to be checked that Ctrl is _not_ pressed,
 334                 // otherwise inserting of "Alt Gr" codes on non-US keyboards would yield errors
 335                 final int ctrlState = KEY_EVENT_RECORD.CTRL_PRESSED;
 336 
 337                 boolean handled = false;
 338 
 339                 if ((keyEvent.controlKeyState & ctrlState) != 0) {
 340                     switch (keyEvent.keyCode) {
 341                         case 0x43: //Ctrl-C
 342                             sb.append("\003");
 343                             handled = true;
 344                             break;
 345                     }
 346                 }
 347 
 348                 if ((keyEvent.controlKeyState & KEY_EVENT_RECORD.SHIFT_PRESSED) != 0) {
 349                     switch (keyEvent.keyCode) {
 350                         case 0x09: //Shift-Tab
 351                             sb.append("\033\133\132");
 352                             handled = true;
 353                             break;
 354                     }
 355                 }
 356 
 357                 if (!handled) {
 358                     if (((keyEvent.uchar >= '@' && keyEvent.uchar <= '_') || (keyEvent.uchar >= 'a' && keyEvent.uchar <= 'z'))
 359                         && ((keyEvent.controlKeyState & altState) != 0) && ((keyEvent.controlKeyState & ctrlState) == 0)) {
 360                         sb.append('\u001B'); // ESC
 361                     }
 362 
 363                     sb.append(keyEvent.uchar);

 364                 }
 365             } else {
 366                 // virtual keycodes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
 367                 // just add support for basic editing keys (no control state, no numpad keys)
 368                 String escapeSequence = null;
 369                 switch (keyEvent.keyCode) {
 370                 case 0x21: // VK_PRIOR PageUp
 371                     escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[5~", "\u001B[5;%d~");
 372                     break;
 373                 case 0x22: // VK_NEXT PageDown
 374                     escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[6~", "\u001B[6;%d~");
 375                     break;
 376                 case 0x23: // VK_END
 377                     escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[4~", "\u001B[4;%d~");
 378                     break;
 379                 case 0x24: // VK_HOME
 380                     escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[1~", "\u001B[1;%d~");
 381                     break;
 382                 case 0x25: // VK_LEFT
 383                     escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[D", "\u001B[1;%dD");
 384                     break;
 385                 case 0x26: // VK_UP
 386                     escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[A", "\u001B[1;%dA");
 387                     break;
 388                 case 0x27: // VK_RIGHT
 389                     escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[C", "\u001B[1;%dC");
 390                     break;
 391                 case 0x28: // VK_DOWN
 392                     escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[B", "\u001B[1;%dB");
 393                     break;
 394                 case 0x2D: // VK_INSERT
 395                     escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[2~", "\u001B[2;%d~");
 396                     break;
 397                 case 0x2E: // VK_DELETE
 398                     escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[3~", "\u001B[3;%d~");
 399                     break;
 400                 default:
 401                     break;
 402                 }
 403                 if (escapeSequence != null) {
 404                     for (int k = 0; k < keyEvent.repeatCount; k++) {
 405                         sb.append(escapeSequence);
 406                     }
 407                 }
 408             }
 409         } else {
 410             // key up event
 411             // support ALT+NumPad input method
 412             if (keyEvent.keyCode == 0x12/*VK_MENU ALT key*/ && keyEvent.uchar > 0) {
 413                 sb.append(keyEvent.uchar);
 414             }
 415         }
 416         return sb.toString();
 417     }
 418 
 419     private static String escapeSequence(int controlKeyState, String noControlSequence, String withControlSequence) {
 420         int controlNum = 1;
 421 
 422         if ((controlKeyState & KEY_EVENT_RECORD.SHIFT_PRESSED) != 0) {
 423             controlNum += 1;
 424         }
 425 
 426         if ((controlKeyState & KEY_EVENT_RECORD.ALT_PRESSED) != 0) {
 427             controlNum += 2;
 428         }
 429 
 430         if ((controlKeyState & KEY_EVENT_RECORD.CTRL_PRESSED) != 0) {
 431             controlNum += 4;
 432         }
 433 
 434         if (controlNum > 1) {
 435             return String.format(withControlSequence, controlNum);
 436         } else {
 437             return noControlSequence;
 438         }
 439     }
 440 
 441     private native KEY_EVENT_RECORD readKeyEvent();
 442 
 443     public static class KEY_EVENT_RECORD {
 444         public final static int ALT_PRESSED = 0x3;
 445         public final static int CTRL_PRESSED = 0xC;
 446         public final static int SHIFT_PRESSED = 0x10;
 447         public final boolean keyDown;
 448         public final char uchar;
 449         public final int controlKeyState;
 450         public final int keyCode;
 451         public final int repeatCount;
 452 
 453         public KEY_EVENT_RECORD(boolean keyDown, char uchar, int controlKeyState, int keyCode, int repeatCount) {
 454             this.keyDown = keyDown;
 455             this.uchar = uchar;
 456             this.controlKeyState = controlKeyState;
 457             this.keyCode = keyCode;
 458             this.repeatCount = repeatCount;
 459         }
 460 


 461     }
 462 
 463     private native int getConsoleOutputCodepage();
 464 
 465     private native int getWindowsTerminalWidth();
 466 
 467     private native int getWindowsTerminalHeight();
 468 
 469     /**
 470      * Console mode
 471      * <p/>
 472      * Constants copied <tt>wincon.h</tt>.
 473      */
 474     public static enum ConsoleMode
 475     {
 476         /**
 477          * The ReadFile or ReadConsole function returns only when a carriage return
 478          * character is read. If this mode is disable, the functions return when one
 479          * or more characters are available.
 480          */
 481         ENABLE_LINE_INPUT(2),
 482 
 483         /**
 484          * Characters read by the ReadFile or ReadConsole function are written to
 485          * the active screen buffer as they are read. This mode can be used only if
 486          * the ENABLE_LINE_INPUT mode is also enabled.
 487          */
 488         ENABLE_ECHO_INPUT(4),


< prev index next >