1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "jni.h"
  27 #include "jni_util.h"
  28 #include "jvm.h"
  29 #include "jdk_internal_jline_WindowsTerminal.h"
  30 
  31 #include <stdlib.h>
  32 #include <Wincon.h>
  33 #include <Winuser.h>
  34 
  35 static jclass recordClass;
  36 static jmethodID recordConstructor;
  37 
  38 JNIEXPORT void JNICALL Java_jdk_internal_jline_WindowsTerminal_initIDs
  39   (JNIEnv *env, jclass) {
  40     jclass cls = env->FindClass("jdk/internal/jline/WindowsTerminal$KEY_EVENT_RECORD");
  41     CHECK_NULL(cls);
  42     recordClass = (jclass) env->NewGlobalRef(cls);
  43     CHECK_NULL(recordClass);
  44     recordConstructor = env->GetMethodID(cls, "<init>", "(ZCIII)V");
  45     CHECK_NULL(recordConstructor);
  46 }
  47 
  48 JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getConsoleMode
  49   (JNIEnv *, jobject) {
  50     HANDLE hStdIn;
  51     if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
  52         return -1;
  53     }
  54     DWORD fdwMode;
  55     if (! GetConsoleMode(hStdIn, &fdwMode)) {
  56         return -1;
  57     }
  58     return fdwMode;
  59 }
  60 
  61 JNIEXPORT void JNICALL Java_jdk_internal_jline_WindowsTerminal_setConsoleMode
  62   (JNIEnv *, jobject, jint mode) {
  63     HANDLE hStdIn;
  64     if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
  65         return ;
  66     }
  67     DWORD fdwMode = mode;
  68     SetConsoleMode(hStdIn, fdwMode);
  69 }
  70 
  71 JNIEXPORT jobject JNICALL Java_jdk_internal_jline_WindowsTerminal_readKeyEvent
  72   (JNIEnv *env, jobject) {
  73     HANDLE hStdIn;
  74     if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
  75         return NULL;
  76     }
  77     INPUT_RECORD record;
  78     DWORD n;
  79     while (TRUE) {
  80         if (ReadConsoleInput(hStdIn, &record, 1, &n) == 0) {
  81             return NULL;
  82         }
  83         if (record.EventType == KEY_EVENT) {
  84             jclass clazz = env->FindClass("jdk/internal/jline/WindowsTerminal$KEY_EVENT_RECORD");
  85             jmethodID constr = env->GetMethodID(clazz, "<init>", "(ZCIII)V");
  86             return env->NewObject(recordClass,
  87                                   recordConstructor,
  88                                   record.Event.KeyEvent.bKeyDown,
  89                                   record.Event.KeyEvent.uChar.UnicodeChar,
  90                                   record.Event.KeyEvent.dwControlKeyState,
  91                                   record.Event.KeyEvent.wVirtualKeyCode,
  92                                   record.Event.KeyEvent.wRepeatCount);
  93         }
  94         continue;
  95     }
  96 }
  97 
  98 JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getConsoleOutputCodepage
  99   (JNIEnv *, jobject) {
 100     return GetConsoleCP();
 101 }
 102 
 103 JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getWindowsTerminalWidth
 104   (JNIEnv *, jobject) {
 105     HANDLE hStdOut;
 106     if ((hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
 107         return -1;
 108     }
 109     CONSOLE_SCREEN_BUFFER_INFO info;
 110     if (! GetConsoleScreenBufferInfo(hStdOut, &info)) {
 111         return -1;
 112     }
 113     return info.srWindow.Right - info.srWindow.Left;
 114 }
 115 
 116 JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getWindowsTerminalHeight
 117   (JNIEnv *, jobject) {
 118     HANDLE hStdOut;
 119     if ((hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
 120         return -1;
 121     }
 122     CONSOLE_SCREEN_BUFFER_INFO info;
 123     if (! GetConsoleScreenBufferInfo(hStdOut, &info)) {
 124         return -1;
 125     }
 126     return info.srWindow.Bottom - info.srWindow.Top + 1;
 127 }