diff --git a/make/modules/jdk.internal.le/Lib.gmk b/make/modules/jdk.internal.le/Lib.gmk index 0c5af51bf2344..6a5e9ec663f4d 100644 --- a/make/modules/jdk.internal.le/Lib.gmk +++ b/make/modules/jdk.internal.le/Lib.gmk @@ -27,7 +27,7 @@ include LibCommon.gmk ################################################################################ -ifeq ($(call isTargetOs, linux macosx), true) +ifeq ($(call isTargetOs, linux macosx windows), true) $(eval $(call SetupJdkLibrary, BUILD_LIBLE, \ NAME := le, \ diff --git a/src/jdk.internal.le/unix/classes/jdk/internal/console/LastErrorException.java b/src/jdk.internal.le/share/classes/jdk/internal/console/LastErrorException.java similarity index 100% rename from src/jdk.internal.le/unix/classes/jdk/internal/console/LastErrorException.java rename to src/jdk.internal.le/share/classes/jdk/internal/console/LastErrorException.java diff --git a/src/jdk.internal.le/share/classes/jdk/internal/console/SimpleConsoleReader.java b/src/jdk.internal.le/share/classes/jdk/internal/console/SimpleConsoleReader.java index c3d8b1bb33eaf..9688e6a8cc169 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/console/SimpleConsoleReader.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/console/SimpleConsoleReader.java @@ -41,10 +41,9 @@ public static char[] doRead(Reader reader, Writer out, boolean password, int fir CleanableBuffer result = new CleanableBuffer(); try { doReadImpl(reader, out, password, firstLineOffset, terminalWidthSupplier, result); - return result.data; - } catch (Throwable t) { + return Arrays.copyOf(result.data, result.length); + } finally { result.zeroOut(); - throw t; } } diff --git a/src/jdk.internal.le/windows/classes/jdk/internal/console/Kernel32.java b/src/jdk.internal.le/windows/classes/jdk/internal/console/Kernel32.java deleted file mode 100644 index 7fb32b95cf33e..0000000000000 --- a/src/jdk.internal.le/windows/classes/jdk/internal/console/Kernel32.java +++ /dev/null @@ -1,942 +0,0 @@ -/* - * Copyright (c) 2009-2023, the original author(s). - * - * This software is distributable under the BSD license. See the terms of the - * BSD license in the documentation provided with this software. - * - * https://opensource.org/licenses/BSD-3-Clause - */ -package jdk.internal.console; - -import java.io.IOException; -import java.lang.foreign.MemoryLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; -import java.nio.charset.StandardCharsets; -import java.util.Objects; - -@SuppressWarnings({"unused", "restricted"}) -final class Kernel32 { - - public static final int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000; - - public static final int INVALID_HANDLE_VALUE = -1; - public static final int STD_INPUT_HANDLE = -10; - public static final int STD_OUTPUT_HANDLE = -11; - public static final int STD_ERROR_HANDLE = -12; - - public static final int ENABLE_PROCESSED_INPUT = 0x0001; - public static final int ENABLE_LINE_INPUT = 0x0002; - public static final int ENABLE_ECHO_INPUT = 0x0004; - public static final int ENABLE_WINDOW_INPUT = 0x0008; - public static final int ENABLE_MOUSE_INPUT = 0x0010; - public static final int ENABLE_INSERT_MODE = 0x0020; - public static final int ENABLE_QUICK_EDIT_MODE = 0x0040; - public static final int ENABLE_EXTENDED_FLAGS = 0x0080; - - public static final int SHIFT_FLAG = 0x01; - public static final int ALT_FLAG = 0x02; - public static final int CTRL_FLAG = 0x04; - - public static final int RIGHT_ALT_PRESSED = 0x0001; - public static final int LEFT_ALT_PRESSED = 0x0002; - public static final int RIGHT_CTRL_PRESSED = 0x0004; - public static final int LEFT_CTRL_PRESSED = 0x0008; - public static final int SHIFT_PRESSED = 0x0010; - - public static final int FOREGROUND_BLUE = 0x0001; - public static final int FOREGROUND_GREEN = 0x0002; - public static final int FOREGROUND_RED = 0x0004; - public static final int FOREGROUND_INTENSITY = 0x0008; - public static final int BACKGROUND_BLUE = 0x0010; - public static final int BACKGROUND_GREEN = 0x0020; - public static final int BACKGROUND_RED = 0x0040; - public static final int BACKGROUND_INTENSITY = 0x0080; - - // Button state - public static final int FROM_LEFT_1ST_BUTTON_PRESSED = 0x0001; - public static final int RIGHTMOST_BUTTON_PRESSED = 0x0002; - public static final int FROM_LEFT_2ND_BUTTON_PRESSED = 0x0004; - public static final int FROM_LEFT_3RD_BUTTON_PRESSED = 0x0008; - public static final int FROM_LEFT_4TH_BUTTON_PRESSED = 0x0010; - - // Event flags - public static final int MOUSE_MOVED = 0x0001; - public static final int DOUBLE_CLICK = 0x0002; - public static final int MOUSE_WHEELED = 0x0004; - public static final int MOUSE_HWHEELED = 0x0008; - - // Event types - public static final short KEY_EVENT = 0x0001; - public static final short MOUSE_EVENT = 0x0002; - public static final short WINDOW_BUFFER_SIZE_EVENT = 0x0004; - public static final short MENU_EVENT = 0x0008; - public static final short FOCUS_EVENT = 0x0010; - - public static int WaitForSingleObject(java.lang.foreign.MemorySegment hHandle, int dwMilliseconds) { - MethodHandle mh$ = requireNonNull(WaitForSingleObject$MH, "WaitForSingleObject"); - try { - return (int) mh$.invokeExact(hHandle, dwMilliseconds); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static java.lang.foreign.MemorySegment GetStdHandle(int nStdHandle) { - MethodHandle mh$ = requireNonNull(GetStdHandle$MH, "GetStdHandle"); - try { - return (java.lang.foreign.MemorySegment) mh$.invokeExact(nStdHandle); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int FormatMessageW( - int dwFlags, - java.lang.foreign.MemorySegment lpSource, - int dwMessageId, - int dwLanguageId, - java.lang.foreign.MemorySegment lpBuffer, - int nSize, - java.lang.foreign.MemorySegment Arguments) { - MethodHandle mh$ = requireNonNull(FormatMessageW$MH, "FormatMessageW"); - try { - return (int) mh$.invokeExact(dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize, Arguments); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int SetConsoleTextAttribute(java.lang.foreign.MemorySegment hConsoleOutput, short wAttributes) { - MethodHandle mh$ = requireNonNull(SetConsoleTextAttribute$MH, "SetConsoleTextAttribute"); - try { - return (int) mh$.invokeExact(hConsoleOutput, wAttributes); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int SetConsoleMode(java.lang.foreign.MemorySegment hConsoleHandle, int dwMode) { - MethodHandle mh$ = requireNonNull(SetConsoleMode$MH, "SetConsoleMode"); - try { - return (int) mh$.invokeExact(hConsoleHandle, dwMode); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int GetConsoleMode( - java.lang.foreign.MemorySegment hConsoleHandle, java.lang.foreign.MemorySegment lpMode) { - MethodHandle mh$ = requireNonNull(GetConsoleMode$MH, "GetConsoleMode"); - try { - return (int) mh$.invokeExact(hConsoleHandle, lpMode); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int SetConsoleTitleW(java.lang.foreign.MemorySegment lpConsoleTitle) { - MethodHandle mh$ = requireNonNull(SetConsoleTitleW$MH, "SetConsoleTitleW"); - try { - return (int) mh$.invokeExact(lpConsoleTitle); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int SetConsoleCursorPosition(java.lang.foreign.MemorySegment hConsoleOutput, COORD dwCursorPosition) { - MethodHandle mh$ = requireNonNull(SetConsoleCursorPosition$MH, "SetConsoleCursorPosition"); - try { - return (int) mh$.invokeExact(hConsoleOutput, dwCursorPosition.seg); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int FillConsoleOutputCharacterW( - java.lang.foreign.MemorySegment hConsoleOutput, - char cCharacter, - int nLength, - COORD dwWriteCoord, - java.lang.foreign.MemorySegment lpNumberOfCharsWritten) { - MethodHandle mh$ = requireNonNull(FillConsoleOutputCharacterW$MH, "FillConsoleOutputCharacterW"); - try { - return (int) mh$.invokeExact(hConsoleOutput, cCharacter, nLength, dwWriteCoord.seg, lpNumberOfCharsWritten); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int FillConsoleOutputAttribute( - java.lang.foreign.MemorySegment hConsoleOutput, - short wAttribute, - int nLength, - COORD dwWriteCoord, - java.lang.foreign.MemorySegment lpNumberOfAttrsWritten) { - MethodHandle mh$ = requireNonNull(FillConsoleOutputAttribute$MH, "FillConsoleOutputAttribute"); - try { - return (int) mh$.invokeExact(hConsoleOutput, wAttribute, nLength, dwWriteCoord.seg, lpNumberOfAttrsWritten); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int WriteConsoleW( - java.lang.foreign.MemorySegment hConsoleOutput, - java.lang.foreign.MemorySegment lpBuffer, - int nNumberOfCharsToWrite, - java.lang.foreign.MemorySegment lpNumberOfCharsWritten, - java.lang.foreign.MemorySegment lpReserved) { - MethodHandle mh$ = requireNonNull(WriteConsoleW$MH, "WriteConsoleW"); - try { - return (int) mh$.invokeExact( - hConsoleOutput, lpBuffer, nNumberOfCharsToWrite, lpNumberOfCharsWritten, lpReserved); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int ReadConsoleInputW( - java.lang.foreign.MemorySegment hConsoleInput, - java.lang.foreign.MemorySegment lpBuffer, - int nLength, - java.lang.foreign.MemorySegment lpNumberOfEventsRead) { - MethodHandle mh$ = requireNonNull(ReadConsoleInputW$MH, "ReadConsoleInputW"); - try { - return (int) mh$.invokeExact(hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int PeekConsoleInputW( - java.lang.foreign.MemorySegment hConsoleInput, - java.lang.foreign.MemorySegment lpBuffer, - int nLength, - java.lang.foreign.MemorySegment lpNumberOfEventsRead) { - MethodHandle mh$ = requireNonNull(PeekConsoleInputW$MH, "PeekConsoleInputW"); - try { - return (int) mh$.invokeExact(hConsoleInput, lpBuffer, nLength, lpNumberOfEventsRead); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int GetConsoleScreenBufferInfo( - java.lang.foreign.MemorySegment hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo) { - MethodHandle mh$ = requireNonNull(GetConsoleScreenBufferInfo$MH, "GetConsoleScreenBufferInfo"); - try { - return (int) mh$.invokeExact(hConsoleOutput, lpConsoleScreenBufferInfo.seg); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int ScrollConsoleScreenBuffer( - java.lang.foreign.MemorySegment hConsoleOutput, - SMALL_RECT lpScrollRectangle, - SMALL_RECT lpClipRectangle, - COORD dwDestinationOrigin, - CHAR_INFO lpFill) { - MethodHandle mh$ = requireNonNull(ScrollConsoleScreenBufferW$MH, "ScrollConsoleScreenBuffer"); - try { - return (int) - mh$.invokeExact(hConsoleOutput, lpScrollRectangle.seg, lpClipRectangle.seg, dwDestinationOrigin.seg, lpFill.seg); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int GetLastError() { - MethodHandle mh$ = requireNonNull(GetLastError$MH, "GetLastError"); - try { - return (int) mh$.invokeExact(); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static int GetFileType(java.lang.foreign.MemorySegment hFile) { - MethodHandle mh$ = requireNonNull(GetFileType$MH, "GetFileType"); - try { - return (int) mh$.invokeExact(hFile); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static java.lang.foreign.MemorySegment _get_osfhandle(int fd) { - MethodHandle mh$ = requireNonNull(_get_osfhandle$MH, "_get_osfhandle"); - try { - return (java.lang.foreign.MemorySegment) mh$.invokeExact(fd); - } catch (Throwable ex$) { - throw new AssertionError("should not reach here", ex$); - } - } - - public static INPUT_RECORD[] readConsoleInputHelper(java.lang.foreign.MemorySegment handle, int count, boolean peek) - throws IOException { - return readConsoleInputHelper(java.lang.foreign.Arena.ofAuto(), handle, count, peek); - } - - public static INPUT_RECORD[] readConsoleInputHelper( - java.lang.foreign.Arena arena, java.lang.foreign.MemorySegment handle, int count, boolean peek) - throws IOException { - java.lang.foreign.MemorySegment inputRecordPtr = arena.allocate(INPUT_RECORD.LAYOUT, count); - java.lang.foreign.MemorySegment length = arena.allocate(java.lang.foreign.ValueLayout.JAVA_INT, 1); - int res = peek - ? PeekConsoleInputW(handle, inputRecordPtr, count, length) - : ReadConsoleInputW(handle, inputRecordPtr, count, length); - if (res == 0) { - throw new IOException("ReadConsoleInputW failed: " + getLastErrorMessage()); - } - int len = length.get(java.lang.foreign.ValueLayout.JAVA_INT, 0); - return inputRecordPtr - .elements(INPUT_RECORD.LAYOUT) - .map(INPUT_RECORD::new) - .limit(len) - .toArray(INPUT_RECORD[]::new); - } - - public static String getLastErrorMessage() { - int errorCode = GetLastError(); - return getErrorMessage(errorCode); - } - - public static String getErrorMessage(int errorCode) { - int bufferSize = 160; - try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) { - java.lang.foreign.MemorySegment data = arena.allocate(bufferSize); - FormatMessageW( - FORMAT_MESSAGE_FROM_SYSTEM, - java.lang.foreign.MemorySegment.NULL, - errorCode, - 0, - data, - bufferSize, - java.lang.foreign.MemorySegment.NULL); - return new String(data.toArray(java.lang.foreign.ValueLayout.JAVA_BYTE), StandardCharsets.UTF_16LE).trim(); - } - } - - private static final java.lang.foreign.SymbolLookup SYMBOL_LOOKUP; - - static { - System.loadLibrary("msvcrt"); - System.loadLibrary("Kernel32"); - SYMBOL_LOOKUP = java.lang.foreign.SymbolLookup.loaderLookup(); - } - - static MethodHandle downcallHandle(String name, java.lang.foreign.FunctionDescriptor fdesc) { - return SYMBOL_LOOKUP - .find(name) - .map(addr -> java.lang.foreign.Linker.nativeLinker().downcallHandle(addr, fdesc)) - .orElse(null); - } - - static final java.lang.foreign.ValueLayout.OfBoolean C_BOOL$LAYOUT = java.lang.foreign.ValueLayout.JAVA_BOOLEAN; - static final java.lang.foreign.ValueLayout.OfByte C_CHAR$LAYOUT = java.lang.foreign.ValueLayout.JAVA_BYTE; - static final java.lang.foreign.ValueLayout.OfChar C_WCHAR$LAYOUT = java.lang.foreign.ValueLayout.JAVA_CHAR; - static final java.lang.foreign.ValueLayout.OfShort C_SHORT$LAYOUT = java.lang.foreign.ValueLayout.JAVA_SHORT; - static final java.lang.foreign.ValueLayout.OfShort C_WORD$LAYOUT = java.lang.foreign.ValueLayout.JAVA_SHORT; - static final java.lang.foreign.ValueLayout.OfInt C_DWORD$LAYOUT = java.lang.foreign.ValueLayout.JAVA_INT; - static final java.lang.foreign.ValueLayout.OfInt C_INT$LAYOUT = java.lang.foreign.ValueLayout.JAVA_INT; - static final java.lang.foreign.ValueLayout.OfLong C_LONG$LAYOUT = java.lang.foreign.ValueLayout.JAVA_LONG; - static final java.lang.foreign.ValueLayout.OfLong C_LONG_LONG$LAYOUT = java.lang.foreign.ValueLayout.JAVA_LONG; - static final java.lang.foreign.ValueLayout.OfFloat C_FLOAT$LAYOUT = java.lang.foreign.ValueLayout.JAVA_FLOAT; - static final java.lang.foreign.ValueLayout.OfDouble C_DOUBLE$LAYOUT = java.lang.foreign.ValueLayout.JAVA_DOUBLE; - static final java.lang.foreign.AddressLayout C_POINTER$LAYOUT = java.lang.foreign.ValueLayout.ADDRESS; - - static final MethodHandle WaitForSingleObject$MH = downcallHandle( - "WaitForSingleObject", - java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT, C_INT$LAYOUT)); - static final MethodHandle GetStdHandle$MH = - downcallHandle("GetStdHandle", java.lang.foreign.FunctionDescriptor.of(C_POINTER$LAYOUT, C_INT$LAYOUT)); - static final MethodHandle FormatMessageW$MH = downcallHandle( - "FormatMessageW", - java.lang.foreign.FunctionDescriptor.of( - C_INT$LAYOUT, - C_INT$LAYOUT, - C_POINTER$LAYOUT, - C_INT$LAYOUT, - C_INT$LAYOUT, - C_POINTER$LAYOUT, - C_INT$LAYOUT, - C_POINTER$LAYOUT)); - static final MethodHandle SetConsoleTextAttribute$MH = downcallHandle( - "SetConsoleTextAttribute", - java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT, C_SHORT$LAYOUT)); - static final MethodHandle SetConsoleMode$MH = downcallHandle( - "SetConsoleMode", java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT, C_INT$LAYOUT)); - static final MethodHandle GetConsoleMode$MH = downcallHandle( - "GetConsoleMode", - java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT)); - - static final MethodHandle SetConsoleTitleW$MH = - downcallHandle("SetConsoleTitleW", java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT)); - static final MethodHandle SetConsoleCursorPosition$MH = downcallHandle( - "SetConsoleCursorPosition", - java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT, COORD.LAYOUT)); - static final MethodHandle FillConsoleOutputCharacterW$MH = downcallHandle( - "FillConsoleOutputCharacterW", - java.lang.foreign.FunctionDescriptor.of( - C_INT$LAYOUT, C_POINTER$LAYOUT, C_WCHAR$LAYOUT, C_INT$LAYOUT, COORD.LAYOUT, C_POINTER$LAYOUT)); - static final MethodHandle FillConsoleOutputAttribute$MH = downcallHandle( - "FillConsoleOutputAttribute", - java.lang.foreign.FunctionDescriptor.of( - C_INT$LAYOUT, C_POINTER$LAYOUT, C_SHORT$LAYOUT, C_INT$LAYOUT, COORD.LAYOUT, C_POINTER$LAYOUT)); - static final MethodHandle WriteConsoleW$MH = downcallHandle( - "WriteConsoleW", - java.lang.foreign.FunctionDescriptor.of( - C_INT$LAYOUT, - C_POINTER$LAYOUT, - C_POINTER$LAYOUT, - C_INT$LAYOUT, - C_POINTER$LAYOUT, - C_POINTER$LAYOUT)); - - static final MethodHandle ReadConsoleInputW$MH = downcallHandle( - "ReadConsoleInputW", - java.lang.foreign.FunctionDescriptor.of( - C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT, C_INT$LAYOUT, C_POINTER$LAYOUT)); - static final MethodHandle PeekConsoleInputW$MH = downcallHandle( - "PeekConsoleInputW", - java.lang.foreign.FunctionDescriptor.of( - C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT, C_INT$LAYOUT, C_POINTER$LAYOUT)); - - static final MethodHandle GetConsoleScreenBufferInfo$MH = downcallHandle( - "GetConsoleScreenBufferInfo", - java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT, C_POINTER$LAYOUT)); - - static final MethodHandle ScrollConsoleScreenBufferW$MH = downcallHandle( - "ScrollConsoleScreenBufferW", - java.lang.foreign.FunctionDescriptor.of( - C_INT$LAYOUT, - C_POINTER$LAYOUT, - C_POINTER$LAYOUT, - C_POINTER$LAYOUT, - COORD.LAYOUT, - C_POINTER$LAYOUT)); - static final MethodHandle GetLastError$MH = - downcallHandle("GetLastError", java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT)); - static final MethodHandle GetFileType$MH = - downcallHandle("GetFileType", java.lang.foreign.FunctionDescriptor.of(C_INT$LAYOUT, C_POINTER$LAYOUT)); - static final MethodHandle _get_osfhandle$MH = - downcallHandle("_get_osfhandle", java.lang.foreign.FunctionDescriptor.of(C_POINTER$LAYOUT, C_INT$LAYOUT)); - - public static final class INPUT_RECORD { - static final java.lang.foreign.MemoryLayout LAYOUT = java.lang.foreign.MemoryLayout.structLayout( - java.lang.foreign.ValueLayout.JAVA_SHORT.withName("EventType"), - java.lang.foreign.ValueLayout.JAVA_SHORT, // padding - java.lang.foreign.MemoryLayout.unionLayout( - KEY_EVENT_RECORD.LAYOUT.withName("KeyEvent"), - MOUSE_EVENT_RECORD.LAYOUT.withName("MouseEvent"), - WINDOW_BUFFER_SIZE_RECORD.LAYOUT.withName("WindowBufferSizeEvent"), - MENU_EVENT_RECORD.LAYOUT.withName("MenuEvent"), - FOCUS_EVENT_RECORD.LAYOUT.withName("FocusEvent")) - .withName("Event")); - static final VarHandle EventType$VH = varHandle(LAYOUT, "EventType"); - static final long Event$OFFSET = byteOffset(LAYOUT, "Event"); - - private final java.lang.foreign.MemorySegment seg; - - public INPUT_RECORD() { - this(java.lang.foreign.Arena.ofAuto()); - } - - public INPUT_RECORD(java.lang.foreign.Arena arena) { - this(arena.allocate(LAYOUT)); - } - - public INPUT_RECORD(java.lang.foreign.MemorySegment seg) { - this.seg = seg; - } - - public short eventType() { - return (short) EventType$VH.get(seg); - } - - public KEY_EVENT_RECORD keyEvent() { - return new KEY_EVENT_RECORD(seg, Event$OFFSET); - } - - public MOUSE_EVENT_RECORD mouseEvent() { - return new MOUSE_EVENT_RECORD(seg, Event$OFFSET); - } - - public FOCUS_EVENT_RECORD focusEvent() { - return new FOCUS_EVENT_RECORD(seg, Event$OFFSET); - } - } - - public static final class MENU_EVENT_RECORD { - - static final java.lang.foreign.GroupLayout LAYOUT = - java.lang.foreign.MemoryLayout.structLayout(C_DWORD$LAYOUT.withName("dwCommandId")); - static final VarHandle COMMAND_ID = varHandle(LAYOUT, "dwCommandId"); - - private final java.lang.foreign.MemorySegment seg; - - public MENU_EVENT_RECORD() { - this(java.lang.foreign.Arena.ofAuto()); - } - - public MENU_EVENT_RECORD(java.lang.foreign.Arena arena) { - this(arena.allocate(LAYOUT)); - } - - public MENU_EVENT_RECORD(java.lang.foreign.MemorySegment seg) { - this.seg = seg; - } - - public int commandId() { - return (int) MENU_EVENT_RECORD.COMMAND_ID.get(seg); - } - - public void commandId(int commandId) { - MENU_EVENT_RECORD.COMMAND_ID.set(seg, commandId); - } - } - - public static final class FOCUS_EVENT_RECORD { - - static final java.lang.foreign.GroupLayout LAYOUT = - java.lang.foreign.MemoryLayout.structLayout(C_INT$LAYOUT.withName("bSetFocus")); - static final VarHandle SET_FOCUS = varHandle(LAYOUT, "bSetFocus"); - - private final java.lang.foreign.MemorySegment seg; - - public FOCUS_EVENT_RECORD() { - this(java.lang.foreign.Arena.ofAuto()); - } - - public FOCUS_EVENT_RECORD(java.lang.foreign.Arena arena) { - this(arena.allocate(LAYOUT)); - } - - public FOCUS_EVENT_RECORD(java.lang.foreign.MemorySegment seg) { - this.seg = Objects.requireNonNull(seg); - } - - public FOCUS_EVENT_RECORD(java.lang.foreign.MemorySegment seg, long offset) { - this.seg = Objects.requireNonNull(seg).asSlice(offset, LAYOUT.byteSize()); - } - - public boolean setFocus() { - return ((int) FOCUS_EVENT_RECORD.SET_FOCUS.get(seg) != 0); - } - - public void setFocus(boolean setFocus) { - FOCUS_EVENT_RECORD.SET_FOCUS.set(seg, setFocus ? 1 : 0); - } - } - - public static final class WINDOW_BUFFER_SIZE_RECORD { - - static final java.lang.foreign.GroupLayout LAYOUT = - java.lang.foreign.MemoryLayout.structLayout(COORD.LAYOUT.withName("size")); - static final long SIZE_OFFSET = byteOffset(LAYOUT, "size"); - - private final java.lang.foreign.MemorySegment seg; - - public WINDOW_BUFFER_SIZE_RECORD() { - this(java.lang.foreign.Arena.ofAuto()); - } - - public WINDOW_BUFFER_SIZE_RECORD(java.lang.foreign.Arena arena) { - this(arena.allocate(LAYOUT)); - } - - public WINDOW_BUFFER_SIZE_RECORD(java.lang.foreign.MemorySegment seg) { - this.seg = seg; - } - - public COORD size() { - return new COORD(seg, SIZE_OFFSET); - } - - public String toString() { - return "WINDOW_BUFFER_SIZE_RECORD{size=" + this.size() + '}'; - } - } - - public static final class MOUSE_EVENT_RECORD { - - static final java.lang.foreign.MemoryLayout LAYOUT = java.lang.foreign.MemoryLayout.structLayout( - COORD.LAYOUT.withName("dwMousePosition"), - C_DWORD$LAYOUT.withName("dwButtonState"), - C_DWORD$LAYOUT.withName("dwControlKeyState"), - C_DWORD$LAYOUT.withName("dwEventFlags")); - static final long MOUSE_POSITION_OFFSET = byteOffset(LAYOUT, "dwMousePosition"); - static final VarHandle BUTTON_STATE = varHandle(LAYOUT, "dwButtonState"); - static final VarHandle CONTROL_KEY_STATE = varHandle(LAYOUT, "dwControlKeyState"); - static final VarHandle EVENT_FLAGS = varHandle(LAYOUT, "dwEventFlags"); - - private final java.lang.foreign.MemorySegment seg; - - public MOUSE_EVENT_RECORD() { - this(java.lang.foreign.Arena.ofAuto()); - } - - public MOUSE_EVENT_RECORD(java.lang.foreign.Arena arena) { - this(arena.allocate(LAYOUT)); - } - - public MOUSE_EVENT_RECORD(java.lang.foreign.MemorySegment seg) { - this.seg = Objects.requireNonNull(seg); - } - - public MOUSE_EVENT_RECORD(java.lang.foreign.MemorySegment seg, long offset) { - this.seg = Objects.requireNonNull(seg).asSlice(offset, LAYOUT.byteSize()); - } - - public COORD mousePosition() { - return new COORD(seg, MOUSE_POSITION_OFFSET); - } - - public int buttonState() { - return (int) BUTTON_STATE.get(seg); - } - - public int controlKeyState() { - return (int) CONTROL_KEY_STATE.get(seg); - } - - public int eventFlags() { - return (int) EVENT_FLAGS.get(seg); - } - - public String toString() { - return "MOUSE_EVENT_RECORD{mousePosition=" + mousePosition() + ", buttonState=" + buttonState() - + ", controlKeyState=" + controlKeyState() + ", eventFlags=" + eventFlags() + '}'; - } - } - - public static final class KEY_EVENT_RECORD { - - static final java.lang.foreign.MemoryLayout LAYOUT = java.lang.foreign.MemoryLayout.structLayout( - java.lang.foreign.ValueLayout.JAVA_INT.withName("bKeyDown"), - java.lang.foreign.ValueLayout.JAVA_SHORT.withName("wRepeatCount"), - java.lang.foreign.ValueLayout.JAVA_SHORT.withName("wVirtualKeyCode"), - java.lang.foreign.ValueLayout.JAVA_SHORT.withName("wVirtualScanCode"), - java.lang.foreign.MemoryLayout.unionLayout( - java.lang.foreign.ValueLayout.JAVA_CHAR.withName("UnicodeChar"), - java.lang.foreign.ValueLayout.JAVA_BYTE.withName("AsciiChar")) - .withName("uChar"), - java.lang.foreign.ValueLayout.JAVA_INT.withName("dwControlKeyState")); - static final VarHandle bKeyDown$VH = varHandle(LAYOUT, "bKeyDown"); - static final VarHandle wRepeatCount$VH = varHandle(LAYOUT, "wRepeatCount"); - static final VarHandle wVirtualKeyCode$VH = varHandle(LAYOUT, "wVirtualKeyCode"); - static final VarHandle wVirtualScanCode$VH = varHandle(LAYOUT, "wVirtualScanCode"); - static final VarHandle UnicodeChar$VH = varHandle(LAYOUT, "uChar", "UnicodeChar"); - static final VarHandle AsciiChar$VH = varHandle(LAYOUT, "uChar", "AsciiChar"); - static final VarHandle dwControlKeyState$VH = varHandle(LAYOUT, "dwControlKeyState"); - - final java.lang.foreign.MemorySegment seg; - - public KEY_EVENT_RECORD() { - this(java.lang.foreign.Arena.ofAuto()); - } - - public KEY_EVENT_RECORD(java.lang.foreign.Arena arena) { - this(arena.allocate(LAYOUT)); - } - - public KEY_EVENT_RECORD(java.lang.foreign.MemorySegment seg) { - this.seg = seg; - } - - public KEY_EVENT_RECORD(java.lang.foreign.MemorySegment seg, long offset) { - this.seg = Objects.requireNonNull(seg).asSlice(offset, LAYOUT.byteSize()); - } - - public boolean keyDown() { - return ((int) bKeyDown$VH.get(seg)) != 0; - } - - public int repeatCount() { - return (int) wRepeatCount$VH.get(seg); - } - - public short keyCode() { - return (short) wVirtualKeyCode$VH.get(seg); - } - - public short scanCode() { - return (short) wVirtualScanCode$VH.get(seg); - } - - public char uchar() { - return (char) UnicodeChar$VH.get(seg); - } - - public int controlKeyState() { - return (int) dwControlKeyState$VH.get(seg); - } - - public String toString() { - return "KEY_EVENT_RECORD{keyDown=" + this.keyDown() + ", repeatCount=" + this.repeatCount() + ", keyCode=" - + this.keyCode() + ", scanCode=" + this.scanCode() + ", uchar=" + this.uchar() - + ", controlKeyState=" - + this.controlKeyState() + '}'; - } - } - - public static final class CHAR_INFO { - - static final java.lang.foreign.GroupLayout LAYOUT = java.lang.foreign.MemoryLayout.structLayout( - java.lang.foreign.MemoryLayout.unionLayout( - C_WCHAR$LAYOUT.withName("UnicodeChar"), C_CHAR$LAYOUT.withName("AsciiChar")) - .withName("Char"), - C_WORD$LAYOUT.withName("Attributes")); - static final VarHandle UnicodeChar$VH = varHandle(LAYOUT, "Char", "UnicodeChar"); - static final VarHandle Attributes$VH = varHandle(LAYOUT, "Attributes"); - - final java.lang.foreign.MemorySegment seg; - - public CHAR_INFO() { - this(java.lang.foreign.Arena.ofAuto()); - } - - public CHAR_INFO(java.lang.foreign.Arena arena) { - this(arena.allocate(LAYOUT)); - } - - public CHAR_INFO(java.lang.foreign.Arena arena, char c, short a) { - this(arena); - UnicodeChar$VH.set(seg, c); - Attributes$VH.set(seg, a); - } - - public CHAR_INFO(java.lang.foreign.MemorySegment seg) { - this.seg = seg; - } - - public char unicodeChar() { - return (char) UnicodeChar$VH.get(seg); - } - } - - public static final class CONSOLE_SCREEN_BUFFER_INFO { - static final java.lang.foreign.GroupLayout LAYOUT = java.lang.foreign.MemoryLayout.structLayout( - COORD.LAYOUT.withName("dwSize"), - COORD.LAYOUT.withName("dwCursorPosition"), - C_WORD$LAYOUT.withName("wAttributes"), - SMALL_RECT.LAYOUT.withName("srWindow"), - COORD.LAYOUT.withName("dwMaximumWindowSize")); - static final long dwSize$OFFSET = byteOffset(LAYOUT, "dwSize"); - static final long dwCursorPosition$OFFSET = byteOffset(LAYOUT, "dwCursorPosition"); - static final VarHandle wAttributes$VH = varHandle(LAYOUT, "wAttributes"); - static final long srWindow$OFFSET = byteOffset(LAYOUT, "srWindow"); - - private final java.lang.foreign.MemorySegment seg; - - public CONSOLE_SCREEN_BUFFER_INFO() { - this(java.lang.foreign.Arena.ofAuto()); - } - - public CONSOLE_SCREEN_BUFFER_INFO(java.lang.foreign.Arena arena) { - this(arena.allocate(LAYOUT)); - } - - public CONSOLE_SCREEN_BUFFER_INFO(java.lang.foreign.MemorySegment seg) { - this.seg = seg; - } - - public COORD size() { - return new COORD(seg, dwSize$OFFSET); - } - - public COORD cursorPosition() { - return new COORD(seg, dwCursorPosition$OFFSET); - } - - public short attributes() { - return (short) wAttributes$VH.get(seg); - } - - public SMALL_RECT window() { - return new SMALL_RECT(seg, srWindow$OFFSET); - } - - public int windowWidth() { - return this.window().width() + 1; - } - - public int windowHeight() { - return this.window().height() + 1; - } - - public void attributes(short attr) { - wAttributes$VH.set(seg, attr); - } - } - - public static final class COORD { - - static final java.lang.foreign.GroupLayout LAYOUT = - java.lang.foreign.MemoryLayout.structLayout(C_SHORT$LAYOUT.withName("x"), C_SHORT$LAYOUT.withName("y")); - static final VarHandle x$VH = varHandle(LAYOUT, "x"); - static final VarHandle y$VH = varHandle(LAYOUT, "y"); - - private final java.lang.foreign.MemorySegment seg; - - public COORD() { - this(java.lang.foreign.Arena.ofAuto()); - } - - public COORD(java.lang.foreign.Arena arena) { - this(arena.allocate(LAYOUT)); - } - - public COORD(java.lang.foreign.Arena arena, short x, short y) { - this(arena.allocate(LAYOUT)); - x(x); - y(y); - } - - public COORD(java.lang.foreign.MemorySegment seg) { - this.seg = seg; - } - - public COORD(java.lang.foreign.MemorySegment seg, long offset) { - this.seg = Objects.requireNonNull(seg).asSlice(offset, LAYOUT.byteSize()); - } - - public short x() { - return (short) COORD.x$VH.get(seg); - } - - public void x(short x) { - COORD.x$VH.set(seg, x); - } - - public short y() { - return (short) COORD.y$VH.get(seg); - } - - public void y(short y) { - COORD.y$VH.set(seg, y); - } - - public COORD copy(java.lang.foreign.Arena arena) { - return new COORD(arena.allocate(LAYOUT).copyFrom(seg)); - } - } - - public static final class SMALL_RECT { - - static final java.lang.foreign.GroupLayout LAYOUT = java.lang.foreign.MemoryLayout.structLayout( - C_SHORT$LAYOUT.withName("Left"), - C_SHORT$LAYOUT.withName("Top"), - C_SHORT$LAYOUT.withName("Right"), - C_SHORT$LAYOUT.withName("Bottom")); - static final VarHandle Left$VH = varHandle(LAYOUT, "Left"); - static final VarHandle Top$VH = varHandle(LAYOUT, "Top"); - static final VarHandle Right$VH = varHandle(LAYOUT, "Right"); - static final VarHandle Bottom$VH = varHandle(LAYOUT, "Bottom"); - - private final java.lang.foreign.MemorySegment seg; - - public SMALL_RECT() { - this(java.lang.foreign.Arena.ofAuto()); - } - - public SMALL_RECT(java.lang.foreign.Arena arena) { - this(arena.allocate(LAYOUT)); - } - - public SMALL_RECT(java.lang.foreign.Arena arena, SMALL_RECT rect) { - this(arena); - left(rect.left()); - right(rect.right()); - top(rect.top()); - bottom(rect.bottom()); - } - - public SMALL_RECT(java.lang.foreign.MemorySegment seg, long offset) { - this(seg.asSlice(offset, LAYOUT.byteSize())); - } - - public SMALL_RECT(java.lang.foreign.MemorySegment seg) { - this.seg = seg; - } - - public short left() { - return (short) Left$VH.get(seg); - } - - public short top() { - return (short) Top$VH.get(seg); - } - - public short right() { - return (short) Right$VH.get(seg); - } - - public short bottom() { - return (short) Bottom$VH.get(seg); - } - - public short width() { - return (short) (this.right() - this.left()); - } - - public short height() { - return (short) (this.bottom() - this.top()); - } - - public void left(short l) { - Left$VH.set(seg, l); - } - - public void top(short t) { - Top$VH.set(seg, t); - } - - public void right(short r) { - Right$VH.set(seg, r); - } - - public void bottom(short b) { - Bottom$VH.set(seg, b); - } - - public SMALL_RECT copy(java.lang.foreign.Arena arena) { - return new SMALL_RECT(arena.allocate(LAYOUT).copyFrom(seg)); - } - } - - static T requireNonNull(T obj, String symbolName) { - if (obj == null) { - throw new UnsatisfiedLinkError("unresolved symbol: " + symbolName); - } - return obj; - } - - static VarHandle varHandle(java.lang.foreign.MemoryLayout layout, String name) { - return lookupVarHandle( - layout, java.lang.foreign.MemoryLayout.PathElement.groupElement(name)); - } - - static VarHandle varHandle(java.lang.foreign.MemoryLayout layout, String e1, String name) { - return lookupVarHandle( - layout, - java.lang.foreign.MemoryLayout.PathElement.groupElement(e1), - java.lang.foreign.MemoryLayout.PathElement.groupElement(name)); - } - - static long byteOffset(java.lang.foreign.MemoryLayout layout, String name) { - return layout.byteOffset(java.lang.foreign.MemoryLayout.PathElement.groupElement(name)); - } - - static VarHandle lookupVarHandle(MemoryLayout layout, MemoryLayout.PathElement... element) { - VarHandle h = layout.varHandle(element); - - // the last parameter of the VarHandle is additional offset, hardcode zero: - h = MethodHandles.insertCoordinates(h, h.coordinateTypes().size() - 1, 0L); - - return h; - } -} diff --git a/src/jdk.internal.le/windows/classes/jdk/internal/console/NativeConsoleReader.java b/src/jdk.internal.le/windows/classes/jdk/internal/console/NativeConsoleReader.java index 3b7e1711aff8a..b07d4018b5773 100644 --- a/src/jdk.internal.le/windows/classes/jdk/internal/console/NativeConsoleReader.java +++ b/src/jdk.internal.le/windows/classes/jdk/internal/console/NativeConsoleReader.java @@ -3,25 +3,7 @@ import java.io.Reader; import java.io.Writer; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.foreign.Arena; -import java.lang.foreign.MemorySegment; import java.util.concurrent.atomic.AtomicInteger; -import static jdk.internal.console.Kernel32.ALT_FLAG; -import jdk.internal.console.Kernel32.CONSOLE_SCREEN_BUFFER_INFO; -import static jdk.internal.console.Kernel32.CTRL_FLAG; -import jdk.internal.console.Kernel32.INPUT_RECORD; -import static jdk.internal.console.Kernel32.INVALID_HANDLE_VALUE; -import static jdk.internal.console.Kernel32.KEY_EVENT; -import jdk.internal.console.Kernel32.KEY_EVENT_RECORD; -import static jdk.internal.console.Kernel32.LEFT_ALT_PRESSED; -import static jdk.internal.console.Kernel32.LEFT_CTRL_PRESSED; -import static jdk.internal.console.Kernel32.RIGHT_ALT_PRESSED; -import static jdk.internal.console.Kernel32.RIGHT_CTRL_PRESSED; -import static jdk.internal.console.Kernel32.SHIFT_FLAG; -import static jdk.internal.console.Kernel32.SHIFT_PRESSED; -import static jdk.internal.console.Kernel32.WINDOW_BUFFER_SIZE_EVENT; //partly based on JLine: /* @@ -35,79 +17,83 @@ public class NativeConsoleReader { - private static final int ENABLE_PROCESSED_INPUT = 0x0001; //for input - private static final int ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200; //for input - private static final int ENABLE_PROCESSED_OUTPUT = 0x0001; //for output - private static final int ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004; //for output + public static final int SHIFT_FLAG = 0x01; + public static final int ALT_FLAG = 0x02; + public static final int CTRL_FLAG = 0x04; + + public static final int RIGHT_ALT_PRESSED = 0x0001; + public static final int LEFT_ALT_PRESSED = 0x0002; + public static final int RIGHT_CTRL_PRESSED = 0x0004; + public static final int LEFT_CTRL_PRESSED = 0x0008; + public static final int SHIFT_PRESSED = 0x0010; public static char[] readline(Reader reader, Writer out, boolean password) throws IOException { - try (Arena arena = Arena.ofConfined()) { - MemorySegment inConsole = Kernel32.GetStdHandle(Kernel32.STD_INPUT_HANDLE); - MemorySegment originalInModeRef = arena.allocate(java.lang.foreign.ValueLayout.JAVA_INT); - Kernel32.GetConsoleMode(inConsole, originalInModeRef); - int originalInMode = originalInModeRef.get(java.lang.foreign.ValueLayout.JAVA_INT, 0); - Kernel32.SetConsoleMode(inConsole, ENABLE_PROCESSED_INPUT); - MemorySegment outConsole = Kernel32.GetStdHandle(Kernel32.STD_OUTPUT_HANDLE); - MemorySegment originalOutModeRef = arena.allocate(java.lang.foreign.ValueLayout.JAVA_INT); - Kernel32.GetConsoleMode(outConsole, originalOutModeRef); - int originalOutMode = originalOutModeRef.get(java.lang.foreign.ValueLayout.JAVA_INT, 0); - Kernel32.SetConsoleMode(outConsole, ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT); - CONSOLE_SCREEN_BUFFER_INFO consoleInfo = new Kernel32.CONSOLE_SCREEN_BUFFER_INFO(arena); - Kernel32.GetConsoleScreenBufferInfo(outConsole, consoleInfo); - try { - AtomicInteger width = new AtomicInteger(consoleInfo.size().x()); - int firstLineOffset = consoleInfo.cursorPosition().x(); - InputStream in = new ConsoleInputStream(inConsole, () -> { - Kernel32.GetConsoleScreenBufferInfo(outConsole, consoleInfo); - width.set(consoleInfo.size().x()); - }); - return SimpleConsoleReader.doRead(new InputStreamReader(in), out, password, firstLineOffset, () -> width.get()); - } finally { - Kernel32.SetConsoleMode(inConsole, originalInMode); - Kernel32.SetConsoleMode(outConsole, originalOutMode); - } + byte[] originalModes = switchToRaw(); + try { + AtomicInteger width = new AtomicInteger(terminalWidth()); + int firstLineOffset = cursorX(); + Reader in = new ConsoleInputStream(() -> { + width.set(cursorX()); + }); + return SimpleConsoleReader.doRead(in, out, password, firstLineOffset, () -> width.get()); + } finally { + restore(originalModes); } } - private static final class ConsoleInputStream extends InputStream { + static { + loadNativeLibrary(); + } + + @SuppressWarnings("restricted") + private static void loadNativeLibrary() { + System.loadLibrary("le"); + initIDs(); + } + + private static native void initIDs(); + private static native byte[] switchToRaw(); + private static native void restore(byte[] originalModes); + private static native int terminalWidth(); + private static native int cursorX(); + private static native Object readEvent(); + + public record KeyEvent(boolean keyDown, short keyCode, char uchar, int controlKeyState) {}///////////////////////////////////// + public record WindowSizeEvent() {} + + private static final class ConsoleInputStream extends Reader { - private final MemorySegment inConsole; private final Runnable refreshWidth; - private int[] backlog; + private char[] backlog; private int backlogIndex; - public ConsoleInputStream(MemorySegment inConsole, Runnable refreshWidth) { - this.inConsole = inConsole; + public ConsoleInputStream(Runnable refreshWidth) { this.refreshWidth = refreshWidth; } @Override - public int read() throws IOException { + public int read(char[] cbuf, int off, int len) throws IOException { + if (len == 0) { + return 0; + } + while (backlog == null || backlogIndex >= backlog.length) { - try (Arena arena = Arena.ofConfined()) { - INPUT_RECORD[] events; - if (inConsole != null - && inConsole.address() != INVALID_HANDLE_VALUE - && Kernel32.WaitForSingleObject(inConsole, 100) == 0) { //TODO: 100ms timeout sensible? - events = Kernel32.readConsoleInputHelper(arena, inConsole, 1, false); - } else { - return -1; + Object event = readEvent(); + switch (event) { + case null -> {} //continue + case KeyEvent keyEvent -> { + processKeyEvent( + keyEvent.keyDown(), keyEvent.keyCode(), keyEvent.uchar(), keyEvent.controlKeyState()); } - - for (INPUT_RECORD event : events) { - int eventType = event.eventType(); - if (eventType == KEY_EVENT) { - KEY_EVENT_RECORD keyEvent = event.keyEvent(); - processKeyEvent( - keyEvent.keyDown(), keyEvent.keyCode(), keyEvent.uchar(), keyEvent.controlKeyState()); - } else if (eventType == WINDOW_BUFFER_SIZE_EVENT) { - refreshWidth.run(); - return -1; //repaint - can be better? - } + case WindowSizeEvent evt -> { + refreshWidth.run(); + return -1; } + default -> throw new IllegalStateException("No other instances should be provided! Got: " + event.getClass()); } } - return backlog[backlogIndex++]; + cbuf[0] = backlog[backlogIndex++]; + return 1; } protected void processKeyEvent( @@ -178,7 +164,7 @@ protected void processKeyEvent( data.append(ch); // no such combination in Windows } } - backlog = new int[data.length()]; + backlog = new char[data.length()]; for (int i = 0; i < data.length(); i++) { backlog[i] = data.charAt(i); } @@ -240,6 +226,11 @@ protected String getEscapeSequence(short keyCode, int keyState) { } return escapeSequence; } + + @Override + public void close() throws IOException { + } + } } diff --git a/src/jdk.internal.le/windows/native/lible/NativeConsoleReader.cpp b/src/jdk.internal.le/windows/native/lible/NativeConsoleReader.cpp new file mode 100644 index 0000000000000..7616cd5c6b144 --- /dev/null +++ b/src/jdk.internal.le/windows/native/lible/NativeConsoleReader.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jdk_internal_console_NativeConsoleReader.h" + +#include +#include +//#include +//#include + +static jclass lastErrorExceptionClass; +static jmethodID lastErrorExceptionConstructor; + +static jclass KEY_EVENT_Class; +static jmethodID KEY_EVENT_Constructor; + +static jclass WINDOW_SIZE_EVENT_Class; +static jmethodID WINDOW_SIZE_EVENT_Constructor; + +static void throw_errno(JNIEnv *env); + +JNIEXPORT void JNICALL Java_jdk_internal_console_NativeConsoleReader_initIDs + (JNIEnv *env, jclass) { + jclass cls; + cls = env->FindClass("jdk/internal/console/LastErrorException"); + CHECK_NULL(cls); + lastErrorExceptionClass = (jclass) env->NewGlobalRef(cls); + lastErrorExceptionConstructor = env->GetMethodID(lastErrorExceptionClass, "", "(J)V"); + CHECK_NULL(lastErrorExceptionConstructor); + KEY_EVENT_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/console/NativeConsoleReader$KeyEvent")); + CHECK_NULL(KEY_EVENT_Class); + KEY_EVENT_Constructor = env->GetMethodID(KEY_EVENT_Class, "", "(ZSCI)V"); + CHECK_NULL(KEY_EVENT_Constructor); + WINDOW_SIZE_EVENT_Class = (jclass) env->NewGlobalRef(env->FindClass("jdk/internal/console/NativeConsoleReader$WindowSizeEvent")); + CHECK_NULL(WINDOW_SIZE_EVENT_Class); + WINDOW_SIZE_EVENT_Constructor = env->GetMethodID(WINDOW_SIZE_EVENT_Class, "", "()V"); + CHECK_NULL(WINDOW_SIZE_EVENT_Constructor); +} + +JNIEXPORT jbyteArray JNICALL Java_jdk_internal_console_NativeConsoleReader_switchToRaw + (JNIEnv *env, jclass) { + HANDLE inHandle = GetStdHandle(STD_INPUT_HANDLE); + DWORD origInMode; + + if (!GetConsoleMode(inHandle, &origInMode)) { + throw_errno(env); + return NULL; + } + + HANDLE outHandle = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD origOutMode; + + if (!GetConsoleMode(outHandle, &origOutMode)) { + throw_errno(env); + return NULL; + } + + if (!SetConsoleMode(inHandle, ENABLE_PROCESSED_INPUT)) { + throw_errno(env); + return NULL; + } + + if (!SetConsoleMode(outHandle, ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT)) { + throw_errno(env); + return NULL; + } + + jsize dword_size = (jsize) sizeof(DWORD); + jbyteArray result = env->NewByteArray(2 * dword_size); + + env->SetByteArrayRegion(result, 0, dword_size, (jbyte *) &origInMode); + env->SetByteArrayRegion(result, dword_size, dword_size, (jbyte *) &origOutMode); + + return result; +} + +JNIEXPORT void JNICALL Java_jdk_internal_console_NativeConsoleReader_restore + (JNIEnv *env, jclass, jbyteArray storedData) { + jsize dword_size = (jsize) sizeof(DWORD); + DWORD origInMode; + DWORD origOutMode; + + env->GetByteArrayRegion(storedData, 0, dword_size, (jbyte*) &origInMode); + env->GetByteArrayRegion(storedData, dword_size, dword_size, (jbyte*) &origOutMode); + + HANDLE inHandle = GetStdHandle(STD_INPUT_HANDLE); + + if (!SetConsoleMode(inHandle, origInMode)) { + throw_errno(env); + return ; + } + + HANDLE outHandle = GetStdHandle(STD_OUTPUT_HANDLE); + + if (!SetConsoleMode(outHandle, origOutMode)) { + throw_errno(env); + return ; + } +} + +JNIEXPORT jint JNICALL Java_jdk_internal_console_NativeConsoleReader_terminalWidth + (JNIEnv *env, jclass) { + HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO buffer; + if (!GetConsoleScreenBufferInfo(h, &buffer)) { + DWORD error = GetLastError(); + jobject exc = env->NewObject(lastErrorExceptionClass, + lastErrorExceptionConstructor, + (jlong) error); + env->Throw((jthrowable) exc); + return -1; + } + return buffer.dwSize.X; +} + +JNIEXPORT jint JNICALL Java_jdk_internal_console_NativeConsoleReader_cursorX + (JNIEnv *env, jclass) { + HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_SCREEN_BUFFER_INFO buffer; + if (!GetConsoleScreenBufferInfo(h, &buffer)) { + DWORD error = GetLastError(); + jobject exc = env->NewObject(lastErrorExceptionClass, + lastErrorExceptionConstructor, + (jlong) error); + env->Throw((jthrowable) exc); + return -1; + } + return buffer.dwCursorPosition.X; +} + +JNIEXPORT jobject JNICALL Java_jdk_internal_console_NativeConsoleReader_readEvent + (JNIEnv *env, jclass) { + HANDLE h = GetStdHandle(STD_INPUT_HANDLE); + INPUT_RECORD buffer; + DWORD numberOfEventsRead; + if (!ReadConsoleInputW(h, &buffer, 1, &numberOfEventsRead)) { + throw_errno(env); + return NULL; + } + switch (buffer.EventType) { + case KEY_EVENT: { + jobject keyEvent = env->NewObject(KEY_EVENT_Class, + KEY_EVENT_Constructor, + buffer.Event.KeyEvent.bKeyDown, + buffer.Event.KeyEvent.wVirtualKeyCode, + buffer.Event.KeyEvent.uChar.UnicodeChar, + buffer.Event.KeyEvent.dwControlKeyState); + return keyEvent; + } + case WINDOW_BUFFER_SIZE_EVENT: { + jobject windowSizeEvent = env->NewObject(WINDOW_SIZE_EVENT_Class, + WINDOW_SIZE_EVENT_Constructor); + + return windowSizeEvent; + } + } + return NULL; +} + +/* + * Throws LastErrorException based on GetLastError: + */ +static void throw_errno(JNIEnv *env) { + DWORD error = GetLastError(); + jobject exc = env->NewObject(lastErrorExceptionClass, + lastErrorExceptionConstructor, + (jlong) error); + env->Throw((jthrowable) exc); +}