diff --git a/README.md b/README.md
index 79d04cad5..0e053b456 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,10 @@ The dependencies are minimal: you may use JLine without any dependency on *nix s
You can also use fine grained jars:
* `jline-terminal`: the `Terminal` api and implementations
* `jline-terminal-jansi`: terminal implementations leveraging the `Jansi` library
+* `jline-terminal-jni`: terminal implementations leveraging the JNI native library
* `jline-terminal-jna`: terminal implementations leveraging the `JNA` library
+* `jline-terminal-ffm`: terminal implementations leveraging the Foreign Functions & Mapping layer
+* `jline-native`: the native library
* `jline-reader`: the line reader (including completion, history, etc...)
* `jline-style`: styling api
* `jline-remote-ssh`: helpers for using jline with [Mina SSHD](http://mina.apache.org/sshd-project/)
diff --git a/demo/jline-repl.bat b/demo/jline-repl.bat
index c68fdbd03..f7a5a2bed 100644
--- a/demo/jline-repl.bat
+++ b/demo/jline-repl.bat
@@ -1,75 +1,75 @@
-@echo off
-
-set DIRNAME=%~dp0%
-set ROOTDIR=%DIRNAME%\..
-set TARGETDIR=%DIRNAME%target
-
-rem initialization
-if not exist %TARGETDIR%\lib (
- echo Build jline with maven before running the demo
- goto END
-)
-
-goto :SETUP_CLASSPATH
-
-: APPEND_TO_CLASSPATH
-set filename=%~1
-set cp=%cp%;%TARGETDIR%\lib\%filename%
-goto :EOF
-
-:SETUP_CLASSPATH
-set cp=%TARGETDIR%\classes
-rem JLINE
-pushd %TARGETDIR%\lib
-for %%G in (jline-*.jar) do call:APPEND_TO_CLASSPATH %%G
-rem Groovy
-for %%G in (groovy-*.jar) do call:APPEND_TO_CLASSPATH %%G
-for %%G in (ivy-*.jar) do call:APPEND_TO_CLASSPATH %%G
-
-set "opts=%JLINE_OPTS%"
-set "logconf=%DIRNAME%etc\logging.properties"
-:RUN_LOOP
- if "%1" == "jansi" goto :EXECUTE_JANSI
- if "%1" == "jna" goto :EXECUTE_JNA
- if "%1" == "debug" goto :EXECUTE_DEBUG
- if "%1" == "debugs" goto :EXECUTE_DEBUGS
- if "%1" == "verbose" goto :EXECUTE_VERBOSE
- if "%1" == "" goto :EXECUTE_MAIN
- set "opts=%opts% %~1"
- shift
- goto :RUN_LOOP
-
-:EXECUTE_JANSI
- for %%G in (jansi-*.jar) do call:APPEND_TO_CLASSPATH %%G
- shift
- goto :RUN_LOOP
-
-:EXECUTE_JNA
- for %%G in (jna-*.jar) do call:APPEND_TO_CLASSPATH %%G
- shift
- goto :RUN_LOOP
-
-:EXECUTE_DEBUG
- set "opts=%opts% -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
- shift
- goto :RUN_LOOP
-
-:EXECUTE_DEBUGS
- set "opts=%opts% -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"
- shift
- goto :RUN_LOOP
-
-:EXECUTE_VERBOSE
- set "logconf=%DIRNAME%etc\logging-verbose.properties"
- shift
- goto :RUN_LOOP
-
-:EXECUTE_MAIN
-popd
-
-rem Launching Groovy REPL...
-echo Launching Groovy REPL...
-echo Classpath: %cp%
-java -cp %cp% %opts% -Dgosh.home=%DIRNAME% -Djava.util.logging.config.file=%logconf% org.jline.demo.Repl
-
+@echo off
+
+set DIRNAME=%~dp0%
+set ROOTDIR=%DIRNAME%\..
+set TARGETDIR=%DIRNAME%target
+
+rem initialization
+if not exist %TARGETDIR%\lib (
+ echo Build jline with maven before running the demo
+ goto END
+)
+
+goto :SETUP_CLASSPATH
+
+: APPEND_TO_CLASSPATH
+set filename=%~1
+set cp=%cp%;%TARGETDIR%\lib\%filename%
+goto :EOF
+
+:SETUP_CLASSPATH
+set cp=%TARGETDIR%\classes
+rem JLINE
+pushd %TARGETDIR%\lib
+for %%G in (jline-*.jar) do call:APPEND_TO_CLASSPATH %%G
+rem Groovy
+for %%G in (groovy-*.jar) do call:APPEND_TO_CLASSPATH %%G
+for %%G in (ivy-*.jar) do call:APPEND_TO_CLASSPATH %%G
+
+set "opts=%JLINE_OPTS%"
+set "logconf=%DIRNAME%etc\logging.properties"
+:RUN_LOOP
+ if "%1" == "jansi" goto :EXECUTE_JANSI
+ if "%1" == "jna" goto :EXECUTE_JNA
+ if "%1" == "debug" goto :EXECUTE_DEBUG
+ if "%1" == "debugs" goto :EXECUTE_DEBUGS
+ if "%1" == "verbose" goto :EXECUTE_VERBOSE
+ if "%1" == "" goto :EXECUTE_MAIN
+ set "opts=%opts% %~1"
+ shift
+ goto :RUN_LOOP
+
+:EXECUTE_JANSI
+ for %%G in (jansi-*.jar) do call:APPEND_TO_CLASSPATH %%G
+ shift
+ goto :RUN_LOOP
+
+:EXECUTE_JNA
+ for %%G in (jna-*.jar) do call:APPEND_TO_CLASSPATH %%G
+ shift
+ goto :RUN_LOOP
+
+:EXECUTE_DEBUG
+ set "opts=%opts% -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
+ shift
+ goto :RUN_LOOP
+
+:EXECUTE_DEBUGS
+ set "opts=%opts% -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"
+ shift
+ goto :RUN_LOOP
+
+:EXECUTE_VERBOSE
+ set "logconf=%DIRNAME%etc\logging-verbose.properties"
+ shift
+ goto :RUN_LOOP
+
+:EXECUTE_MAIN
+popd
+
+rem Launching Groovy REPL...
+echo Launching Groovy REPL...
+echo Classpath: %cp%
+java -cp %cp% %opts% -Dgosh.home=%DIRNAME% -Djava.util.logging.config.file=%logconf% org.jline.demo.Repl
+
:END
\ No newline at end of file
diff --git a/demo/pom.xml b/demo/pom.xml
index 9c7ca7eea..8eb6eb17a 100644
--- a/demo/pom.xml
+++ b/demo/pom.xml
@@ -31,6 +31,10 @@
org.jline
jline-terminal-ffm
+
+ org.jline
+ jline-terminal-jni
+
org.jline
jline-terminal-jansi
diff --git a/jline/pom.xml b/jline/pom.xml
index c10bd7fa8..ef47dae02 100644
--- a/jline/pom.xml
+++ b/jline/pom.xml
@@ -68,6 +68,11 @@
jline-terminal
test
+
+ org.jline
+ jline-terminal-jni
+ test
+
org.jline
jline-terminal-jansi
@@ -139,6 +144,14 @@
false
${project.build.directory}/generated-sources
+
+ org.jline
+ jline-terminal-jni
+ sources
+ jar
+ false
+ ${project.build.directory}/generated-sources
+
org.jline
jline-terminal-jansi
@@ -213,6 +226,14 @@
${project.build.directory}/generated-resources
**/*.class
+
+ org.jline
+ jline-terminal-jni
+ jar
+ false
+ ${project.build.directory}/generated-resources
+ **/*.class
+
org.jline
jline-terminal-jansi
diff --git a/native/Makefile b/native/Makefile
index 08b450541..4b42b1bbc 100644
--- a/native/Makefile
+++ b/native/Makefile
@@ -23,6 +23,7 @@ linux-armv6-digest:=@sha256:7bad6ab302af34bdf6634c8c2b02c8dc6ac932c67da9ecc199c5
linux-x86-digest:=:latest
windows-static-x86-digest:=@sha256:99d7069789560ef77a7504ead4a2b5e3c245cb45a45f964c74fecbf649398d3a
windows-static-x64-digest:=@sha256:f159861bc80b29e5dafb223477167bec53ecec6cdacb051d31e90c5823542100
+windows-arm64-digest:=@sha256:f4b3c1a49ec8b53418cef1499dc3f9a54a5570b7a3ecdf42fc8c83eb94b01b7d
cross-build-digest:=@sha256:8dbaa86462270db93ae1b1b319bdd88d89272faf3a68632daf4fa36b414a326e
freebsd-crossbuild-digest:=@sha256:cda62697a15d8bdc0bc26e780b1771ee78f12c55e7d5813e62c478af5a747c43
mcandre-snek-digest:=@sha256:9f84e9fcdf66daafc1f1c3fb772a6c97977714e17800aeac2e3bbe5dc5039dd0
@@ -68,9 +69,9 @@ $(JLINENATIVE_OUT)/%.o: src/main/native/%.c
ifeq ($(OS_NAME), Windows)
$(JLINENATIVE_OUT)/$(LIBNAME): ducible
endif
-$(JLINENATIVE_OUT)/$(LIBNAME): $(JLINENATIVE_OUT)/jlinenative.o
+$(JLINENATIVE_OUT)/$(LIBNAME): $(JLINENATIVE_OUT)/jlinenative.o $(JLINENATIVE_OUT)/clibrary.o $(JLINENATIVE_OUT)/kernel32.o
@mkdir -p $(@D)
- $(CC) $(CCFLAGS) -o $@ $(JLINENATIVE_OUT)/jlinenative.o $(LINKFLAGS)
+ $(CC) $(CCFLAGS) -o $@ $(JLINENATIVE_OUT)/jlinenative.o $(JLINENATIVE_OUT)/clibrary.o $(JLINENATIVE_OUT)/kernel32.o $(LINKFLAGS)
ifeq ($(OS_NAME), Windows)
target/ducible/ducible $(JLINENATIVE_OUT)/$(LIBNAME)
endif
@@ -81,8 +82,11 @@ NATIVE_DLL:=$(NATIVE_DIR)/$(LIBNAME)
# For cross-compilation, install docker. See also https://github.com/dockcross/dockcross
# Disabled linux-armv6 build because of this issue; https://github.com/dockcross/dockcross/issues/190
-native-all: linux-x86 linux-x86_64 linux-arm linux-armv6 linux-armv7 \
- linux-arm64 linux-ppc64 win-x86 win-x86_64 mac-x86 mac-x86_64 mac-arm64 freebsd-x86 freebsd-x86_64
+native-all: \
+ linux-x86 linux-x86_64 linux-arm linux-armv6 linux-armv7 linux-arm64 linux-ppc64 linux-riscv64 \
+ win-x86 win-x86_64 win-arm64 \
+ mac-x86 mac-x86_64 mac-arm64 \
+ freebsd-x86 freebsd-x86_64
native: $(NATIVE_DLL)
@@ -139,6 +143,12 @@ target/dockcross/dockcross-windows-static-x64: dockcross
win-x86_64: download-includes target/dockcross/dockcross-windows-static-x64
target/dockcross/dockcross-windows-static-x64 bash -c 'make clean-native native CROSS_PREFIX=x86_64-w64-mingw32.static- OS_NAME=Windows OS_ARCH=x86_64'
+target/dockcross/dockcross-windows-arm64: dockcross
+ docker run --rm dockcross/windows-arm64$(windows-arm64-digest) > target/dockcross/dockcross-windows-arm64
+ chmod +x target/dockcross/dockcross-windows-arm64
+win-arm64: download-includes target/dockcross/dockcross-windows-arm64
+ target/dockcross/dockcross-windows-arm64 bash -c 'make clean-native native CROSS_PREFIX=aarch64-w64-mingw32- OS_NAME=Windows OS_ARCH=arm64'
+
mac-x86: download-includes
docker run -it --rm -v $$PWD:/workdir --user $$(id -u):$$(id -g) \
-e CROSS_TRIPLE=i386-apple-darwin multiarch/crossbuild$(cross-build-digest) make clean-native native OS_NAME=Mac OS_ARCH=x86
diff --git a/native/Makefile.common b/native/Makefile.common
index fdc17ff86..9c2fc01e3 100644
--- a/native/Makefile.common
+++ b/native/Makefile.common
@@ -17,7 +17,7 @@
# os=Default is meant to be generic unix/linux
-known_targets := Linux-x86 Linux-x86_64 Linux-arm Linux-armv6 Linux-armv7 Linux-android-arm Linux-ppc64 Mac-x86 Mac-x86_64 Mac-arm64 DragonFly-x86_64 FreeBSD-x86_64 OpenBSD-x86_64 Windows-x86 Windows-x86_64 SunOS-sparcv9 HPUX-ia64_32
+known_targets := Linux-x86 Linux-x86_64 Linux-arm Linux-armv6 Linux-armv7 Linux-android-arm Linux-arm64 Linux-ppc64 Linux-riscv64 Mac-x86 Mac-x86_64 Mac-arm64 DragonFly-x86_64 FreeBSD-x86_64 OpenBSD-x86_64 Windows-x86 Windows-x86_64 SunOS-sparcv9 HPUX-ia64_32
target := $(OS_NAME)-$(OS_ARCH)
ifeq (,$(findstring $(strip $(target)),$(known_targets)))
@@ -32,105 +32,96 @@ Default_STRIP := $(CROSS_PREFIX)strip
Default_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -Os -fPIC -fvisibility=hidden
Default_LINKFLAGS := -shared
Default_LIBNAME := libjlinenative.so
-Default_JANSI_FLAGS :=
Linux-x86_CC := $(CROSS_PREFIX)gcc
Linux-x86_STRIP := $(CROSS_PREFIX)strip
Linux-x86_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -Os -fPIC -m32 -fvisibility=hidden
Linux-x86_LINKFLAGS := -shared -static-libgcc
Linux-x86_LIBNAME := libjlinenative.so
-Linux-x86_JANSI_FLAGS :=
Linux-x86_64_CC := $(CROSS_PREFIX)gcc
Linux-x86_64_STRIP := $(CROSS_PREFIX)strip
Linux-x86_64_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -Os -fPIC -m64 -fvisibility=hidden
Linux-x86_64_LINKFLAGS := -shared -static-libgcc
Linux-x86_64_LIBNAME := libjlinenative.so
-Linux-x86_64_JANSI_FLAGS :=
Linux-arm_CC := $(CROSS_PREFIX)gcc
Linux-arm_STRIP := $(CROSS_PREFIX)strip
Linux-arm_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -Os -fPIC -mfloat-abi=softfp -mfpu=vfp -fvisibility=hidden
Linux-arm_LINKFLAGS := -shared -static-libgcc
Linux-arm_LIBNAME := libjlinenative.so
-Linux-arm_JANSI_FLAGS :=
Linux-armv6_CC := $(CROSS_PREFIX)gcc
Linux-armv6_STRIP := $(CROSS_PREFIX)strip
Linux-armv6_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -Os -mfloat-abi=hard -mfpu=vfp -fPIC -fvisibility=hidden
Linux-armv6_LINKFLAGS := -shared -static-libgcc
Linux-armv6_LIBNAME := libjlinenative.so
-Linux-armv6_JANSI_FLAGS :=
Linux-armv7_CC := $(CROSS_PREFIX)gcc
Linux-armv7_STRIP := $(CROSS_PREFIX)strip
Linux-armv7_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -Os -mfloat-abi=hard -mfpu=vfp -fPIC -fvisibility=hidden
Linux-armv7_LINKFLAGS := -shared -static-libgcc
Linux-armv7_LIBNAME := libjlinenative.so
-Linux-armv7_JANSI_FLAGS :=
Linux-arm64_CC := $(CROSS_PREFIX)gcc
Linux-arm64_STRIP := $(CROSS_PREFIX)strip
-Linux-arm64_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -Os -mfloat-abi=hard -mfpu=vfp -fPIC -fvisibility=hidden
+Linux-arm64_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -Os -march=armv8-a -fPIC -fvisibility=hidden
Linux-arm64_LINKFLAGS := -shared -static-libgcc
Linux-arm64_LIBNAME := libjlinenative.so
-Linux-arm64_JANSI_FLAGS :=
Linux-ppc64_CC := $(CROSS_PREFIX)gcc
Linux-ppc64_STRIP := $(CROSS_PREFIX)strip
Linux-ppc64_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -Os -fPIC -fvisibility=hidden
Linux-ppc64_LINKFLAGS := -shared -static-libgcc
Linux-ppc64_LIBNAME := libjlinenative.so
-Linux-ppc64_JANSI_FLAGS :=
+
+Linux-riscv64_CC := $(CROSS_PREFIX)gcc
+Linux-riscv64_STRIP := $(CROSS_PREFIX)strip
+Linux-riscv64_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -Os -march=rv64g -fPIC -fvisibility=hidden
+Linux-riscv64_LINKFLAGS := -shared -static-libgcc
+Linux-riscv64_LIBNAME := libjlinenative.so
DragonFly-x86_64_CC := $(CROSS_PREFIX)cc
DragonFly-x86_64_STRIP := $(CROSS_PREFIX)strip
DragonFly-x86_64_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -O2 -fPIC -fvisibility=hidden
DragonFly-x86_64_LINKFLAGS := -shared
DragonFly-x86_64_LIBNAME := libjlinenative.so
-DragonFly-x86_64_JANSI_FLAGS :=
FreeBSD-x86_CC := $(CROSS_PREFIX)gcc
FreeBSD-x86_STRIP := $(CROSS_PREFIX)strip
FreeBSD-x86_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -Os -fPIC -fvisibility=hidden
FreeBSD-x86_LINKFLAGS := -shared
FreeBSD-x86_LIBNAME := libjlinenative.so
-FreeBSD-x86_JANSI_FLAGS :=
FreeBSD-x86_64_CC := $(CROSS_PREFIX)gcc
FreeBSD-x86_64_STRIP := $(CROSS_PREFIX)strip
FreeBSD-x86_64_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -Os -fPIC -fvisibility=hidden
FreeBSD-x86_64_LINKFLAGS := -shared
FreeBSD-x86_64_LIBNAME := libjlinenative.so
-FreeBSD-x86_64_JANSI_FLAGS :=
OpenBSD-x86_64_CC := $(CROSS_PREFIX)gcc
OpenBSD-x86_64_STRIP := $(CROSS_PREFIX)strip
OpenBSD-x86_64_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -Os -fPIC -fvisibility=hidden
OpenBSD-x86_64_LINKFLAGS := -shared
OpenBSD-x86_64_LIBNAME := libjlinenative.so
-OpenBSD-x86_64_JANSI_FLAGS :=
SunOS-sparcv9_CC := $(CROSS_PREFIX)gcc
SunOS-sparcv9_STRIP := $(CROSS_PREFIX)strip
SunOS-sparcv9_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -O2s-fPIC -m64 -fvisibility=hidden
SunOS-sparcv9_LINKFLAGS := -shared -static-libgcc
SunOS-sparcv9_LIBNAME := libjlinenative.so
-SunOS-sparcv9_JANSI_FLAGS :=
HPUX-ia64_32_CC := cc
HPUX-ia64_32_STRIP := strip
HPUX-ia64_32_CCFLAGS := -Itarget/inc -Itarget/inc/unix +Osize +z -Bhidden
HPUX-ia64_32_LINKFLAGS := -b
-HPUX-ia64_32_LIBNAME := libjlinenative.so
-HPUX-ia64_32_JANSI_FLAGS :=
+SHPUX-ia64_32_LIBNAME := libjlinenative.so
Mac-x86_CC := gcc
Mac-x86_STRIP := strip -x
Mac-x86_CCFLAGS := -I$(JAVA_HOME)/include -Itarget/inc -Itarget/inc/unix -Os -fPIC -mmacosx-version-min=10.4 -fvisibility=hidden
Mac-x86_LINKFLAGS := -dynamiclib
Mac-x86_LIBNAME := libjlinenative.jnilib
-Mac-x86_JANSI_FLAGS := -DJANSI_ENABLE_LOCKING_STYLE=0
Mac-x86_64_CC := gcc -arch $(OS_ARCH)
Mac-x86_64_STRIP := strip -x
@@ -141,7 +132,6 @@ endif
Mac-x86_64_CCFLAGS := -I$(MAC_SDK)/System/Library/Frameworks/JavaVM.framework/Headers -Itarget/inc -Itarget/inc/unix -Os -fPIC -mmacosx-version-min=10.6 -fvisibility=hidden
Mac-x86_64_LINKFLAGS := -dynamiclib
Mac-x86_64_LIBNAME := libjlinenative.jnilib
-Mac-x86_64_JANSI_FLAGS :=
Mac-arm64_CC := $(CROSS_PREFIX)clang -v
Mac-arm64_STRIP := $(CROSS_PREFIX)strip -x
@@ -149,21 +139,18 @@ MAC_SDK := /usr/local/osxcross/SDK/MacOSX11.3.sdk/
Mac-arm64_CCFLAGS := -I$(MAC_SDK)/System/Library/Frameworks/JavaVM.framework/Headers -Itarget/inc -Itarget/inc/unix -Os -fPIC -mmacosx-version-min=11.0 -fvisibility=hidden
Mac-arm64_LINKFLAGS := -shared
Mac-arm64_LIBNAME := libjlinenative.jnilib
-Mac-arm64_JANSI_FLAGS :=
Windows-x86_CC := $(CROSS_PREFIX)gcc
Windows-x86_STRIP := $(CROSS_PREFIX)strip
Windows-x86_CCFLAGS := -D_JNI_IMPLEMENTATION_ -Itarget/inc -Itarget/inc/windows -Os
Windows-x86_LINKFLAGS := -Wl,--kill-at -shared -static-libgcc
Windows-x86_LIBNAME := jlinenative.dll
-Windows-x86_JANSI_FLAGS :=
Windows-x86_64_CC := $(CROSS_PREFIX)gcc
Windows-x86_64_STRIP := $(CROSS_PREFIX)strip
Windows-x86_64_CCFLAGS := -D_JNI_IMPLEMENTATION_ -Itarget/inc -Itarget/inc/windows -Os
Windows-x86_64_LINKFLAGS := -Wl,--kill-at -shared -static-libgcc
Windows-x86_64_LIBNAME := jlinenative.dll
-Windows-x86_64_JANSI_FLAGS :=
CC := $($(target)_CC)
diff --git a/native/src/main/java/org/jline/nativ/CLibrary.java b/native/src/main/java/org/jline/nativ/CLibrary.java
new file mode 100644
index 000000000..bc69f59d5
--- /dev/null
+++ b/native/src/main/java/org/jline/nativ/CLibrary.java
@@ -0,0 +1,144 @@
+/*
+ * 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 org.jline.nativ;
+
+/**
+ * Interface to access some low level POSIX functions,.
+ *
+ * @see JLineNativeLoader
+ */
+@SuppressWarnings("unused")
+public class CLibrary {
+
+ //
+ // Initialization
+ //
+
+ static {
+ if (JLineNativeLoader.initialize()) {
+ init();
+ }
+ }
+
+ private static native void init();
+
+ //
+ // Constants
+ //
+
+ public static int TCSANOW;
+ public static int TCSADRAIN;
+ public static int TCSAFLUSH;
+ public static long TIOCGWINSZ;
+ public static long TIOCSWINSZ;
+
+ /**
+ * test whether a file descriptor refers to a terminal
+ *
+ * @param fd file descriptor
+ * @return isatty() returns 1 if fd is an open file descriptor referring to a
+ * terminal; otherwise 0 is returned, and errno is set to indicate the
+ * error
+ * @see ISATTY(3) man-page
+ * @see ISATTY(3P) man-page
+ */
+ public static native int isatty(int fd);
+
+ public static native String ttyname(int filedes);
+
+ /**
+ * The openpty() function finds an available pseudoterminal and returns
+ * file descriptors for the master and slave in amaster and aslave.
+ *
+ * @param amaster master return value
+ * @param aslave slave return value
+ * @param name filename return value
+ * @param termios optional pty attributes
+ * @param winsize optional size
+ * @return 0 on success
+ * @see OPENPTY(3) man-page
+ */
+ public static native int openpty(int[] amaster, int[] aslave, byte[] name, Termios termios, WinSize winsize);
+
+ public static native int tcgetattr(int filedes, Termios termios);
+
+ public static native int tcsetattr(int filedes, int optional_actions, Termios termios);
+
+ /**
+ * Control a STREAMS device.
+ *
+ * @see IOCTL(3P) man-page
+ */
+ public static native int ioctl(int filedes, long request, int[] params);
+
+ public static native int ioctl(int filedes, long request, WinSize params);
+
+ public static short getTerminalWidth(int fd) {
+ WinSize sz = new WinSize();
+ ioctl(fd, TIOCGWINSZ, sz);
+ return sz.ws_col;
+ }
+
+ /**
+ * Window sizes.
+ *
+ * @see IOCTL_TTY(2) man-page
+ */
+ public static class WinSize {
+
+ static {
+ if (JLineNativeLoader.initialize()) {
+ init();
+ }
+ }
+
+ private static native void init();
+
+ public static int SIZEOF;
+
+ public short ws_row;
+ public short ws_col;
+ public short ws_xpixel;
+ public short ws_ypixel;
+
+ public WinSize() {}
+
+ public WinSize(short ws_row, short ws_col) {
+ this.ws_row = ws_row;
+ this.ws_col = ws_col;
+ }
+ }
+
+ /**
+ * termios structure for termios functions, describing a general terminal interface that is
+ * provided to control asynchronous communications ports
+ *
+ * @see TERMIOS(3) man-page
+ */
+ public static class Termios {
+
+ static {
+ if (JLineNativeLoader.initialize()) {
+ init();
+ }
+ }
+
+ private static native void init();
+
+ public static int SIZEOF;
+
+ public long c_iflag;
+ public long c_oflag;
+ public long c_cflag;
+ public long c_lflag;
+ public byte[] c_cc = new byte[32];
+ public long c_ispeed;
+ public long c_ospeed;
+ }
+}
diff --git a/native/src/main/java/org/jline/nativ/Kernel32.java b/native/src/main/java/org/jline/nativ/Kernel32.java
new file mode 100644
index 000000000..66a525ffc
--- /dev/null
+++ b/native/src/main/java/org/jline/nativ/Kernel32.java
@@ -0,0 +1,533 @@
+/*
+ * 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 org.jline.nativ;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Interface to access Win32 base APIs.
+ */
+@SuppressWarnings("unused")
+public class Kernel32 {
+
+ static {
+ if (JLineNativeLoader.initialize()) {
+ init();
+ }
+ }
+
+ private static native void init();
+
+ public static short FOREGROUND_BLUE;
+ public static short FOREGROUND_GREEN;
+ public static short FOREGROUND_RED;
+ public static short FOREGROUND_INTENSITY;
+ public static short BACKGROUND_BLUE;
+ public static short BACKGROUND_GREEN;
+ public static short BACKGROUND_RED;
+ public static short BACKGROUND_INTENSITY;
+ public static short COMMON_LVB_LEADING_BYTE;
+ public static short COMMON_LVB_TRAILING_BYTE;
+ public static short COMMON_LVB_GRID_HORIZONTAL;
+ public static short COMMON_LVB_GRID_LVERTICAL;
+ public static short COMMON_LVB_GRID_RVERTICAL;
+ public static short COMMON_LVB_REVERSE_VIDEO;
+ public static short COMMON_LVB_UNDERSCORE;
+ public static int FORMAT_MESSAGE_FROM_SYSTEM;
+ public static int STD_INPUT_HANDLE;
+ public static int STD_OUTPUT_HANDLE;
+ public static int STD_ERROR_HANDLE;
+ public static int INVALID_HANDLE_VALUE;
+
+ public static native long malloc(long size);
+
+ public static native void free(long ptr);
+
+ /**
+ * http://msdn.microsoft.com/en-us/library/ms686311%28VS.85%29.aspx
+ */
+ public static class SMALL_RECT {
+ static {
+ if (JLineNativeLoader.initialize()) {
+ init();
+ }
+ }
+
+ private static native void init();
+
+ public static int SIZEOF;
+
+ public short left;
+ public short top;
+ public short right;
+ public short bottom;
+
+ public short width() {
+ return (short) (right - left);
+ }
+
+ public short height() {
+ return (short) (bottom - top);
+ }
+
+ public SMALL_RECT copy() {
+ SMALL_RECT rc = new SMALL_RECT();
+ rc.left = left;
+ rc.top = top;
+ rc.right = right;
+ rc.bottom = bottom;
+ return rc;
+ }
+ }
+
+ /**
+ * see http://msdn.microsoft.com/en-us/library/ms686047%28VS.85%29.aspx
+ */
+ public static native int SetConsoleTextAttribute(long consoleOutput, short attributes);
+
+ public static class COORD {
+
+ static {
+ if (JLineNativeLoader.initialize()) {
+ init();
+ }
+ }
+
+ private static native void init();
+
+ public static int SIZEOF;
+
+ public short x;
+ public short y;
+
+ public COORD copy() {
+ COORD rc = new COORD();
+ rc.x = x;
+ rc.y = y;
+ return rc;
+ }
+ }
+
+ /**
+ * http://msdn.microsoft.com/en-us/library/ms682093%28VS.85%29.aspx
+ */
+ public static class CONSOLE_SCREEN_BUFFER_INFO {
+
+ static {
+ if (JLineNativeLoader.initialize()) {
+ init();
+ }
+ }
+
+ private static native void init();
+
+ public static int SIZEOF;
+
+ public COORD size = new COORD();
+ public COORD cursorPosition = new COORD();
+ public short attributes;
+ public SMALL_RECT window = new SMALL_RECT();
+ public COORD maximumWindowSize = new COORD();
+
+ public int windowWidth() {
+ return window.width() + 1;
+ }
+
+ public int windowHeight() {
+ return window.height() + 1;
+ }
+ }
+
+ // DWORD WINAPI WaitForSingleObject(
+ // _In_ HANDLE hHandle,
+ // _In_ DWORD dwMilliseconds
+ // );
+ public static native int WaitForSingleObject(long hHandle, int dwMilliseconds);
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms724211%28VS.85%29.aspx
+ */
+ public static native int CloseHandle(long handle);
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms679360(VS.85).aspx
+ */
+ public static native int GetLastError();
+
+ public static native int FormatMessageW(
+ int flags, long source, int messageId, int languageId, byte[] buffer, int size, long[] args);
+
+ /**
+ * See: http://msdn.microsoft.com/en-us/library/ms683171%28VS.85%29.aspx
+ */
+ public static native int GetConsoleScreenBufferInfo(
+ long consoleOutput, CONSOLE_SCREEN_BUFFER_INFO consoleScreenBufferInfo);
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms683231%28VS.85%29.aspx
+ */
+ public static native long GetStdHandle(int stdHandle);
+
+ /**
+ * http://msdn.microsoft.com/en-us/library/ms686025%28VS.85%29.aspx
+ */
+ public static native int SetConsoleCursorPosition(long consoleOutput, COORD cursorPosition);
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms682663%28VS.85%29.aspx
+ */
+ public static native int FillConsoleOutputCharacterW(
+ long consoleOutput, char character, int length, COORD writeCoord, int[] numberOfCharsWritten);
+
+ /**
+ * see: https://msdn.microsoft.com/en-us/library/ms682662%28VS.85%29.aspx
+ */
+ public static native int FillConsoleOutputAttribute(
+ long consoleOutput, short attribute, int length, COORD writeCoord, int[] numberOfAttrsWritten);
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms687401(v=VS.85).aspx
+ */
+ public static native int WriteConsoleW(
+ long consoleOutput, char[] buffer, int numberOfCharsToWrite, int[] numberOfCharsWritten, long reserved);
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms683167%28VS.85%29.aspx
+ */
+ public static native int GetConsoleMode(long handle, int[] mode);
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms686033%28VS.85%29.aspx
+ */
+ public static native int SetConsoleMode(long handle, int mode);
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/078sfkak(VS.80).aspx
+ */
+ public static native int _getch();
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms686050%28VS.85%29.aspx
+ *
+ * @return 0 if title was set successfully
+ */
+ public static native int SetConsoleTitle(String title);
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms683169(v=VS.85).aspx
+ *
+ * @return the current output code page
+ */
+ public static native int GetConsoleOutputCP();
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms686036(v=VS.85).aspx
+ *
+ * @return non 0 if code page was set
+ */
+ public static native int SetConsoleOutputCP(int codePageID);
+
+ /**
+ * see: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682013(v=vs.85).aspx
+ */
+ public static class CHAR_INFO {
+
+ static {
+ JLineNativeLoader.initialize();
+ init();
+ }
+
+ private static native void init();
+
+ public static int SIZEOF;
+
+ public short attributes;
+ public char unicodeChar;
+ }
+
+ /**
+ * see: https://msdn.microsoft.com/en-us/library/windows/desktop/ms685107(v=vs.85).aspx
+ */
+ public static native int ScrollConsoleScreenBuffer(
+ long consoleOutput,
+ SMALL_RECT scrollRectangle,
+ SMALL_RECT clipRectangle,
+ COORD destinationOrigin,
+ CHAR_INFO fill);
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms684166(v=VS.85).aspx
+ */
+ public static class KEY_EVENT_RECORD {
+
+ static {
+ if (JLineNativeLoader.initialize()) {
+ init();
+ }
+ }
+
+ private static native void init();
+
+ public static int SIZEOF;
+ public static int CAPSLOCK_ON;
+ public static int NUMLOCK_ON;
+ public static int SCROLLLOCK_ON;
+ public static int ENHANCED_KEY;
+ public static int LEFT_ALT_PRESSED;
+ public static int LEFT_CTRL_PRESSED;
+ public static int RIGHT_ALT_PRESSED;
+ public static int RIGHT_CTRL_PRESSED;
+ public static int SHIFT_PRESSED;
+
+ public boolean keyDown;
+ public short repeatCount;
+ public short keyCode;
+ public short scanCode;
+ public char uchar;
+ public int controlKeyState;
+
+ public String toString() {
+ return "KEY_EVENT_RECORD{" + "keyDown="
+ + keyDown + ", repeatCount="
+ + repeatCount + ", keyCode="
+ + keyCode + ", scanCode="
+ + scanCode + ", uchar="
+ + uchar + ", controlKeyState="
+ + controlKeyState + '}';
+ }
+ }
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms684239(v=VS.85).aspx
+ */
+ public static class MOUSE_EVENT_RECORD {
+
+ static {
+ if (JLineNativeLoader.initialize()) {
+ init();
+ }
+ }
+
+ private static native void init();
+
+ public static int SIZEOF;
+ public static int FROM_LEFT_1ST_BUTTON_PRESSED;
+ public static int FROM_LEFT_2ND_BUTTON_PRESSED;
+ public static int FROM_LEFT_3RD_BUTTON_PRESSED;
+ public static int FROM_LEFT_4TH_BUTTON_PRESSED;
+ public static int RIGHTMOST_BUTTON_PRESSED;
+
+ public static int CAPSLOCK_ON;
+ public static int NUMLOCK_ON;
+ public static int SCROLLLOCK_ON;
+ public static int ENHANCED_KEY;
+ public static int LEFT_ALT_PRESSED;
+ public static int LEFT_CTRL_PRESSED;
+ public static int RIGHT_ALT_PRESSED;
+ public static int RIGHT_CTRL_PRESSED;
+ public static int SHIFT_PRESSED;
+
+ public static int DOUBLE_CLICK;
+ public static int MOUSE_HWHEELED;
+ public static int MOUSE_MOVED;
+ public static int MOUSE_WHEELED;
+
+ public COORD mousePosition = new COORD();
+ public int buttonState;
+ public int controlKeyState;
+ public int eventFlags;
+
+ public String toString() {
+ return "MOUSE_EVENT_RECORD{" + "mousePosition="
+ + mousePosition + ", buttonState="
+ + buttonState + ", controlKeyState="
+ + controlKeyState + ", eventFlags="
+ + eventFlags + '}';
+ }
+ }
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms687093(v=VS.85).aspx
+ */
+ public static class WINDOW_BUFFER_SIZE_RECORD {
+
+ static {
+ if (JLineNativeLoader.initialize()) {
+ init();
+ }
+ }
+
+ private static native void init();
+
+ public static int SIZEOF;
+
+ public COORD size = new COORD();
+
+ public String toString() {
+ return "WINDOW_BUFFER_SIZE_RECORD{size=" + size + '}';
+ }
+ }
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms683149(v=VS.85).aspx
+ */
+ public static class FOCUS_EVENT_RECORD {
+ static {
+ if (JLineNativeLoader.initialize()) {
+ init();
+ }
+ }
+
+ private static native void init();
+
+ public static int SIZEOF;
+ public boolean setFocus;
+ }
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms684213(v=VS.85).aspx
+ */
+ public static class MENU_EVENT_RECORD {
+ static {
+ if (JLineNativeLoader.initialize()) {
+ init();
+ }
+ }
+
+ private static native void init();
+
+ public static int SIZEOF;
+ public int commandId;
+ }
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms683499(v=VS.85).aspx
+ */
+ public static class INPUT_RECORD {
+
+ static {
+ if (JLineNativeLoader.initialize()) {
+ init();
+ }
+ }
+
+ private static native void init();
+
+ public static int SIZEOF;
+ public static short KEY_EVENT;
+ public static short MOUSE_EVENT;
+ public static short WINDOW_BUFFER_SIZE_EVENT;
+ public static short FOCUS_EVENT;
+ public static short MENU_EVENT;
+ public short eventType;
+ public KEY_EVENT_RECORD keyEvent = new KEY_EVENT_RECORD();
+ public MOUSE_EVENT_RECORD mouseEvent = new MOUSE_EVENT_RECORD();
+ public WINDOW_BUFFER_SIZE_RECORD windowBufferSizeEvent = new WINDOW_BUFFER_SIZE_RECORD();
+ public MENU_EVENT_RECORD menuEvent = new MENU_EVENT_RECORD();
+ public FOCUS_EVENT_RECORD focusEvent = new FOCUS_EVENT_RECORD();
+
+ public static native void memmove(INPUT_RECORD dest, long src, long size);
+ }
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms684961(v=VS.85).aspx
+ */
+ private static native int ReadConsoleInputW(long handle, long inputRecord, int length, int[] eventsCount);
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms684344(v=VS.85).aspx
+ */
+ private static native int PeekConsoleInputW(long handle, long inputRecord, int length, int[] eventsCount);
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms683207(v=VS.85).aspx
+ */
+ public static native int GetNumberOfConsoleInputEvents(long handle, int[] numberOfEvents);
+
+ /**
+ * see: http://msdn.microsoft.com/en-us/library/ms683147(v=VS.85).aspx
+ */
+ public static native int FlushConsoleInputBuffer(long handle);
+
+ /**
+ * Return console input events.
+ */
+ public static INPUT_RECORD[] readConsoleInputHelper(long handle, int count, boolean peek) throws IOException {
+ int[] length = new int[1];
+ int res;
+ long inputRecordPtr = 0;
+ try {
+ inputRecordPtr = malloc(INPUT_RECORD.SIZEOF * count);
+ if (inputRecordPtr == 0) {
+ throw new IOException("cannot allocate memory with JNI");
+ }
+ res = peek
+ ? PeekConsoleInputW(handle, inputRecordPtr, count, length)
+ : ReadConsoleInputW(handle, inputRecordPtr, count, length);
+ if (res == 0) {
+ int bufferSize = 160;
+ byte[] data = new byte[bufferSize];
+ FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, data, bufferSize, null);
+ String lastErrorMessage = new String(data, StandardCharsets.UTF_16LE).trim();
+ throw new IOException("ReadConsoleInputW failed: " + lastErrorMessage);
+ }
+ if (length[0] <= 0) {
+ return new INPUT_RECORD[0];
+ }
+ INPUT_RECORD[] records = new INPUT_RECORD[length[0]];
+ for (int i = 0; i < records.length; i++) {
+ records[i] = new INPUT_RECORD();
+ INPUT_RECORD.memmove(records[i], inputRecordPtr + i * INPUT_RECORD.SIZEOF, INPUT_RECORD.SIZEOF);
+ }
+ return records;
+ } finally {
+ if (inputRecordPtr != 0) {
+ free(inputRecordPtr);
+ }
+ }
+ }
+
+ /**
+ * Return console input key events (discard other events).
+ *
+ * @param count requested number of events
+ * @return array possibly of size smaller then count
+ */
+ public static INPUT_RECORD[] readConsoleKeyInput(long handle, int count, boolean peek) throws IOException {
+ while (true) {
+ // read events until we have keyboard events, the queue could be full
+ // of mouse events.
+ INPUT_RECORD[] evts = readConsoleInputHelper(handle, count, peek);
+ int keyEvtCount = 0;
+ for (INPUT_RECORD evt : evts) {
+ if (evt.eventType == INPUT_RECORD.KEY_EVENT) keyEvtCount++;
+ }
+ if (keyEvtCount > 0) {
+ INPUT_RECORD[] res = new INPUT_RECORD[keyEvtCount];
+ int i = 0;
+ for (INPUT_RECORD evt : evts) {
+ if (evt.eventType == INPUT_RECORD.KEY_EVENT) {
+ res[i++] = evt;
+ }
+ }
+ return res;
+ }
+ }
+ }
+
+ public static String getLastErrorMessage() {
+ int bufferSize = 160;
+ byte[] data = new byte[bufferSize];
+ FormatMessageW(Kernel32.FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, data, bufferSize, null);
+ return new String(data, StandardCharsets.UTF_16LE).trim();
+ }
+
+ public static native int isatty(int fd);
+}
diff --git a/native/src/main/native/clibrary.c b/native/src/main/native/clibrary.c
new file mode 100644
index 000000000..59b9c14d3
--- /dev/null
+++ b/native/src/main/native/clibrary.c
@@ -0,0 +1,241 @@
+/*******************************************************************************
+ * Copyright (C) 2009-2017 the original author(s).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+#include "jlinenative.h"
+
+#if !defined(_WIN32) && !defined(_WIN64)
+
+#define Termios_NATIVE(func) Java_org_jline_nativ_CLibrary_00024Termios_##func
+#define WinSize_NATIVE(func) Java_org_jline_nativ_CLibrary_00024WinSize_##func
+#define CLibrary_NATIVE(func) Java_org_jline_nativ_CLibrary_##func
+
+typedef struct Termios_FID_CACHE {
+ int cached;
+ jclass clazz;
+ jfieldID c_iflag, c_oflag, c_cflag, c_lflag, c_cc, c_ispeed, c_ospeed;
+} Termios_FID_CACHE;
+
+Termios_FID_CACHE TermiosFc;
+
+void cacheTermiosFields(JNIEnv *env, jobject lpObject)
+{
+ if (TermiosFc.cached) return;
+ TermiosFc.clazz = (*env)->GetObjectClass(env, lpObject);
+ TermiosFc.c_iflag = (*env)->GetFieldID(env, TermiosFc.clazz, "c_iflag", "J");
+ TermiosFc.c_oflag = (*env)->GetFieldID(env, TermiosFc.clazz, "c_oflag", "J");
+ TermiosFc.c_cflag = (*env)->GetFieldID(env, TermiosFc.clazz, "c_cflag", "J");
+ TermiosFc.c_lflag = (*env)->GetFieldID(env, TermiosFc.clazz, "c_lflag", "J");
+ TermiosFc.c_cc = (*env)->GetFieldID(env, TermiosFc.clazz, "c_cc", "[B");
+ TermiosFc.c_ispeed = (*env)->GetFieldID(env, TermiosFc.clazz, "c_ispeed", "J");
+ TermiosFc.c_ospeed = (*env)->GetFieldID(env, TermiosFc.clazz, "c_ospeed", "J");
+ hawtjni_w_barrier();
+ TermiosFc.cached = 1;
+}
+
+struct termios *getTermiosFields(JNIEnv *env, jobject lpObject, struct termios *lpStruct)
+{
+ if (!TermiosFc.cached) cacheTermiosFields(env, lpObject);
+ lpStruct->c_iflag = (*env)->GetLongField(env, lpObject, TermiosFc.c_iflag);
+ lpStruct->c_oflag = (*env)->GetLongField(env, lpObject, TermiosFc.c_oflag);
+ lpStruct->c_cflag = (*env)->GetLongField(env, lpObject, TermiosFc.c_cflag);
+ lpStruct->c_lflag = (*env)->GetLongField(env, lpObject, TermiosFc.c_lflag);
+ {
+ jbyteArray lpObject1 = (jbyteArray)(*env)->GetObjectField(env, lpObject, TermiosFc.c_cc);
+ (*env)->GetByteArrayRegion(env, lpObject1, 0, sizeof(lpStruct->c_cc), (jbyte *)lpStruct->c_cc);
+ }
+ lpStruct->c_ispeed = (*env)->GetLongField(env, lpObject, TermiosFc.c_ispeed);
+ lpStruct->c_ospeed = (*env)->GetLongField(env, lpObject, TermiosFc.c_ospeed);
+ return lpStruct;
+}
+
+void setTermiosFields(JNIEnv *env, jobject lpObject, struct termios *lpStruct)
+{
+ if (!TermiosFc.cached) cacheTermiosFields(env, lpObject);
+ (*env)->SetLongField(env, lpObject, TermiosFc.c_iflag, (jlong)lpStruct->c_iflag);
+ (*env)->SetLongField(env, lpObject, TermiosFc.c_oflag, (jlong)lpStruct->c_oflag);
+ (*env)->SetLongField(env, lpObject, TermiosFc.c_cflag, (jlong)lpStruct->c_cflag);
+ (*env)->SetLongField(env, lpObject, TermiosFc.c_lflag, (jlong)lpStruct->c_lflag);
+ {
+ jbyteArray lpObject1 = (jbyteArray)(*env)->GetObjectField(env, lpObject, TermiosFc.c_cc);
+ (*env)->SetByteArrayRegion(env, lpObject1, 0, sizeof(lpStruct->c_cc), (jbyte *)lpStruct->c_cc);
+ }
+ (*env)->SetLongField(env, lpObject, TermiosFc.c_ispeed, (jlong)lpStruct->c_ispeed);
+ (*env)->SetLongField(env, lpObject, TermiosFc.c_ospeed, (jlong)lpStruct->c_ospeed);
+}
+
+typedef struct WinSize_FID_CACHE {
+ int cached;
+ jclass clazz;
+ jfieldID ws_row, ws_col, ws_xpixel, ws_ypixel;
+} WinSize_FID_CACHE;
+
+WinSize_FID_CACHE WinSizeFc;
+
+void cacheWinSizeFields(JNIEnv *env, jobject lpObject)
+{
+ if (WinSizeFc.cached) return;
+ WinSizeFc.clazz = (*env)->GetObjectClass(env, lpObject);
+ WinSizeFc.ws_row = (*env)->GetFieldID(env, WinSizeFc.clazz, "ws_row", "S");
+ WinSizeFc.ws_col = (*env)->GetFieldID(env, WinSizeFc.clazz, "ws_col", "S");
+ WinSizeFc.ws_xpixel = (*env)->GetFieldID(env, WinSizeFc.clazz, "ws_xpixel", "S");
+ WinSizeFc.ws_ypixel = (*env)->GetFieldID(env, WinSizeFc.clazz, "ws_ypixel", "S");
+ hawtjni_w_barrier();
+ WinSizeFc.cached = 1;
+}
+
+struct winsize *getWinSizeFields(JNIEnv *env, jobject lpObject, struct winsize *lpStruct)
+{
+ if (!WinSizeFc.cached) cacheWinSizeFields(env, lpObject);
+ lpStruct->ws_row = (*env)->GetShortField(env, lpObject, WinSizeFc.ws_row);
+ lpStruct->ws_col = (*env)->GetShortField(env, lpObject, WinSizeFc.ws_col);
+ lpStruct->ws_xpixel = (*env)->GetShortField(env, lpObject, WinSizeFc.ws_xpixel);
+ lpStruct->ws_ypixel = (*env)->GetShortField(env, lpObject, WinSizeFc.ws_ypixel);
+ return lpStruct;
+}
+
+void setWinSizeFields(JNIEnv *env, jobject lpObject, struct winsize *lpStruct)
+{
+ if (!WinSizeFc.cached) cacheWinSizeFields(env, lpObject);
+ (*env)->SetShortField(env, lpObject, WinSizeFc.ws_row, (jshort)lpStruct->ws_row);
+ (*env)->SetShortField(env, lpObject, WinSizeFc.ws_col, (jshort)lpStruct->ws_col);
+ (*env)->SetShortField(env, lpObject, WinSizeFc.ws_xpixel, (jshort)lpStruct->ws_xpixel);
+ (*env)->SetShortField(env, lpObject, WinSizeFc.ws_ypixel, (jshort)lpStruct->ws_ypixel);
+}
+
+JNIEXPORT void JNICALL Termios_NATIVE(init)(JNIEnv *env, jclass that)
+{
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SIZEOF", "I"), (jint)sizeof(struct termios));
+ return;
+}
+
+JNIEXPORT void JNICALL WinSize_NATIVE(init)(JNIEnv *env, jclass that)
+{
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SIZEOF", "I"), (jint)sizeof(struct winsize));
+ return;
+}
+
+JNIEXPORT void JNICALL CLibrary_NATIVE(init)(JNIEnv *env, jclass that)
+{
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "TCSANOW", "I"), (jint)TCSANOW);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "TCSADRAIN", "I"), (jint)TCSADRAIN);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "TCSAFLUSH", "I"), (jint)TCSAFLUSH);
+ (*env)->SetStaticLongField(env, that, (*env)->GetStaticFieldID(env, that, "TIOCGWINSZ", "J"), (jlong)TIOCGWINSZ);
+ (*env)->SetStaticLongField(env, that, (*env)->GetStaticFieldID(env, that, "TIOCSWINSZ", "J"), (jlong)TIOCSWINSZ);
+ return;
+}
+
+JNIEXPORT jint JNICALL CLibrary_NATIVE(ioctl__IJLorg_jline_nativ_CLibrary_00024WinSize_2)
+ (JNIEnv *env, jclass that, jint arg0, jlong arg1, jobject arg2)
+{
+ struct winsize _arg2, *lparg2=NULL;
+ jint rc = 0;
+
+ if (arg2) if ((lparg2 = getWinSizeFields(env, arg2, &_arg2)) == NULL) goto fail;
+ rc = (jint)ioctl(arg0, arg1, (intptr_t)lparg2);
+fail:
+ if (arg2 && lparg2) setWinSizeFields(env, arg2, lparg2);
+
+ return rc;
+}
+
+JNIEXPORT jint JNICALL CLibrary_NATIVE(ioctl__IJ_3I)
+ (JNIEnv *env, jclass that, jint arg0, jlong arg1, jintArray arg2)
+{
+ jint *lparg2=NULL;
+ jint rc = 0;
+
+ if (arg2) if ((lparg2 = (*env)->GetIntArrayElements(env, arg2, NULL)) == NULL) goto fail;
+ rc = (jint)ioctl(arg0, arg1, lparg2);
+fail:
+ if (arg2 && lparg2) (*env)->ReleaseIntArrayElements(env, arg2, lparg2, 0);
+
+ return rc;
+}
+
+JNIEXPORT jint JNICALL CLibrary_NATIVE(openpty)
+ (JNIEnv *env, jclass that, jintArray arg0, jintArray arg1, jbyteArray arg2, jobject arg3, jobject arg4)
+{
+ jint *lparg0=NULL;
+ jint *lparg1=NULL;
+ jbyte *lparg2=NULL;
+ struct termios _arg3, *lparg3=NULL;
+ struct winsize _arg4, *lparg4=NULL;
+ jint rc = 0;
+
+ if (arg0) if ((lparg0 = (*env)->GetIntArrayElements(env, arg0, NULL)) == NULL) goto fail;
+ if (arg1) if ((lparg1 = (*env)->GetIntArrayElements(env, arg1, NULL)) == NULL) goto fail;
+ if (arg2) if ((lparg2 = (*env)->GetByteArrayElements(env, arg2, NULL)) == NULL) goto fail;
+ if (arg3) if ((lparg3 = getTermiosFields(env, arg3, &_arg3)) == NULL) goto fail;
+ if (arg4) if ((lparg4 = getWinSizeFields(env, arg4, &_arg4)) == NULL) goto fail;
+ rc = (jint)openpty((int *)lparg0, (int *)lparg1, (char *)lparg2, (struct termios *)lparg3, (struct winsize *)lparg4);
+fail:
+ if (arg2 && lparg2) (*env)->ReleaseByteArrayElements(env, arg2, lparg2, 0);
+ if (arg1 && lparg1) (*env)->ReleaseIntArrayElements(env, arg1, lparg1, 0);
+ if (arg0 && lparg0) (*env)->ReleaseIntArrayElements(env, arg0, lparg0, 0);
+
+ return rc;
+}
+
+JNIEXPORT jint JNICALL CLibrary_NATIVE(tcgetattr)
+ (JNIEnv *env, jclass that, jint arg0, jobject arg1)
+{
+ struct termios _arg1, *lparg1=NULL;
+ jint rc = 0;
+
+ if (arg1) if ((lparg1 = &_arg1) == NULL) goto fail;
+ rc = (jint)tcgetattr(arg0, (struct termios *)lparg1);
+fail:
+ if (arg1 && lparg1) setTermiosFields(env, arg1, lparg1);
+
+ return rc;
+}
+
+JNIEXPORT jint JNICALL CLibrary_NATIVE(tcsetattr)
+ (JNIEnv *env, jclass that, jint arg0, jint arg1, jobject arg2)
+{
+ struct termios _arg2, *lparg2=NULL;
+ jint rc = 0;
+
+ if (arg2) if ((lparg2 = getTermiosFields(env, arg2, &_arg2)) == NULL) goto fail;
+ rc = (jint)tcsetattr(arg0, arg1, (struct termios *)lparg2);
+fail:
+
+ return rc;
+}
+
+JNIEXPORT jint JNICALL CLibrary_NATIVE(isatty)
+ (JNIEnv *env, jclass that, jint arg0)
+{
+ jint rc = 0;
+
+ rc = (jint)isatty(arg0);
+
+ return rc;
+}
+
+JNIEXPORT jstring JNICALL CLibrary_NATIVE(ttyname)
+ (JNIEnv *env, jclass that, jint arg0)
+{
+ jstring rc = 0;
+ char s[256] = { 0 };
+ int r = 0;
+
+ r = ttyname_r(arg0, s, 256);
+ if (!r) rc = (*env)->NewStringUTF(env,s);
+
+ return rc;
+}
+
+#endif
diff --git a/native/src/main/native/kernel32.c b/native/src/main/native/kernel32.c
new file mode 100644
index 000000000..003cdcbaa
--- /dev/null
+++ b/native/src/main/native/kernel32.c
@@ -0,0 +1,974 @@
+/*******************************************************************************
+ * Copyright (C) 2009-2017 the original author(s).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+#include "jlinenative.h"
+
+#if defined(_WIN32) || defined(_WIN64)
+
+#define isatty _isatty
+
+#define Kernel32_NATIVE(func) Java_org_jline_nativ_Kernel32_##func
+#define CHAR_INFO_NATIVE(func) Java_org_jline_nativ_Kernel32_00024CHAR_1INFO_##func
+#define CONSOLE_SCREEN_BUFFER_INFO_NATIVE(func) Java_org_jline_nativ_Kernel32_00024CONSOLE_1SCREEN_1BUFFER_1INFO_##func
+#define COORD_NATIVE(func) Java_org_jline_nativ_Kernel32_00024COORD_##func
+#define FOCUS_EVENT_RECORD_NATIVE(func) Java_org_jline_nativ_Kernel32_00024FOCUS_1EVENT_1RECORD_##func
+#define INPUT_RECORD_NATIVE(func) Java_org_jline_nativ_Kernel32_00024INPUT_1RECORD_##func
+#define KEY_EVENT_RECORD_NATIVE(func) Java_org_jline_nativ_Kernel32_00024KEY_1EVENT_1RECORD_##func
+#define MENU_EVENT_RECORD_NATIVE(func) Java_org_jline_nativ_Kernel32_00024MENU_1EVENT_1RECORD_##func
+#define MOUSE_EVENT_RECORD_NATIVE(func) Java_org_jline_nativ_Kernel32_00024MOUSE_1EVENT_1RECORD_##func
+#define SMALL_RECT_NATIVE(func) Java_org_jline_nativ_Kernel32_00024SMALL_1RECT_##func
+#define WINDOW_BUFFER_SIZE_RECORD_NATIVE(func) Java_org_jline_nativ_Kernel32_00024WINDOW_1BUFFER_1SIZE_1RECORD_##func
+
+void cacheCHAR_INFOFields(JNIEnv *env, jobject lpObject);
+CHAR_INFO *getCHAR_INFOFields(JNIEnv *env, jobject lpObject, CHAR_INFO *lpStruct);
+void setCHAR_INFOFields(JNIEnv *env, jobject lpObject, CHAR_INFO *lpStruct);
+
+void cacheCONSOLE_SCREEN_BUFFER_INFOFields(JNIEnv *env, jobject lpObject);
+CONSOLE_SCREEN_BUFFER_INFO *getCONSOLE_SCREEN_BUFFER_INFOFields(JNIEnv *env, jobject lpObject, CONSOLE_SCREEN_BUFFER_INFO *lpStruct);
+void setCONSOLE_SCREEN_BUFFER_INFOFields(JNIEnv *env, jobject lpObject, CONSOLE_SCREEN_BUFFER_INFO *lpStruct);
+
+void cacheCOORDFields(JNIEnv *env, jobject lpObject);
+COORD *getCOORDFields(JNIEnv *env, jobject lpObject, COORD *lpStruct);
+void setCOORDFields(JNIEnv *env, jobject lpObject, COORD *lpStruct);
+
+void cacheFOCUS_EVENT_RECORDFields(JNIEnv *env, jobject lpObject);
+FOCUS_EVENT_RECORD *getFOCUS_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, FOCUS_EVENT_RECORD *lpStruct);
+void setFOCUS_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, FOCUS_EVENT_RECORD *lpStruct);
+
+void cacheINPUT_RECORDFields(JNIEnv *env, jobject lpObject);
+INPUT_RECORD *getINPUT_RECORDFields(JNIEnv *env, jobject lpObject, INPUT_RECORD *lpStruct);
+void setINPUT_RECORDFields(JNIEnv *env, jobject lpObject, INPUT_RECORD *lpStruct);
+
+void cacheKEY_EVENT_RECORDFields(JNIEnv *env, jobject lpObject);
+KEY_EVENT_RECORD *getKEY_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, KEY_EVENT_RECORD *lpStruct);
+void setKEY_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, KEY_EVENT_RECORD *lpStruct);
+
+void cacheMENU_EVENT_RECORDFields(JNIEnv *env, jobject lpObject);
+MENU_EVENT_RECORD *getMENU_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, MENU_EVENT_RECORD *lpStruct);
+void setMENU_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, MENU_EVENT_RECORD *lpStruct);
+
+void cacheMOUSE_EVENT_RECORDFields(JNIEnv *env, jobject lpObject);
+MOUSE_EVENT_RECORD *getMOUSE_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, MOUSE_EVENT_RECORD *lpStruct);
+void setMOUSE_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, MOUSE_EVENT_RECORD *lpStruct);
+
+void cacheSMALL_RECTFields(JNIEnv *env, jobject lpObject);
+SMALL_RECT *getSMALL_RECTFields(JNIEnv *env, jobject lpObject, SMALL_RECT *lpStruct);
+void setSMALL_RECTFields(JNIEnv *env, jobject lpObject, SMALL_RECT *lpStruct);
+
+void cacheWINDOW_BUFFER_SIZE_RECORDFields(JNIEnv *env, jobject lpObject);
+WINDOW_BUFFER_SIZE_RECORD *getWINDOW_BUFFER_SIZE_RECORDFields(JNIEnv *env, jobject lpObject, WINDOW_BUFFER_SIZE_RECORD *lpStruct);
+void setWINDOW_BUFFER_SIZE_RECORDFields(JNIEnv *env, jobject lpObject, WINDOW_BUFFER_SIZE_RECORD *lpStruct);
+
+typedef struct CHAR_INFO_FID_CACHE {
+ int cached;
+ jclass clazz;
+ jfieldID attributes, unicodeChar;
+} CHAR_INFO_FID_CACHE;
+
+CHAR_INFO_FID_CACHE CHAR_INFOFc;
+
+void cacheCHAR_INFOFields(JNIEnv *env, jobject lpObject)
+{
+ if (CHAR_INFOFc.cached) return;
+ CHAR_INFOFc.clazz = (*env)->GetObjectClass(env, lpObject);
+ CHAR_INFOFc.attributes = (*env)->GetFieldID(env, CHAR_INFOFc.clazz, "attributes", "S");
+ CHAR_INFOFc.unicodeChar = (*env)->GetFieldID(env, CHAR_INFOFc.clazz, "unicodeChar", "C");
+ hawtjni_w_barrier();
+ CHAR_INFOFc.cached = 1;
+}
+
+CHAR_INFO *getCHAR_INFOFields(JNIEnv *env, jobject lpObject, CHAR_INFO *lpStruct)
+{
+ if (!CHAR_INFOFc.cached) cacheCHAR_INFOFields(env, lpObject);
+ lpStruct->Attributes = (*env)->GetShortField(env, lpObject, CHAR_INFOFc.attributes);
+ lpStruct->Char.UnicodeChar = (*env)->GetCharField(env, lpObject, CHAR_INFOFc.unicodeChar);
+ return lpStruct;
+}
+
+void setCHAR_INFOFields(JNIEnv *env, jobject lpObject, CHAR_INFO *lpStruct)
+{
+ if (!CHAR_INFOFc.cached) cacheCHAR_INFOFields(env, lpObject);
+ (*env)->SetShortField(env, lpObject, CHAR_INFOFc.attributes, (jshort)lpStruct->Attributes);
+ (*env)->SetCharField(env, lpObject, CHAR_INFOFc.unicodeChar, (jchar)lpStruct->Char.UnicodeChar);
+}
+
+typedef struct CONSOLE_SCREEN_BUFFER_INFO_FID_CACHE {
+ int cached;
+ jclass clazz;
+ jfieldID size, cursorPosition, attributes, window, maximumWindowSize;
+} CONSOLE_SCREEN_BUFFER_INFO_FID_CACHE;
+
+CONSOLE_SCREEN_BUFFER_INFO_FID_CACHE CONSOLE_SCREEN_BUFFER_INFOFc;
+
+void cacheCONSOLE_SCREEN_BUFFER_INFOFields(JNIEnv *env, jobject lpObject)
+{
+ if (CONSOLE_SCREEN_BUFFER_INFOFc.cached) return;
+ CONSOLE_SCREEN_BUFFER_INFOFc.clazz = (*env)->GetObjectClass(env, lpObject);
+ CONSOLE_SCREEN_BUFFER_INFOFc.size = (*env)->GetFieldID(env, CONSOLE_SCREEN_BUFFER_INFOFc.clazz, "size", "Lorg/jline/nativ/Kernel32$COORD;");
+ CONSOLE_SCREEN_BUFFER_INFOFc.cursorPosition = (*env)->GetFieldID(env, CONSOLE_SCREEN_BUFFER_INFOFc.clazz, "cursorPosition", "Lorg/jline/nativ/Kernel32$COORD;");
+ CONSOLE_SCREEN_BUFFER_INFOFc.attributes = (*env)->GetFieldID(env, CONSOLE_SCREEN_BUFFER_INFOFc.clazz, "attributes", "S");
+ CONSOLE_SCREEN_BUFFER_INFOFc.window = (*env)->GetFieldID(env, CONSOLE_SCREEN_BUFFER_INFOFc.clazz, "window", "Lorg/jline/nativ/Kernel32$SMALL_RECT;");
+ CONSOLE_SCREEN_BUFFER_INFOFc.maximumWindowSize = (*env)->GetFieldID(env, CONSOLE_SCREEN_BUFFER_INFOFc.clazz, "maximumWindowSize", "Lorg/jline/nativ/Kernel32$COORD;");
+ hawtjni_w_barrier();
+ CONSOLE_SCREEN_BUFFER_INFOFc.cached = 1;
+}
+
+CONSOLE_SCREEN_BUFFER_INFO *getCONSOLE_SCREEN_BUFFER_INFOFields(JNIEnv *env, jobject lpObject, CONSOLE_SCREEN_BUFFER_INFO *lpStruct)
+{
+ if (!CONSOLE_SCREEN_BUFFER_INFOFc.cached) cacheCONSOLE_SCREEN_BUFFER_INFOFields(env, lpObject);
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CONSOLE_SCREEN_BUFFER_INFOFc.size);
+ if (lpObject1 != NULL) getCOORDFields(env, lpObject1, &lpStruct->dwSize);
+ }
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CONSOLE_SCREEN_BUFFER_INFOFc.cursorPosition);
+ if (lpObject1 != NULL) getCOORDFields(env, lpObject1, &lpStruct->dwCursorPosition);
+ }
+ lpStruct->wAttributes = (*env)->GetShortField(env, lpObject, CONSOLE_SCREEN_BUFFER_INFOFc.attributes);
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CONSOLE_SCREEN_BUFFER_INFOFc.window);
+ if (lpObject1 != NULL) getSMALL_RECTFields(env, lpObject1, &lpStruct->srWindow);
+ }
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CONSOLE_SCREEN_BUFFER_INFOFc.maximumWindowSize);
+ if (lpObject1 != NULL) getCOORDFields(env, lpObject1, &lpStruct->dwMaximumWindowSize);
+ }
+ return lpStruct;
+}
+
+void setCONSOLE_SCREEN_BUFFER_INFOFields(JNIEnv *env, jobject lpObject, CONSOLE_SCREEN_BUFFER_INFO *lpStruct)
+{
+ if (!CONSOLE_SCREEN_BUFFER_INFOFc.cached) cacheCONSOLE_SCREEN_BUFFER_INFOFields(env, lpObject);
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CONSOLE_SCREEN_BUFFER_INFOFc.size);
+ if (lpObject1 != NULL) setCOORDFields(env, lpObject1, &lpStruct->dwSize);
+ }
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CONSOLE_SCREEN_BUFFER_INFOFc.cursorPosition);
+ if (lpObject1 != NULL) setCOORDFields(env, lpObject1, &lpStruct->dwCursorPosition);
+ }
+ (*env)->SetShortField(env, lpObject, CONSOLE_SCREEN_BUFFER_INFOFc.attributes, (jshort)lpStruct->wAttributes);
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CONSOLE_SCREEN_BUFFER_INFOFc.window);
+ if (lpObject1 != NULL) setSMALL_RECTFields(env, lpObject1, &lpStruct->srWindow);
+ }
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, CONSOLE_SCREEN_BUFFER_INFOFc.maximumWindowSize);
+ if (lpObject1 != NULL) setCOORDFields(env, lpObject1, &lpStruct->dwMaximumWindowSize);
+ }
+}
+
+typedef struct COORD_FID_CACHE {
+ int cached;
+ jclass clazz;
+ jfieldID x, y;
+} COORD_FID_CACHE;
+
+COORD_FID_CACHE COORDFc;
+
+void cacheCOORDFields(JNIEnv *env, jobject lpObject)
+{
+ if (COORDFc.cached) return;
+ COORDFc.clazz = (*env)->GetObjectClass(env, lpObject);
+ COORDFc.x = (*env)->GetFieldID(env, COORDFc.clazz, "x", "S");
+ COORDFc.y = (*env)->GetFieldID(env, COORDFc.clazz, "y", "S");
+ hawtjni_w_barrier();
+ COORDFc.cached = 1;
+}
+
+COORD *getCOORDFields(JNIEnv *env, jobject lpObject, COORD *lpStruct)
+{
+ if (!COORDFc.cached) cacheCOORDFields(env, lpObject);
+ lpStruct->X = (*env)->GetShortField(env, lpObject, COORDFc.x);
+ lpStruct->Y = (*env)->GetShortField(env, lpObject, COORDFc.y);
+ return lpStruct;
+}
+
+void setCOORDFields(JNIEnv *env, jobject lpObject, COORD *lpStruct)
+{
+ if (!COORDFc.cached) cacheCOORDFields(env, lpObject);
+ (*env)->SetShortField(env, lpObject, COORDFc.x, (jshort)lpStruct->X);
+ (*env)->SetShortField(env, lpObject, COORDFc.y, (jshort)lpStruct->Y);
+}
+
+typedef struct FOCUS_EVENT_RECORD_FID_CACHE {
+ int cached;
+ jclass clazz;
+ jfieldID setFocus;
+} FOCUS_EVENT_RECORD_FID_CACHE;
+
+FOCUS_EVENT_RECORD_FID_CACHE FOCUS_EVENT_RECORDFc;
+
+void cacheFOCUS_EVENT_RECORDFields(JNIEnv *env, jobject lpObject)
+{
+ if (FOCUS_EVENT_RECORDFc.cached) return;
+ FOCUS_EVENT_RECORDFc.clazz = (*env)->GetObjectClass(env, lpObject);
+ FOCUS_EVENT_RECORDFc.setFocus = (*env)->GetFieldID(env, FOCUS_EVENT_RECORDFc.clazz, "setFocus", "Z");
+ hawtjni_w_barrier();
+ FOCUS_EVENT_RECORDFc.cached = 1;
+}
+
+FOCUS_EVENT_RECORD *getFOCUS_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, FOCUS_EVENT_RECORD *lpStruct)
+{
+ if (!FOCUS_EVENT_RECORDFc.cached) cacheFOCUS_EVENT_RECORDFields(env, lpObject);
+ lpStruct->bSetFocus = (*env)->GetBooleanField(env, lpObject, FOCUS_EVENT_RECORDFc.setFocus);
+ return lpStruct;
+}
+
+void setFOCUS_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, FOCUS_EVENT_RECORD *lpStruct)
+{
+ if (!FOCUS_EVENT_RECORDFc.cached) cacheFOCUS_EVENT_RECORDFields(env, lpObject);
+ (*env)->SetBooleanField(env, lpObject, FOCUS_EVENT_RECORDFc.setFocus, (jboolean)lpStruct->bSetFocus);
+}
+
+typedef struct INPUT_RECORD_FID_CACHE {
+ int cached;
+ jclass clazz;
+ jfieldID eventType, keyEvent, mouseEvent, windowBufferSizeEvent, menuEvent, focusEvent;
+} INPUT_RECORD_FID_CACHE;
+
+INPUT_RECORD_FID_CACHE INPUT_RECORDFc;
+
+void cacheINPUT_RECORDFields(JNIEnv *env, jobject lpObject)
+{
+ if (INPUT_RECORDFc.cached) return;
+ INPUT_RECORDFc.clazz = (*env)->GetObjectClass(env, lpObject);
+ INPUT_RECORDFc.eventType = (*env)->GetFieldID(env, INPUT_RECORDFc.clazz, "eventType", "S");
+ INPUT_RECORDFc.keyEvent = (*env)->GetFieldID(env, INPUT_RECORDFc.clazz, "keyEvent", "Lorg/jline/nativ/Kernel32$KEY_EVENT_RECORD;");
+ INPUT_RECORDFc.mouseEvent = (*env)->GetFieldID(env, INPUT_RECORDFc.clazz, "mouseEvent", "Lorg/jline/nativ/Kernel32$MOUSE_EVENT_RECORD;");
+ INPUT_RECORDFc.windowBufferSizeEvent = (*env)->GetFieldID(env, INPUT_RECORDFc.clazz, "windowBufferSizeEvent", "Lorg/jline/nativ/Kernel32$WINDOW_BUFFER_SIZE_RECORD;");
+ INPUT_RECORDFc.menuEvent = (*env)->GetFieldID(env, INPUT_RECORDFc.clazz, "menuEvent", "Lorg/jline/nativ/Kernel32$MENU_EVENT_RECORD;");
+ INPUT_RECORDFc.focusEvent = (*env)->GetFieldID(env, INPUT_RECORDFc.clazz, "focusEvent", "Lorg/jline/nativ/Kernel32$FOCUS_EVENT_RECORD;");
+ hawtjni_w_barrier();
+ INPUT_RECORDFc.cached = 1;
+}
+
+INPUT_RECORD *getINPUT_RECORDFields(JNIEnv *env, jobject lpObject, INPUT_RECORD *lpStruct)
+{
+ if (!INPUT_RECORDFc.cached) cacheINPUT_RECORDFields(env, lpObject);
+ lpStruct->EventType = (*env)->GetShortField(env, lpObject, INPUT_RECORDFc.eventType);
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, INPUT_RECORDFc.keyEvent);
+ if (lpObject1 != NULL) getKEY_EVENT_RECORDFields(env, lpObject1, &lpStruct->Event.KeyEvent);
+ }
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, INPUT_RECORDFc.mouseEvent);
+ if (lpObject1 != NULL) getMOUSE_EVENT_RECORDFields(env, lpObject1, &lpStruct->Event.MouseEvent);
+ }
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, INPUT_RECORDFc.windowBufferSizeEvent);
+ if (lpObject1 != NULL) getWINDOW_BUFFER_SIZE_RECORDFields(env, lpObject1, &lpStruct->Event.WindowBufferSizeEvent);
+ }
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, INPUT_RECORDFc.menuEvent);
+ if (lpObject1 != NULL) getMENU_EVENT_RECORDFields(env, lpObject1, &lpStruct->Event.MenuEvent);
+ }
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, INPUT_RECORDFc.focusEvent);
+ if (lpObject1 != NULL) getFOCUS_EVENT_RECORDFields(env, lpObject1, &lpStruct->Event.FocusEvent);
+ }
+ return lpStruct;
+}
+
+void setINPUT_RECORDFields(JNIEnv *env, jobject lpObject, INPUT_RECORD *lpStruct)
+{
+ if (!INPUT_RECORDFc.cached) cacheINPUT_RECORDFields(env, lpObject);
+ (*env)->SetShortField(env, lpObject, INPUT_RECORDFc.eventType, (jshort)lpStruct->EventType);
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, INPUT_RECORDFc.keyEvent);
+ if (lpObject1 != NULL) setKEY_EVENT_RECORDFields(env, lpObject1, &lpStruct->Event.KeyEvent);
+ }
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, INPUT_RECORDFc.mouseEvent);
+ if (lpObject1 != NULL) setMOUSE_EVENT_RECORDFields(env, lpObject1, &lpStruct->Event.MouseEvent);
+ }
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, INPUT_RECORDFc.windowBufferSizeEvent);
+ if (lpObject1 != NULL) setWINDOW_BUFFER_SIZE_RECORDFields(env, lpObject1, &lpStruct->Event.WindowBufferSizeEvent);
+ }
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, INPUT_RECORDFc.menuEvent);
+ if (lpObject1 != NULL) setMENU_EVENT_RECORDFields(env, lpObject1, &lpStruct->Event.MenuEvent);
+ }
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, INPUT_RECORDFc.focusEvent);
+ if (lpObject1 != NULL) setFOCUS_EVENT_RECORDFields(env, lpObject1, &lpStruct->Event.FocusEvent);
+ }
+}
+
+typedef struct KEY_EVENT_RECORD_FID_CACHE {
+ int cached;
+ jclass clazz;
+ jfieldID keyDown, repeatCount, keyCode, scanCode, uchar, controlKeyState;
+} KEY_EVENT_RECORD_FID_CACHE;
+
+KEY_EVENT_RECORD_FID_CACHE KEY_EVENT_RECORDFc;
+
+void cacheKEY_EVENT_RECORDFields(JNIEnv *env, jobject lpObject)
+{
+ if (KEY_EVENT_RECORDFc.cached) return;
+ KEY_EVENT_RECORDFc.clazz = (*env)->GetObjectClass(env, lpObject);
+ KEY_EVENT_RECORDFc.keyDown = (*env)->GetFieldID(env, KEY_EVENT_RECORDFc.clazz, "keyDown", "Z");
+ KEY_EVENT_RECORDFc.repeatCount = (*env)->GetFieldID(env, KEY_EVENT_RECORDFc.clazz, "repeatCount", "S");
+ KEY_EVENT_RECORDFc.keyCode = (*env)->GetFieldID(env, KEY_EVENT_RECORDFc.clazz, "keyCode", "S");
+ KEY_EVENT_RECORDFc.scanCode = (*env)->GetFieldID(env, KEY_EVENT_RECORDFc.clazz, "scanCode", "S");
+ KEY_EVENT_RECORDFc.uchar = (*env)->GetFieldID(env, KEY_EVENT_RECORDFc.clazz, "uchar", "C");
+ KEY_EVENT_RECORDFc.controlKeyState = (*env)->GetFieldID(env, KEY_EVENT_RECORDFc.clazz, "controlKeyState", "I");
+ hawtjni_w_barrier();
+ KEY_EVENT_RECORDFc.cached = 1;
+}
+
+KEY_EVENT_RECORD *getKEY_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, KEY_EVENT_RECORD *lpStruct)
+{
+ if (!KEY_EVENT_RECORDFc.cached) cacheKEY_EVENT_RECORDFields(env, lpObject);
+ lpStruct->bKeyDown = (*env)->GetBooleanField(env, lpObject, KEY_EVENT_RECORDFc.keyDown);
+ lpStruct->wRepeatCount = (*env)->GetShortField(env, lpObject, KEY_EVENT_RECORDFc.repeatCount);
+ lpStruct->wVirtualKeyCode = (*env)->GetShortField(env, lpObject, KEY_EVENT_RECORDFc.keyCode);
+ lpStruct->wVirtualScanCode = (*env)->GetShortField(env, lpObject, KEY_EVENT_RECORDFc.scanCode);
+ lpStruct->uChar.UnicodeChar = (*env)->GetCharField(env, lpObject, KEY_EVENT_RECORDFc.uchar);
+ lpStruct->dwControlKeyState = (*env)->GetIntField(env, lpObject, KEY_EVENT_RECORDFc.controlKeyState);
+ return lpStruct;
+}
+
+void setKEY_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, KEY_EVENT_RECORD *lpStruct)
+{
+ if (!KEY_EVENT_RECORDFc.cached) cacheKEY_EVENT_RECORDFields(env, lpObject);
+ (*env)->SetBooleanField(env, lpObject, KEY_EVENT_RECORDFc.keyDown, (jboolean)lpStruct->bKeyDown);
+ (*env)->SetShortField(env, lpObject, KEY_EVENT_RECORDFc.repeatCount, (jshort)lpStruct->wRepeatCount);
+ (*env)->SetShortField(env, lpObject, KEY_EVENT_RECORDFc.keyCode, (jshort)lpStruct->wVirtualKeyCode);
+ (*env)->SetShortField(env, lpObject, KEY_EVENT_RECORDFc.scanCode, (jshort)lpStruct->wVirtualScanCode);
+ (*env)->SetCharField(env, lpObject, KEY_EVENT_RECORDFc.uchar, (jchar)lpStruct->uChar.UnicodeChar);
+ (*env)->SetIntField(env, lpObject, KEY_EVENT_RECORDFc.controlKeyState, (jint)lpStruct->dwControlKeyState);
+}
+
+typedef struct MENU_EVENT_RECORD_FID_CACHE {
+ int cached;
+ jclass clazz;
+ jfieldID commandId;
+} MENU_EVENT_RECORD_FID_CACHE;
+
+MENU_EVENT_RECORD_FID_CACHE MENU_EVENT_RECORDFc;
+
+void cacheMENU_EVENT_RECORDFields(JNIEnv *env, jobject lpObject)
+{
+ if (MENU_EVENT_RECORDFc.cached) return;
+ MENU_EVENT_RECORDFc.clazz = (*env)->GetObjectClass(env, lpObject);
+ MENU_EVENT_RECORDFc.commandId = (*env)->GetFieldID(env, MENU_EVENT_RECORDFc.clazz, "commandId", "I");
+ hawtjni_w_barrier();
+ MENU_EVENT_RECORDFc.cached = 1;
+}
+
+MENU_EVENT_RECORD *getMENU_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, MENU_EVENT_RECORD *lpStruct)
+{
+ if (!MENU_EVENT_RECORDFc.cached) cacheMENU_EVENT_RECORDFields(env, lpObject);
+#if defined(_WIN32) || defined(_WIN64)
+ lpStruct->dwCommandId = (*env)->GetIntField(env, lpObject, MENU_EVENT_RECORDFc.commandId);
+#endif
+ return lpStruct;
+}
+
+void setMENU_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, MENU_EVENT_RECORD *lpStruct)
+{
+ if (!MENU_EVENT_RECORDFc.cached) cacheMENU_EVENT_RECORDFields(env, lpObject);
+ (*env)->SetIntField(env, lpObject, MENU_EVENT_RECORDFc.commandId, (jint)lpStruct->dwCommandId);
+}
+
+typedef struct MOUSE_EVENT_RECORD_FID_CACHE {
+ int cached;
+ jclass clazz;
+ jfieldID mousePosition, buttonState, controlKeyState, eventFlags;
+} MOUSE_EVENT_RECORD_FID_CACHE;
+
+MOUSE_EVENT_RECORD_FID_CACHE MOUSE_EVENT_RECORDFc;
+
+void cacheMOUSE_EVENT_RECORDFields(JNIEnv *env, jobject lpObject)
+{
+ if (MOUSE_EVENT_RECORDFc.cached) return;
+ MOUSE_EVENT_RECORDFc.clazz = (*env)->GetObjectClass(env, lpObject);
+ MOUSE_EVENT_RECORDFc.mousePosition = (*env)->GetFieldID(env, MOUSE_EVENT_RECORDFc.clazz, "mousePosition", "Lorg/jline/nativ/Kernel32$COORD;");
+ MOUSE_EVENT_RECORDFc.buttonState = (*env)->GetFieldID(env, MOUSE_EVENT_RECORDFc.clazz, "buttonState", "I");
+ MOUSE_EVENT_RECORDFc.controlKeyState = (*env)->GetFieldID(env, MOUSE_EVENT_RECORDFc.clazz, "controlKeyState", "I");
+ MOUSE_EVENT_RECORDFc.eventFlags = (*env)->GetFieldID(env, MOUSE_EVENT_RECORDFc.clazz, "eventFlags", "I");
+ hawtjni_w_barrier();
+ MOUSE_EVENT_RECORDFc.cached = 1;
+}
+
+MOUSE_EVENT_RECORD *getMOUSE_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, MOUSE_EVENT_RECORD *lpStruct)
+{
+ if (!MOUSE_EVENT_RECORDFc.cached) cacheMOUSE_EVENT_RECORDFields(env, lpObject);
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, MOUSE_EVENT_RECORDFc.mousePosition);
+ if (lpObject1 != NULL) getCOORDFields(env, lpObject1, &lpStruct->dwMousePosition);
+ }
+ lpStruct->dwButtonState = (*env)->GetIntField(env, lpObject, MOUSE_EVENT_RECORDFc.buttonState);
+ lpStruct->dwControlKeyState = (*env)->GetIntField(env, lpObject, MOUSE_EVENT_RECORDFc.controlKeyState);
+ lpStruct->dwEventFlags = (*env)->GetIntField(env, lpObject, MOUSE_EVENT_RECORDFc.eventFlags);
+ return lpStruct;
+}
+
+void setMOUSE_EVENT_RECORDFields(JNIEnv *env, jobject lpObject, MOUSE_EVENT_RECORD *lpStruct)
+{
+ if (!MOUSE_EVENT_RECORDFc.cached) cacheMOUSE_EVENT_RECORDFields(env, lpObject);
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, MOUSE_EVENT_RECORDFc.mousePosition);
+ if (lpObject1 != NULL) setCOORDFields(env, lpObject1, &lpStruct->dwMousePosition);
+ }
+ (*env)->SetIntField(env, lpObject, MOUSE_EVENT_RECORDFc.buttonState, (jint)lpStruct->dwButtonState);
+ (*env)->SetIntField(env, lpObject, MOUSE_EVENT_RECORDFc.controlKeyState, (jint)lpStruct->dwControlKeyState);
+ (*env)->SetIntField(env, lpObject, MOUSE_EVENT_RECORDFc.eventFlags, (jint)lpStruct->dwEventFlags);
+}
+
+typedef struct SMALL_RECT_FID_CACHE {
+ int cached;
+ jclass clazz;
+ jfieldID left, top, right, bottom;
+} SMALL_RECT_FID_CACHE;
+
+SMALL_RECT_FID_CACHE SMALL_RECTFc;
+
+void cacheSMALL_RECTFields(JNIEnv *env, jobject lpObject)
+{
+ if (SMALL_RECTFc.cached) return;
+ SMALL_RECTFc.clazz = (*env)->GetObjectClass(env, lpObject);
+ SMALL_RECTFc.left = (*env)->GetFieldID(env, SMALL_RECTFc.clazz, "left", "S");
+ SMALL_RECTFc.top = (*env)->GetFieldID(env, SMALL_RECTFc.clazz, "top", "S");
+ SMALL_RECTFc.right = (*env)->GetFieldID(env, SMALL_RECTFc.clazz, "right", "S");
+ SMALL_RECTFc.bottom = (*env)->GetFieldID(env, SMALL_RECTFc.clazz, "bottom", "S");
+ hawtjni_w_barrier();
+ SMALL_RECTFc.cached = 1;
+}
+
+SMALL_RECT *getSMALL_RECTFields(JNIEnv *env, jobject lpObject, SMALL_RECT *lpStruct)
+{
+ if (!SMALL_RECTFc.cached) cacheSMALL_RECTFields(env, lpObject);
+ lpStruct->Left = (*env)->GetShortField(env, lpObject, SMALL_RECTFc.left);
+ lpStruct->Top = (*env)->GetShortField(env, lpObject, SMALL_RECTFc.top);
+ lpStruct->Right = (*env)->GetShortField(env, lpObject, SMALL_RECTFc.right);
+ lpStruct->Bottom = (*env)->GetShortField(env, lpObject, SMALL_RECTFc.bottom);
+ return lpStruct;
+}
+
+void setSMALL_RECTFields(JNIEnv *env, jobject lpObject, SMALL_RECT *lpStruct)
+{
+ if (!SMALL_RECTFc.cached) cacheSMALL_RECTFields(env, lpObject);
+ (*env)->SetShortField(env, lpObject, SMALL_RECTFc.left, (jshort)lpStruct->Left);
+ (*env)->SetShortField(env, lpObject, SMALL_RECTFc.top, (jshort)lpStruct->Top);
+ (*env)->SetShortField(env, lpObject, SMALL_RECTFc.right, (jshort)lpStruct->Right);
+ (*env)->SetShortField(env, lpObject, SMALL_RECTFc.bottom, (jshort)lpStruct->Bottom);
+}
+
+typedef struct WINDOW_BUFFER_SIZE_RECORD_FID_CACHE {
+ int cached;
+ jclass clazz;
+ jfieldID size;
+} WINDOW_BUFFER_SIZE_RECORD_FID_CACHE;
+
+WINDOW_BUFFER_SIZE_RECORD_FID_CACHE WINDOW_BUFFER_SIZE_RECORDFc;
+
+void cacheWINDOW_BUFFER_SIZE_RECORDFields(JNIEnv *env, jobject lpObject)
+{
+ if (WINDOW_BUFFER_SIZE_RECORDFc.cached) return;
+ WINDOW_BUFFER_SIZE_RECORDFc.clazz = (*env)->GetObjectClass(env, lpObject);
+ WINDOW_BUFFER_SIZE_RECORDFc.size = (*env)->GetFieldID(env, WINDOW_BUFFER_SIZE_RECORDFc.clazz, "size", "Lorg/jline/nativ/Kernel32$COORD;");
+ hawtjni_w_barrier();
+ WINDOW_BUFFER_SIZE_RECORDFc.cached = 1;
+}
+
+WINDOW_BUFFER_SIZE_RECORD *getWINDOW_BUFFER_SIZE_RECORDFields(JNIEnv *env, jobject lpObject, WINDOW_BUFFER_SIZE_RECORD *lpStruct)
+{
+ if (!WINDOW_BUFFER_SIZE_RECORDFc.cached) cacheWINDOW_BUFFER_SIZE_RECORDFields(env, lpObject);
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, WINDOW_BUFFER_SIZE_RECORDFc.size);
+ if (lpObject1 != NULL) getCOORDFields(env, lpObject1, &lpStruct->dwSize);
+ }
+ return lpStruct;
+}
+
+void setWINDOW_BUFFER_SIZE_RECORDFields(JNIEnv *env, jobject lpObject, WINDOW_BUFFER_SIZE_RECORD *lpStruct)
+{
+ if (!WINDOW_BUFFER_SIZE_RECORDFc.cached) cacheWINDOW_BUFFER_SIZE_RECORDFields(env, lpObject);
+ {
+ jobject lpObject1 = (*env)->GetObjectField(env, lpObject, WINDOW_BUFFER_SIZE_RECORDFc.size);
+ if (lpObject1 != NULL) setCOORDFields(env, lpObject1, &lpStruct->dwSize);
+ }
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(CloseHandle)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ jint rc = 0;
+ rc = (jint)CloseHandle((HANDLE)arg0);
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(FillConsoleOutputAttribute)
+ (JNIEnv *env, jclass that, jlong arg0, jshort arg1, jint arg2, jobject arg3, jintArray arg4)
+{
+ COORD _arg3, *lparg3=NULL;
+ jint *lparg4=NULL;
+ jint rc = 0;
+ if (arg3) if ((lparg3 = getCOORDFields(env, arg3, &_arg3)) == NULL) goto fail;
+ if (arg4) if ((lparg4 = (*env)->GetIntArrayElements(env, arg4, NULL)) == NULL) goto fail;
+ rc = (jint)FillConsoleOutputAttribute((HANDLE)(intptr_t)arg0, arg1, arg2, *lparg3, lparg4);
+fail:
+ if (arg4 && lparg4) (*env)->ReleaseIntArrayElements(env, arg4, lparg4, 0);
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(FillConsoleOutputCharacterW)
+ (JNIEnv *env, jclass that, jlong arg0, jchar arg1, jint arg2, jobject arg3, jintArray arg4)
+{
+ COORD _arg3, *lparg3=NULL;
+ jint *lparg4=NULL;
+ jint rc = 0;
+ if (arg3) if ((lparg3 = getCOORDFields(env, arg3, &_arg3)) == NULL) goto fail;
+ if (arg4) if ((lparg4 = (*env)->GetIntArrayElements(env, arg4, NULL)) == NULL) goto fail;
+ rc = (jint)FillConsoleOutputCharacterW((HANDLE)(intptr_t)arg0, arg1, arg2, *lparg3, lparg4);
+fail:
+ if (arg4 && lparg4) (*env)->ReleaseIntArrayElements(env, arg4, lparg4, 0);
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(FlushConsoleInputBuffer)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ jint rc = 0;
+ rc = (jint)FlushConsoleInputBuffer((HANDLE)(intptr_t)arg0);
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(FormatMessageW)
+ (JNIEnv *env, jclass that, jint arg0, jlong arg1, jint arg2, jint arg3, jbyteArray arg4, jint arg5, jlongArray arg6)
+{
+ jbyte *lparg4=NULL;
+ jlong *lparg6=NULL;
+ jint rc = 0;
+ if (arg4) if ((lparg4 = (*env)->GetPrimitiveArrayCritical(env, arg4, NULL)) == NULL) goto fail;
+ if (arg6) if ((lparg6 = (*env)->GetPrimitiveArrayCritical(env, arg6, NULL)) == NULL) goto fail;
+ rc = (jint)FormatMessageW(arg0, (void *)(intptr_t)arg1, arg2, arg3, (void *)lparg4, arg5, (void *)NULL);
+fail:
+ if (arg6 && lparg6) (*env)->ReleasePrimitiveArrayCritical(env, arg6, lparg6, 0);
+ if (arg4 && lparg4) (*env)->ReleasePrimitiveArrayCritical(env, arg4, lparg4, 0);
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(GetConsoleMode)
+ (JNIEnv *env, jclass that, jlong arg0, jintArray arg1)
+{
+ jint *lparg1=NULL;
+ jint rc = 0;
+ if (arg1) if ((lparg1 = (*env)->GetIntArrayElements(env, arg1, NULL)) == NULL) goto fail;
+ rc = (jint)GetConsoleMode((HANDLE)(intptr_t)arg0, lparg1);
+fail:
+ if (arg1 && lparg1) (*env)->ReleaseIntArrayElements(env, arg1, lparg1, 0);
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(GetConsoleOutputCP)
+ (JNIEnv *env, jclass that)
+{
+ jint rc = 0;
+ rc = (jint)GetConsoleOutputCP();
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(GetConsoleScreenBufferInfo)
+ (JNIEnv *env, jclass that, jlong arg0, jobject arg1)
+{
+ CONSOLE_SCREEN_BUFFER_INFO _arg1, *lparg1=NULL;
+ jint rc = 0;
+ if (arg1) if ((lparg1 = &_arg1) == NULL) goto fail;
+ rc = (jint)GetConsoleScreenBufferInfo((HANDLE)(intptr_t)arg0, lparg1);
+fail:
+ if (arg1 && lparg1) setCONSOLE_SCREEN_BUFFER_INFOFields(env, arg1, lparg1);
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(GetLastError)
+ (JNIEnv *env, jclass that)
+{
+ jint rc = 0;
+ rc = (jint)GetLastError();
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(GetNumberOfConsoleInputEvents)
+ (JNIEnv *env, jclass that, jlong arg0, jintArray arg1)
+{
+ jint *lparg1=NULL;
+ jint rc = 0;
+ if (arg1) if ((lparg1 = (*env)->GetIntArrayElements(env, arg1, NULL)) == NULL) goto fail;
+ rc = (jint)GetNumberOfConsoleInputEvents((HANDLE)(intptr_t)arg0, lparg1);
+fail:
+ if (arg1 && lparg1) (*env)->ReleaseIntArrayElements(env, arg1, lparg1, 0);
+ return rc;
+}
+
+JNIEXPORT jlong JNICALL Kernel32_NATIVE(GetStdHandle)
+ (JNIEnv *env, jclass that, jint arg0)
+{
+ jlong rc = 0;
+ rc = (intptr_t)(HANDLE)GetStdHandle(arg0);
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(PeekConsoleInputW)
+ (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jint arg2, jintArray arg3)
+{
+ jint *lparg3=NULL;
+ jint rc = 0;
+ if (arg3) if ((lparg3 = (*env)->GetIntArrayElements(env, arg3, NULL)) == NULL) goto fail;
+ rc = (jint)PeekConsoleInputW((HANDLE)(intptr_t)arg0, (PINPUT_RECORD)(intptr_t)arg1, arg2, lparg3);
+fail:
+ if (arg3 && lparg3) (*env)->ReleaseIntArrayElements(env, arg3, lparg3, 0);
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(ReadConsoleInputW)
+ (JNIEnv *env, jclass that, jlong arg0, jlong arg1, jint arg2, jintArray arg3)
+{
+ jint *lparg3=NULL;
+ jint rc = 0;
+ if (arg3) if ((lparg3 = (*env)->GetIntArrayElements(env, arg3, NULL)) == NULL) goto fail;
+ rc = (jint)ReadConsoleInputW((HANDLE)(intptr_t)arg0, (PINPUT_RECORD)(intptr_t)arg1, arg2, lparg3);
+fail:
+ if (arg3 && lparg3) (*env)->ReleaseIntArrayElements(env, arg3, lparg3, 0);
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(ScrollConsoleScreenBuffer)
+ (JNIEnv *env, jclass that, jlong arg0, jobject arg1, jobject arg2, jobject arg3, jobject arg4)
+{
+ SMALL_RECT _arg1, *lparg1=NULL;
+ SMALL_RECT _arg2, *lparg2=NULL;
+ COORD _arg3, *lparg3=NULL;
+ CHAR_INFO _arg4, *lparg4=NULL;
+ jint rc = 0;
+ if (arg1) if ((lparg1 = getSMALL_RECTFields(env, arg1, &_arg1)) == NULL) goto fail;
+ if (arg2) if ((lparg2 = getSMALL_RECTFields(env, arg2, &_arg2)) == NULL) goto fail;
+ if (arg3) if ((lparg3 = getCOORDFields(env, arg3, &_arg3)) == NULL) goto fail;
+ if (arg4) if ((lparg4 = getCHAR_INFOFields(env, arg4, &_arg4)) == NULL) goto fail;
+ rc = (jint)ScrollConsoleScreenBuffer((HANDLE)(intptr_t)arg0, lparg1, lparg2, *lparg3, lparg4);
+fail:
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(SetConsoleCursorPosition)
+ (JNIEnv *env, jclass that, jlong arg0, jobject arg1)
+{
+ COORD _arg1, *lparg1=NULL;
+ jint rc = 0;
+ if (arg1) if ((lparg1 = getCOORDFields(env, arg1, &_arg1)) == NULL) goto fail;
+ rc = (jint)SetConsoleCursorPosition((HANDLE)(intptr_t)arg0, *lparg1);
+fail:
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(SetConsoleMode)
+ (JNIEnv *env, jclass that, jlong arg0, jint arg1)
+{
+ return (jint)SetConsoleMode((HANDLE)(intptr_t)arg0, arg1);
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(SetConsoleOutputCP)
+ (JNIEnv *env, jclass that, jint arg0)
+{
+ return (jint)SetConsoleOutputCP(arg0);
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(SetConsoleTextAttribute)
+ (JNIEnv *env, jclass that, jlong arg0, jshort arg1)
+{
+ return (jint)SetConsoleTextAttribute((HANDLE)arg0, arg1);
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(SetConsoleTitle)
+ (JNIEnv *env, jclass that, jstring arg0)
+{
+ const jchar *lparg0= NULL;
+ jint rc = 0;
+ if (arg0) if ((lparg0 = (*env)->GetStringChars(env, arg0, NULL)) == NULL) goto fail;
+ rc = (jint)SetConsoleTitle(lparg0);
+fail:
+ if (arg0 && lparg0) (*env)->ReleaseStringChars(env, arg0, lparg0);
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(WaitForSingleObject)
+ (JNIEnv *env, jclass that, jlong arg0, jint arg1)
+{
+ return (jint)WaitForSingleObject((HANDLE)arg0, arg1);
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(WriteConsoleW)
+ (JNIEnv *env, jclass that, jlong arg0, jcharArray arg1, jint arg2, jintArray arg3, jlong arg4)
+{
+ jchar *lparg1=NULL;
+ jint *lparg3=NULL;
+ jint rc = 0;
+ if (arg1) if ((lparg1 = (*env)->GetCharArrayElements(env, arg1, NULL)) == NULL) goto fail;
+ if (arg3) if ((lparg3 = (*env)->GetIntArrayElements(env, arg3, NULL)) == NULL) goto fail;
+ rc = (jint)WriteConsoleW((HANDLE)(intptr_t)arg0, lparg1, arg2, lparg3, (LPVOID)(intptr_t)arg4);
+fail:
+ if (arg3 && lparg3) (*env)->ReleaseIntArrayElements(env, arg3, lparg3, 0);
+ if (arg1 && lparg1) (*env)->ReleaseCharArrayElements(env, arg1, lparg1, JNI_ABORT);
+ return rc;
+}
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(_1getch)
+ (JNIEnv *env, jclass that)
+{
+ jint rc = 0;
+ rc = (jint)_getch();
+ return rc;
+}
+
+JNIEXPORT void JNICALL Kernel32_NATIVE(free)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ free((void *)(intptr_t)arg0);
+}
+
+JNIEXPORT void JNICALL Kernel32_NATIVE(init)(JNIEnv *env, jclass that)
+{
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "FOREGROUND_BLUE", "S"), (jshort)FOREGROUND_BLUE);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "FOREGROUND_GREEN", "S"), (jshort)FOREGROUND_GREEN);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "FOREGROUND_RED", "S"), (jshort)FOREGROUND_RED);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "FOREGROUND_INTENSITY", "S"), (jshort)FOREGROUND_INTENSITY);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "BACKGROUND_BLUE", "S"), (jshort)BACKGROUND_BLUE);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "BACKGROUND_GREEN", "S"), (jshort)BACKGROUND_GREEN);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "BACKGROUND_RED", "S"), (jshort)BACKGROUND_RED);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "BACKGROUND_INTENSITY", "S"), (jshort)BACKGROUND_INTENSITY);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "COMMON_LVB_LEADING_BYTE", "S"), (jshort)COMMON_LVB_LEADING_BYTE);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "COMMON_LVB_TRAILING_BYTE", "S"), (jshort)COMMON_LVB_TRAILING_BYTE);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "COMMON_LVB_GRID_HORIZONTAL", "S"), (jshort)COMMON_LVB_GRID_HORIZONTAL);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "COMMON_LVB_GRID_LVERTICAL", "S"), (jshort)COMMON_LVB_GRID_LVERTICAL);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "COMMON_LVB_GRID_RVERTICAL", "S"), (jshort)COMMON_LVB_GRID_RVERTICAL);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "COMMON_LVB_REVERSE_VIDEO", "S"), (jshort)COMMON_LVB_REVERSE_VIDEO);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "COMMON_LVB_UNDERSCORE", "S"), (jshort)COMMON_LVB_UNDERSCORE);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "FORMAT_MESSAGE_FROM_SYSTEM", "I"), (jint)FORMAT_MESSAGE_FROM_SYSTEM);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "STD_INPUT_HANDLE", "I"), (jint)STD_INPUT_HANDLE);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "STD_OUTPUT_HANDLE", "I"), (jint)STD_OUTPUT_HANDLE);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "STD_ERROR_HANDLE", "I"), (jint)STD_ERROR_HANDLE);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "INVALID_HANDLE_VALUE", "I"), (jint)INVALID_HANDLE_VALUE);
+ return;
+}
+
+JNIEXPORT jlong JNICALL Kernel32_NATIVE(malloc)
+ (JNIEnv *env, jclass that, jlong arg0)
+{
+ jlong rc = 0;
+ rc = (intptr_t)(void *)malloc((size_t)arg0);
+ return rc;
+}
+
+JNIEXPORT void JNICALL CHAR_INFO_NATIVE(init)(JNIEnv *env, jclass that)
+{
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SIZEOF", "I"), (jint)sizeof(CHAR_INFO));
+ return;
+}
+
+JNIEXPORT void JNICALL CONSOLE_SCREEN_BUFFER_INFO_NATIVE(init)(JNIEnv *env, jclass that)
+{
+#if defined(_WIN32) || defined(_WIN64)
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SIZEOF", "I"), (jint)sizeof(CONSOLE_SCREEN_BUFFER_INFO));
+#endif
+ return;
+}
+
+JNIEXPORT void JNICALL COORD_NATIVE(init)(JNIEnv *env, jclass that)
+{
+#if defined(_WIN32) || defined(_WIN64)
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SIZEOF", "I"), (jint)sizeof(COORD));
+#endif
+ return;
+}
+
+JNIEXPORT void JNICALL FOCUS_EVENT_RECORD_NATIVE(init)(JNIEnv *env, jclass that)
+{
+#if defined(_WIN32) || defined(_WIN64)
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SIZEOF", "I"), (jint)sizeof(WINDOW_BUFFER_SIZE_RECORD));
+#endif
+ return;
+}
+
+JNIEXPORT void JNICALL INPUT_RECORD_NATIVE(init)(JNIEnv *env, jclass that)
+{
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SIZEOF", "I"), (jint)sizeof(INPUT_RECORD));
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "KEY_EVENT", "S"), (jshort)KEY_EVENT);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "MOUSE_EVENT", "S"), (jshort)MOUSE_EVENT);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "WINDOW_BUFFER_SIZE_EVENT", "S"), (jshort)WINDOW_BUFFER_SIZE_EVENT);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "FOCUS_EVENT", "S"), (jshort)FOCUS_EVENT);
+ (*env)->SetStaticShortField(env, that, (*env)->GetStaticFieldID(env, that, "MENU_EVENT", "S"), (jshort)MENU_EVENT);
+ return;
+}
+JNIEXPORT void JNICALL INPUT_RECORD_NATIVE(memmove)
+ (JNIEnv *env, jclass that, jobject arg0, jlong arg1, jlong arg2)
+{
+ INPUT_RECORD _arg0, *lparg0=NULL;
+ if (arg0) if ((lparg0 = &_arg0) == NULL) goto fail;
+ memmove((void *)lparg0, (const void *)(intptr_t)arg1, (size_t)arg2);
+fail:
+ if (arg0 && lparg0) setINPUT_RECORDFields(env, arg0, lparg0);
+}
+
+JNIEXPORT void JNICALL KEY_EVENT_RECORD_NATIVE(init)(JNIEnv *env, jclass that)
+{
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SIZEOF", "I"), (jint)sizeof(KEY_EVENT_RECORD));
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "CAPSLOCK_ON", "I"), (jint)CAPSLOCK_ON);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "NUMLOCK_ON", "I"), (jint)NUMLOCK_ON);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SCROLLLOCK_ON", "I"), (jint)SCROLLLOCK_ON);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "ENHANCED_KEY", "I"), (jint)ENHANCED_KEY);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "LEFT_ALT_PRESSED", "I"), (jint)LEFT_ALT_PRESSED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "LEFT_CTRL_PRESSED", "I"), (jint)LEFT_CTRL_PRESSED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "RIGHT_ALT_PRESSED", "I"), (jint)RIGHT_ALT_PRESSED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "RIGHT_CTRL_PRESSED", "I"), (jint)RIGHT_CTRL_PRESSED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SHIFT_PRESSED", "I"), (jint)SHIFT_PRESSED);
+ return;
+}
+
+JNIEXPORT void JNICALL MENU_EVENT_RECORD_NATIVE(init)(JNIEnv *env, jclass that)
+{
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SIZEOF", "I"), (jint)sizeof(MENU_EVENT_RECORD));
+ return;
+}
+
+JNIEXPORT void JNICALL MOUSE_EVENT_RECORD_NATIVE(init)(JNIEnv *env, jclass that)
+{
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SIZEOF", "I"), (jint)sizeof(MOUSE_EVENT_RECORD));
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "FROM_LEFT_1ST_BUTTON_PRESSED", "I"), (jint)FROM_LEFT_1ST_BUTTON_PRESSED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "FROM_LEFT_2ND_BUTTON_PRESSED", "I"), (jint)FROM_LEFT_2ND_BUTTON_PRESSED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "FROM_LEFT_3RD_BUTTON_PRESSED", "I"), (jint)FROM_LEFT_3RD_BUTTON_PRESSED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "FROM_LEFT_4TH_BUTTON_PRESSED", "I"), (jint)FROM_LEFT_4TH_BUTTON_PRESSED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "RIGHTMOST_BUTTON_PRESSED", "I"), (jint)RIGHTMOST_BUTTON_PRESSED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "CAPSLOCK_ON", "I"), (jint)CAPSLOCK_ON);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "NUMLOCK_ON", "I"), (jint)NUMLOCK_ON);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SCROLLLOCK_ON", "I"), (jint)SCROLLLOCK_ON);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "ENHANCED_KEY", "I"), (jint)ENHANCED_KEY);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "LEFT_ALT_PRESSED", "I"), (jint)LEFT_ALT_PRESSED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "LEFT_CTRL_PRESSED", "I"), (jint)LEFT_CTRL_PRESSED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "RIGHT_ALT_PRESSED", "I"), (jint)RIGHT_ALT_PRESSED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "RIGHT_CTRL_PRESSED", "I"), (jint)RIGHT_CTRL_PRESSED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SHIFT_PRESSED", "I"), (jint)SHIFT_PRESSED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "DOUBLE_CLICK", "I"), (jint)DOUBLE_CLICK);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "MOUSE_HWHEELED", "I"), (jint)MOUSE_HWHEELED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "MOUSE_MOVED", "I"), (jint)MOUSE_MOVED);
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "MOUSE_WHEELED", "I"), (jint)MOUSE_WHEELED);
+ return;
+}
+
+JNIEXPORT void JNICALL SMALL_RECT_NATIVE(init)(JNIEnv *env, jclass that)
+{
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SIZEOF", "I"), (jint)sizeof(SMALL_RECT));
+ return;
+}
+
+JNIEXPORT void JNICALL WINDOW_BUFFER_SIZE_RECORD_NATIVE(init)(JNIEnv *env, jclass that)
+{
+ (*env)->SetStaticIntField(env, that, (*env)->GetStaticFieldID(env, that, "SIZEOF", "I"), (jint)sizeof(WINDOW_BUFFER_SIZE_RECORD));
+ return;
+}
+
+typedef struct _UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Buffer;
+} UNICODE_STRING, *PUNICODE_STRING;
+
+typedef struct _OBJECT_NAME_INFORMATION {
+ UNICODE_STRING Name;
+ WCHAR NameBuffer[0];
+} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
+
+typedef enum {
+ ObjectBasicInformation,
+ ObjectNameInformation,
+ ObjectTypeInformation,
+ ObjectAllInformation,
+ ObjectDataInformation
+} OBJECT_INFORMATION_CLASS;
+
+typedef NTSTATUS (NTAPI *TFNNtQueryObject)(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG);
+TFNNtQueryObject NtQueryObject = 0;
+
+HANDLE hModuleNtDll = 0;
+
+JNIEXPORT jint JNICALL Kernel32_NATIVE(isatty)
+ (JNIEnv *env, jclass that, jint arg0)
+{
+ jint rc;
+
+ ULONG result;
+ BYTE buffer[1024];
+ POBJECT_NAME_INFORMATION nameinfo = (POBJECT_NAME_INFORMATION) buffer;
+ PWSTR name;
+ DWORD mode;
+
+ /* check if fd is a pipe */
+ HANDLE h = (HANDLE) _get_osfhandle(arg0);
+ DWORD t = h != NULL ? GetFileType(h) : 0;
+ if (h != NULL && t == FILE_TYPE_CHAR) {
+ // check that this is a real tty because the /dev/null
+ // and /dev/zero streams are also of type FILE_TYPE_CHAR
+ rc = GetConsoleMode(h, &mode) != 0;
+ }
+ else {
+ if (hModuleNtDll == 0) {
+ hModuleNtDll = LoadLibraryW(L"ntdll.dll");
+ }
+ if (hModuleNtDll == 0) {
+ rc = 0;
+ }
+ else {
+ if (NtQueryObject == 0) {
+ NtQueryObject = (TFNNtQueryObject) GetProcAddress(hModuleNtDll, "NtQueryObject");
+ }
+ if (NtQueryObject == 0) {
+ rc = 0;
+ }
+ /* get pipe name */
+ else if (NtQueryObject(h, ObjectNameInformation, buffer, sizeof(buffer) - 2, &result) != 0) {
+ rc = 0;
+ }
+ else {
+
+ name = nameinfo->Name.Buffer;
+ if (name == NULL) {
+ rc = 0;
+ }
+ else {
+ name[nameinfo->Name.Length / 2] = 0;
+
+ //fprintf( stderr, "Standard stream %d: pipe name: %S\n", arg0, name);
+
+ /*
+ * Check if this could be a MSYS2 pty pipe ('msys-XXXX-ptyN-XX')
+ * or a cygwin pty pipe ('cygwin-XXXX-ptyN-XX')
+ */
+ if ((wcsstr(name, L"msys-") || wcsstr(name, L"cygwin-")) && wcsstr(name, L"-pty")) {
+ rc = 1;
+ } else {
+ // This is definitely not a tty
+ rc = 0;
+ }
+ }
+ }
+ }
+ }
+
+ return rc;
+}
+
+#endif
diff --git a/native/src/main/resources/org/jline/nativ/FreeBSD/x86/libjlinenative.so b/native/src/main/resources/org/jline/nativ/FreeBSD/x86/libjlinenative.so
index 9ad59f06b..13258b54e 100755
Binary files a/native/src/main/resources/org/jline/nativ/FreeBSD/x86/libjlinenative.so and b/native/src/main/resources/org/jline/nativ/FreeBSD/x86/libjlinenative.so differ
diff --git a/native/src/main/resources/org/jline/nativ/FreeBSD/x86_64/libjlinenative.so b/native/src/main/resources/org/jline/nativ/FreeBSD/x86_64/libjlinenative.so
index db84a0835..fa5064632 100755
Binary files a/native/src/main/resources/org/jline/nativ/FreeBSD/x86_64/libjlinenative.so and b/native/src/main/resources/org/jline/nativ/FreeBSD/x86_64/libjlinenative.so differ
diff --git a/native/src/main/resources/org/jline/nativ/Linux/arm/libjlinenative.so b/native/src/main/resources/org/jline/nativ/Linux/arm/libjlinenative.so
index f67f1e324..6791f478d 100755
Binary files a/native/src/main/resources/org/jline/nativ/Linux/arm/libjlinenative.so and b/native/src/main/resources/org/jline/nativ/Linux/arm/libjlinenative.so differ
diff --git a/native/src/main/resources/org/jline/nativ/Linux/arm64/libjlinenative.so b/native/src/main/resources/org/jline/nativ/Linux/arm64/libjlinenative.so
index f6b05768f..de656faad 100755
Binary files a/native/src/main/resources/org/jline/nativ/Linux/arm64/libjlinenative.so and b/native/src/main/resources/org/jline/nativ/Linux/arm64/libjlinenative.so differ
diff --git a/native/src/main/resources/org/jline/nativ/Linux/armv6/libjlinenative.so b/native/src/main/resources/org/jline/nativ/Linux/armv6/libjlinenative.so
index 189d638e4..bfe352076 100755
Binary files a/native/src/main/resources/org/jline/nativ/Linux/armv6/libjlinenative.so and b/native/src/main/resources/org/jline/nativ/Linux/armv6/libjlinenative.so differ
diff --git a/native/src/main/resources/org/jline/nativ/Linux/armv7/libjlinenative.so b/native/src/main/resources/org/jline/nativ/Linux/armv7/libjlinenative.so
index 841b5e54f..d546f10ca 100755
Binary files a/native/src/main/resources/org/jline/nativ/Linux/armv7/libjlinenative.so and b/native/src/main/resources/org/jline/nativ/Linux/armv7/libjlinenative.so differ
diff --git a/native/src/main/resources/org/jline/nativ/Linux/ppc64/libjlinenative.so b/native/src/main/resources/org/jline/nativ/Linux/ppc64/libjlinenative.so
index 9c06e44d0..e79106572 100755
Binary files a/native/src/main/resources/org/jline/nativ/Linux/ppc64/libjlinenative.so and b/native/src/main/resources/org/jline/nativ/Linux/ppc64/libjlinenative.so differ
diff --git a/native/src/main/resources/org/jline/nativ/Linux/x86/libjlinenative.so b/native/src/main/resources/org/jline/nativ/Linux/x86/libjlinenative.so
index ff8aef34d..932849e3d 100755
Binary files a/native/src/main/resources/org/jline/nativ/Linux/x86/libjlinenative.so and b/native/src/main/resources/org/jline/nativ/Linux/x86/libjlinenative.so differ
diff --git a/native/src/main/resources/org/jline/nativ/Linux/x86_64/libjlinenative.so b/native/src/main/resources/org/jline/nativ/Linux/x86_64/libjlinenative.so
index 918a45b3b..5772a2538 100755
Binary files a/native/src/main/resources/org/jline/nativ/Linux/x86_64/libjlinenative.so and b/native/src/main/resources/org/jline/nativ/Linux/x86_64/libjlinenative.so differ
diff --git a/native/src/main/resources/org/jline/nativ/Mac/arm64/libjlinenative.jnilib b/native/src/main/resources/org/jline/nativ/Mac/arm64/libjlinenative.jnilib
index b968d5e5a..d30f8cbb1 100755
Binary files a/native/src/main/resources/org/jline/nativ/Mac/arm64/libjlinenative.jnilib and b/native/src/main/resources/org/jline/nativ/Mac/arm64/libjlinenative.jnilib differ
diff --git a/native/src/main/resources/org/jline/nativ/Mac/x86/libjlinenative.jnilib b/native/src/main/resources/org/jline/nativ/Mac/x86/libjlinenative.jnilib
index e1c953ffa..3418272cd 100755
Binary files a/native/src/main/resources/org/jline/nativ/Mac/x86/libjlinenative.jnilib and b/native/src/main/resources/org/jline/nativ/Mac/x86/libjlinenative.jnilib differ
diff --git a/native/src/main/resources/org/jline/nativ/Mac/x86_64/libjlinenative.jnilib b/native/src/main/resources/org/jline/nativ/Mac/x86_64/libjlinenative.jnilib
index d7f243142..e82521301 100755
Binary files a/native/src/main/resources/org/jline/nativ/Mac/x86_64/libjlinenative.jnilib and b/native/src/main/resources/org/jline/nativ/Mac/x86_64/libjlinenative.jnilib differ
diff --git a/native/src/main/resources/org/jline/nativ/Windows/arm64/libjlinenative.so b/native/src/main/resources/org/jline/nativ/Windows/arm64/libjlinenative.so
new file mode 100755
index 000000000..3fa5ec086
Binary files /dev/null and b/native/src/main/resources/org/jline/nativ/Windows/arm64/libjlinenative.so differ
diff --git a/native/src/main/resources/org/jline/nativ/Windows/x86/jlinenative.dll b/native/src/main/resources/org/jline/nativ/Windows/x86/jlinenative.dll
index 10ddc9c48..f6bfa9ee6 100755
Binary files a/native/src/main/resources/org/jline/nativ/Windows/x86/jlinenative.dll and b/native/src/main/resources/org/jline/nativ/Windows/x86/jlinenative.dll differ
diff --git a/native/src/main/resources/org/jline/nativ/Windows/x86_64/jlinenative.dll b/native/src/main/resources/org/jline/nativ/Windows/x86_64/jlinenative.dll
index 28e694811..6b252cf1e 100755
Binary files a/native/src/main/resources/org/jline/nativ/Windows/x86_64/jlinenative.dll and b/native/src/main/resources/org/jline/nativ/Windows/x86_64/jlinenative.dll differ
diff --git a/pom.xml b/pom.xml
index 6e1e237ce..f8c6af67a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,6 +61,7 @@
terminal-ffm
terminal-jna
terminal-jansi
+ terminal-jni
reader
builtins
console
@@ -144,6 +145,12 @@
${project.version}
+
+ org.jline
+ jline-terminal-jni
+ ${project.version}
+
+
org.jline
jline-terminal-jna
diff --git a/reader/src/test/java/org/jline/terminal/impl/ExternalTerminalTest.java b/reader/src/test/java/org/jline/terminal/impl/ExternalTerminalTest.java
index 7d2e28557..76a069a24 100644
--- a/reader/src/test/java/org/jline/terminal/impl/ExternalTerminalTest.java
+++ b/reader/src/test/java/org/jline/terminal/impl/ExternalTerminalTest.java
@@ -61,19 +61,6 @@ public void testInput() throws IOException, InterruptedException {
testConsole(outIn, out, console);
}
- /* SANDBOX JANSI
- @Test
- public void testPosix() throws IOException, InterruptedException {
- PipedInputStream in = new PipedInputStream();
- PipedOutputStream outIn = new PipedOutputStream(in);
- ByteArrayOutputStream out = new ByteArrayOutputStream();
-
- Console terminal = new PosixPtyConsole("ansi", new ConsoleReaderBuilder(), NativePty.open(null, null), in, out, "UTF-8");
-
- testConsole(outIn, out, terminal);
- }
- */
-
private void testConsole(PipedOutputStream outIn, ByteArrayOutputStream out, Terminal terminal)
throws IOException, InterruptedException {
Attributes attributes = terminal.getAttributes();
diff --git a/terminal-jni/pom.xml b/terminal-jni/pom.xml
new file mode 100644
index 000000000..94183a86e
--- /dev/null
+++ b/terminal-jni/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+
+ 4.0.0
+
+
+ org.jline
+ jline-parent
+ 3.23.1-SNAPSHOT
+
+
+ jline-terminal-jni
+ JLine JNI Terminal
+
+
+ org.jline.terminal.jni
+
+
+
+
+ org.jline
+ jline-native
+
+
+
+ org.jline
+ jline-terminal
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+
+
+ *;-noimport:=true
+ org.jline.terminal
+
+
+
+
+
+
+
diff --git a/terminal-jni/src/main/java/org/jline/terminal/impl/jni/JniNativePty.java b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/JniNativePty.java
new file mode 100644
index 000000000..a6faaa89e
--- /dev/null
+++ b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/JniNativePty.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2002-2020, 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 org.jline.terminal.impl.jni;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.jline.nativ.CLibrary;
+import org.jline.nativ.Kernel32;
+import org.jline.terminal.Attributes;
+import org.jline.terminal.Size;
+import org.jline.terminal.impl.AbstractPty;
+import org.jline.terminal.impl.jni.win.NativeWinSysTerminal;
+import org.jline.terminal.spi.Pty;
+import org.jline.terminal.spi.SystemStream;
+import org.jline.terminal.spi.TerminalProvider;
+import org.jline.utils.OSUtils;
+
+import static org.jline.nativ.CLibrary.TCSANOW;
+
+public abstract class JniNativePty extends AbstractPty implements Pty {
+
+ private final int master;
+ private final int slave;
+ private final int slaveOut;
+ private final String name;
+ private final FileDescriptor masterFD;
+ private final FileDescriptor slaveFD;
+ private final FileDescriptor slaveOutFD;
+
+ public JniNativePty(
+ TerminalProvider provider,
+ SystemStream systemStream,
+ int master,
+ FileDescriptor masterFD,
+ int slave,
+ FileDescriptor slaveFD,
+ String name) {
+ this(provider, systemStream, master, masterFD, slave, slaveFD, slave, slaveFD, name);
+ }
+
+ public JniNativePty(
+ TerminalProvider provider,
+ SystemStream systemStream,
+ int master,
+ FileDescriptor masterFD,
+ int slave,
+ FileDescriptor slaveFD,
+ int slaveOut,
+ FileDescriptor slaveOutFD,
+ String name) {
+ super(provider, systemStream);
+ this.master = master;
+ this.slave = slave;
+ this.slaveOut = slaveOut;
+ this.name = name;
+ this.masterFD = masterFD;
+ this.slaveFD = slaveFD;
+ this.slaveOutFD = slaveOutFD;
+ }
+
+ protected static String ttyname(int fd) throws IOException {
+ String name = CLibrary.ttyname(fd);
+ if (name != null) {
+ name = name.trim();
+ }
+ if (name == null || name.isEmpty()) {
+ throw new IOException("Not a tty");
+ }
+ return name;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (master > 0) {
+ getMasterInput().close();
+ }
+ if (slave > 0) {
+ getSlaveInput().close();
+ }
+ }
+
+ public int getMaster() {
+ return master;
+ }
+
+ public int getSlave() {
+ return slave;
+ }
+
+ public int getSlaveOut() {
+ return slaveOut;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public FileDescriptor getMasterFD() {
+ return masterFD;
+ }
+
+ public FileDescriptor getSlaveFD() {
+ return slaveFD;
+ }
+
+ public FileDescriptor getSlaveOutFD() {
+ return slaveOutFD;
+ }
+
+ public InputStream getMasterInput() {
+ return new FileInputStream(getMasterFD());
+ }
+
+ public OutputStream getMasterOutput() {
+ return new FileOutputStream(getMasterFD());
+ }
+
+ protected InputStream doGetSlaveInput() {
+ return new FileInputStream(getSlaveFD());
+ }
+
+ public OutputStream getSlaveOutput() {
+ return new FileOutputStream(getSlaveOutFD());
+ }
+
+ @Override
+ public Attributes getAttr() throws IOException {
+ CLibrary.Termios tios = new CLibrary.Termios();
+ CLibrary.tcgetattr(slave, tios);
+ return toAttributes(tios);
+ }
+
+ @Override
+ protected void doSetAttr(Attributes attr) throws IOException {
+ CLibrary.Termios tios = toTermios(attr);
+ CLibrary.tcsetattr(slave, TCSANOW, tios);
+ }
+
+ @Override
+ public Size getSize() throws IOException {
+ CLibrary.WinSize sz = new CLibrary.WinSize();
+ int res = CLibrary.ioctl(slave, CLibrary.TIOCGWINSZ, sz);
+ if (res != 0) {
+ throw new IOException("Error calling ioctl(TIOCGWINSZ): return code is " + res);
+ }
+ return new Size(sz.ws_col, sz.ws_row);
+ }
+
+ @Override
+ public void setSize(Size size) throws IOException {
+ CLibrary.WinSize sz = new CLibrary.WinSize((short) size.getRows(), (short) size.getColumns());
+ int res = CLibrary.ioctl(slave, CLibrary.TIOCSWINSZ, sz);
+ if (res != 0) {
+ throw new IOException("Error calling ioctl(TIOCSWINSZ): return code is " + res);
+ }
+ }
+
+ protected abstract CLibrary.Termios toTermios(Attributes t);
+
+ protected abstract Attributes toAttributes(CLibrary.Termios tios);
+
+ @Override
+ public String toString() {
+ return "NativePty[" + getName() + "]";
+ }
+
+ public static boolean isPosixSystemStream(SystemStream stream) {
+ return CLibrary.isatty(fd(stream)) == 1;
+ }
+
+ public static String posixSystemStreamName(SystemStream systemStream) {
+ return CLibrary.ttyname(fd(systemStream));
+ }
+
+ public static int systemStreamWidth(SystemStream systemStream) {
+ try {
+ if (OSUtils.IS_WINDOWS) {
+ Kernel32.CONSOLE_SCREEN_BUFFER_INFO info = new Kernel32.CONSOLE_SCREEN_BUFFER_INFO();
+ long outConsole = NativeWinSysTerminal.getConsole(systemStream);
+ Kernel32.GetConsoleScreenBufferInfo(outConsole, info);
+ return info.windowWidth();
+ } else {
+ CLibrary.WinSize sz = new CLibrary.WinSize();
+ int res = CLibrary.ioctl(fd(systemStream), CLibrary.TIOCGWINSZ, sz);
+ if (res != 0) {
+ throw new IOException("Error calling ioctl(TIOCGWINSZ): return code is " + res);
+ }
+ return sz.ws_col;
+ }
+ } catch (Throwable t) {
+ return -1;
+ }
+ }
+
+ private static int fd(SystemStream systemStream) {
+ switch (systemStream) {
+ case Input:
+ return 0;
+ case Output:
+ return 1;
+ case Error:
+ return 2;
+ default:
+ return -1;
+ }
+ }
+}
diff --git a/terminal-jni/src/main/java/org/jline/terminal/impl/jni/JniTerminalProvider.java b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/JniTerminalProvider.java
new file mode 100644
index 000000000..bc59fa332
--- /dev/null
+++ b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/JniTerminalProvider.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2002-2020, 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 org.jline.terminal.impl.jni;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+
+import org.jline.terminal.Attributes;
+import org.jline.terminal.Size;
+import org.jline.terminal.Terminal;
+import org.jline.terminal.impl.PosixPtyTerminal;
+import org.jline.terminal.impl.PosixSysTerminal;
+import org.jline.terminal.impl.jni.freebsd.FreeBsdNativePty;
+import org.jline.terminal.impl.jni.linux.LinuxNativePty;
+import org.jline.terminal.impl.jni.osx.OsXNativePty;
+import org.jline.terminal.impl.jni.solaris.SolarisNativePty;
+import org.jline.terminal.impl.jni.win.NativeWinSysTerminal;
+import org.jline.terminal.spi.Pty;
+import org.jline.terminal.spi.SystemStream;
+import org.jline.terminal.spi.TerminalProvider;
+import org.jline.utils.OSUtils;
+
+public class JniTerminalProvider implements TerminalProvider {
+
+ @Override
+ public String name() {
+ return "native";
+ }
+
+ public Pty current(SystemStream systemStream) throws IOException {
+ String osName = System.getProperty("os.name");
+ if (osName.startsWith("Linux")) {
+ return LinuxNativePty.current(this, systemStream);
+ } else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) {
+ return OsXNativePty.current(this, systemStream);
+ } else if (osName.startsWith("Solaris") || osName.startsWith("SunOS")) {
+ return SolarisNativePty.current(this, systemStream);
+ } else if (osName.startsWith("FreeBSD")) {
+ return FreeBsdNativePty.current(this, systemStream);
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ public Pty open(Attributes attributes, Size size) throws IOException {
+ String osName = System.getProperty("os.name");
+ if (osName.startsWith("Linux")) {
+ return LinuxNativePty.open(this, attributes, size);
+ } else if (osName.startsWith("Mac") || osName.startsWith("Darwin")) {
+ return OsXNativePty.open(this, attributes, size);
+ } else if (osName.startsWith("Solaris") || osName.startsWith("SunOS")) {
+ return SolarisNativePty.open(this, attributes, size);
+ } else if (osName.startsWith("FreeBSD")) {
+ return FreeBsdNativePty.open(this, attributes, size);
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Terminal sysTerminal(
+ String name,
+ String type,
+ boolean ansiPassThrough,
+ Charset encoding,
+ boolean nativeSignals,
+ Terminal.SignalHandler signalHandler,
+ boolean paused,
+ SystemStream systemStream)
+ throws IOException {
+ if (OSUtils.IS_WINDOWS) {
+ return winSysTerminal(
+ name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, systemStream);
+ } else {
+ return posixSysTerminal(
+ name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused, systemStream);
+ }
+ }
+
+ public Terminal winSysTerminal(
+ String name,
+ String type,
+ boolean ansiPassThrough,
+ Charset encoding,
+ boolean nativeSignals,
+ Terminal.SignalHandler signalHandler,
+ boolean paused,
+ SystemStream systemStream)
+ throws IOException {
+ return NativeWinSysTerminal.createTerminal(
+ this, systemStream, name, type, ansiPassThrough, encoding, nativeSignals, signalHandler, paused);
+ }
+
+ public Terminal posixSysTerminal(
+ String name,
+ String type,
+ boolean ansiPassThrough,
+ Charset encoding,
+ boolean nativeSignals,
+ Terminal.SignalHandler signalHandler,
+ boolean paused,
+ SystemStream systemStream)
+ throws IOException {
+ Pty pty = current(systemStream);
+ return new PosixSysTerminal(name, type, pty, encoding, nativeSignals, signalHandler);
+ }
+
+ @Override
+ public Terminal newTerminal(
+ String name,
+ String type,
+ InputStream in,
+ OutputStream out,
+ Charset encoding,
+ Terminal.SignalHandler signalHandler,
+ boolean paused,
+ Attributes attributes,
+ Size size)
+ throws IOException {
+ Pty pty = open(attributes, size);
+ return new PosixPtyTerminal(name, type, pty, in, out, encoding, signalHandler, paused);
+ }
+
+ @Override
+ public boolean isSystemStream(SystemStream stream) {
+ try {
+ if (OSUtils.IS_WINDOWS) {
+ return isWindowsSystemStream(stream);
+ } else {
+ return isPosixSystemStream(stream);
+ }
+ } catch (Throwable t) {
+ return false;
+ }
+ }
+
+ public boolean isWindowsSystemStream(SystemStream stream) {
+ return NativeWinSysTerminal.isWindowsSystemStream(stream);
+ }
+
+ public boolean isPosixSystemStream(SystemStream stream) {
+ return JniNativePty.isPosixSystemStream(stream);
+ }
+
+ @Override
+ public String systemStreamName(SystemStream stream) {
+ return JniNativePty.posixSystemStreamName(stream);
+ }
+
+ @Override
+ public int systemStreamWidth(SystemStream stream) {
+ return JniNativePty.systemStreamWidth(stream);
+ }
+}
diff --git a/terminal-jni/src/main/java/org/jline/terminal/impl/jni/freebsd/FreeBsdNativePty.java b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/freebsd/FreeBsdNativePty.java
new file mode 100644
index 000000000..8708599b1
--- /dev/null
+++ b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/freebsd/FreeBsdNativePty.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2002-2017, 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 org.jline.terminal.impl.jni.freebsd;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.EnumMap;
+import java.util.EnumSet;
+
+import org.jline.nativ.CLibrary;
+import org.jline.terminal.Attributes;
+import org.jline.terminal.Size;
+import org.jline.terminal.impl.jni.JniNativePty;
+import org.jline.terminal.spi.SystemStream;
+import org.jline.terminal.spi.TerminalProvider;
+
+public class FreeBsdNativePty extends JniNativePty {
+
+ public static FreeBsdNativePty current(TerminalProvider provider, SystemStream systemStream) throws IOException {
+ try {
+ switch (systemStream) {
+ case Output:
+ return new FreeBsdNativePty(
+ provider, systemStream, -1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname(1));
+ case Error:
+ return new FreeBsdNativePty(
+ provider, systemStream, -1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname(2));
+ default:
+ throw new IllegalArgumentException("Unsupport stream for console: " + systemStream);
+ }
+ } catch (IOException e) {
+ throw new IOException("Not a tty", e);
+ }
+ }
+
+ public static FreeBsdNativePty open(TerminalProvider provider, Attributes attr, Size size) throws IOException {
+ int[] master = new int[1];
+ int[] slave = new int[1];
+ byte[] buf = new byte[64];
+ CLibrary.openpty(
+ master,
+ slave,
+ buf,
+ attr != null ? termios(attr) : null,
+ size != null ? new CLibrary.WinSize((short) size.getRows(), (short) size.getColumns()) : null);
+ int len = 0;
+ while (buf[len] != 0) {
+ len++;
+ }
+ String name = new String(buf, 0, len);
+ return new FreeBsdNativePty(
+ provider, null, master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name);
+ }
+
+ public FreeBsdNativePty(
+ TerminalProvider provider,
+ SystemStream systemStream,
+ int master,
+ FileDescriptor masterFD,
+ int slave,
+ FileDescriptor slaveFD,
+ String name) {
+ super(provider, systemStream, master, masterFD, slave, slaveFD, name);
+ }
+
+ public FreeBsdNativePty(
+ TerminalProvider provider,
+ SystemStream systemStream,
+ int master,
+ FileDescriptor masterFD,
+ int slave,
+ FileDescriptor slaveFD,
+ int slaveOut,
+ FileDescriptor slaveOutFD,
+ String name) {
+ super(provider, systemStream, master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name);
+ }
+ // CONSTANTS
+
+ private static final int VEOF = 0;
+ private static final int VEOL = 1;
+ private static final int VEOL2 = 2;
+ private static final int VERASE = 3;
+ private static final int VWERASE = 4;
+ private static final int VKILL = 5;
+ private static final int VREPRINT = 6;
+ private static final int VERASE2 = 7;
+ private static final int VINTR = 8;
+ private static final int VQUIT = 9;
+ private static final int VSUSP = 10;
+ private static final int VDSUSP = 11;
+ private static final int VSTART = 12;
+ private static final int VSTOP = 13;
+ private static final int VLNEXT = 14;
+ private static final int VDISCARD = 15;
+ private static final int VMIN = 16;
+ private static final int VTIME = 17;
+ private static final int VSTATUS = 18;
+
+ private static final int IGNBRK = 0x0000001;
+ private static final int BRKINT = 0x0000002;
+ private static final int IGNPAR = 0x0000004;
+ private static final int PARMRK = 0x0000008;
+ private static final int INPCK = 0x0000010;
+ private static final int ISTRIP = 0x0000020;
+ private static final int INLCR = 0x0000040;
+ private static final int IGNCR = 0x0000080;
+ private static final int ICRNL = 0x0000100;
+ private static final int IXON = 0x0000200;
+ private static final int IXOFF = 0x0000400;
+ private static final int IXANY = 0x0000800;
+ private static final int IMAXBEL = 0x0002000;
+
+ private static final int OPOST = 0x0000001;
+ private static final int ONLCR = 0x0000002;
+ private static final int TABDLY = 0x0000004;
+ private static final int TAB0 = 0x0000000;
+ private static final int TAB3 = 0x0000004;
+ private static final int ONOEOT = 0x0000008;
+ private static final int OCRNL = 0x0000010;
+ private static final int ONLRET = 0x0000040;
+
+ private static final int CIGNORE = 0x0000001;
+ private static final int CSIZE = 0x0000300;
+ private static final int CS5 = 0x0000000;
+ private static final int CS6 = 0x0000100;
+ private static final int CS7 = 0x0000200;
+ private static final int CS8 = 0x0000300;
+ private static final int CSTOPB = 0x0000400;
+ private static final int CREAD = 0x0000800;
+ private static final int PARENB = 0x0001000;
+ private static final int PARODD = 0x0002000;
+ private static final int HUPCL = 0x0004000;
+ private static final int CLOCAL = 0x0008000;
+
+ private static final int ECHOKE = 0x0000001;
+ private static final int ECHOE = 0x0000002;
+ private static final int ECHOK = 0x0000004;
+ private static final int ECHO = 0x0000008;
+ private static final int ECHONL = 0x0000010;
+ private static final int ECHOPRT = 0x0000020;
+ private static final int ECHOCTL = 0x0000040;
+ private static final int ISIG = 0x0000080;
+ private static final int ICANON = 0x0000100;
+ private static final int ALTWERASE = 0x000200;
+ private static final int IEXTEN = 0x0000400;
+ private static final int EXTPROC = 0x0000800;
+ private static final int TOSTOP = 0x0400000;
+ private static final int FLUSHO = 0x0800000;
+ private static final int PENDIN = 0x2000000;
+ private static final int NOFLSH = 0x8000000;
+
+ protected CLibrary.Termios toTermios(Attributes t) {
+ return termios(t);
+ }
+
+ static CLibrary.Termios termios(Attributes t) {
+ CLibrary.Termios tio = new CLibrary.Termios();
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IGNBRK), IGNBRK, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.BRKINT), BRKINT, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IGNPAR), IGNPAR, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.PARMRK), PARMRK, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.INPCK), INPCK, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.ISTRIP), ISTRIP, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.INLCR), INLCR, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IGNCR), IGNCR, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.ICRNL), ICRNL, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IXON), IXON, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IXOFF), IXOFF, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IXANY), IXANY, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IMAXBEL), IMAXBEL, tio.c_iflag);
+ // tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IUTF8), IUTF8, tio.c_iflag);
+ // Output flags
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OPOST), OPOST, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONLCR), ONLCR, tio.c_oflag);
+ // tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OXTABS), OXTABS, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONOEOT), ONOEOT, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OCRNL), OCRNL, tio.c_oflag);
+ // tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONOCR), ONOCR, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONLRET), ONLRET, tio.c_oflag);
+ // tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OFILL), OFILL, tio.c_oflag);
+ // tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.NLDLY), NLDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.TABDLY), TABDLY, tio.c_oflag);
+ // tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.CRDLY), CRDLY, tio.c_oflag);
+ // tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.FFDLY), FFDLY, tio.c_oflag);
+ // tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.BSDLY), BSDLY, tio.c_oflag);
+ // tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.VTDLY), VTDLY, tio.c_oflag);
+ // tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OFDEL), OFDEL, tio.c_oflag);
+ // Control flags
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CIGNORE), CIGNORE, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS5), CS5, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS6), CS6, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS7), CS7, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS8), CS8, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CSTOPB), CSTOPB, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CREAD), CREAD, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.PARENB), PARENB, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.PARODD), PARODD, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.HUPCL), HUPCL, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CLOCAL), CLOCAL, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CCTS_OFLOW), CCTS_OFLOW, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CRTS_IFLOW), CRTS_IFLOW, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CDTR_IFLOW), CDTR_IFLOW, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CDSR_OFLOW), CDSR_OFLOW, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CCAR_OFLOW), CCAR_OFLOW, tio.c_cflag);
+ // Local flags
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOKE), ECHOKE, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOE), ECHOE, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOK), ECHOK, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHO), ECHO, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHONL), ECHONL, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOPRT), ECHOPRT, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOCTL), ECHOCTL, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ISIG), ISIG, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ICANON), ICANON, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ALTWERASE), ALTWERASE, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.IEXTEN), IEXTEN, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.EXTPROC), EXTPROC, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.TOSTOP), TOSTOP, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.FLUSHO), FLUSHO, tio.c_lflag);
+ // tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.NOKERNINFO), NOKERNINFO, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.PENDIN), PENDIN, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.NOFLSH), NOFLSH, tio.c_lflag);
+ // Control chars
+ tio.c_cc[VEOF] = (byte) t.getControlChar(Attributes.ControlChar.VEOF);
+ tio.c_cc[VEOL] = (byte) t.getControlChar(Attributes.ControlChar.VEOL);
+ tio.c_cc[VEOL2] = (byte) t.getControlChar(Attributes.ControlChar.VEOL2);
+ tio.c_cc[VERASE] = (byte) t.getControlChar(Attributes.ControlChar.VERASE);
+ tio.c_cc[VWERASE] = (byte) t.getControlChar(Attributes.ControlChar.VWERASE);
+ tio.c_cc[VKILL] = (byte) t.getControlChar(Attributes.ControlChar.VKILL);
+ tio.c_cc[VREPRINT] = (byte) t.getControlChar(Attributes.ControlChar.VREPRINT);
+ tio.c_cc[VINTR] = (byte) t.getControlChar(Attributes.ControlChar.VINTR);
+ tio.c_cc[VQUIT] = (byte) t.getControlChar(Attributes.ControlChar.VQUIT);
+ tio.c_cc[VSUSP] = (byte) t.getControlChar(Attributes.ControlChar.VSUSP);
+ // tio.c_cc[VDSUSP] = (byte) t.getControlChar(Attributes.ControlChar.VDSUSP);
+ tio.c_cc[VSTART] = (byte) t.getControlChar(Attributes.ControlChar.VSTART);
+ tio.c_cc[VSTOP] = (byte) t.getControlChar(Attributes.ControlChar.VSTOP);
+ tio.c_cc[VLNEXT] = (byte) t.getControlChar(Attributes.ControlChar.VLNEXT);
+ tio.c_cc[VDISCARD] = (byte) t.getControlChar(Attributes.ControlChar.VDISCARD);
+ tio.c_cc[VMIN] = (byte) t.getControlChar(Attributes.ControlChar.VMIN);
+ tio.c_cc[VTIME] = (byte) t.getControlChar(Attributes.ControlChar.VTIME);
+ // tio.c_cc[VSTATUS] = (byte) t.getControlChar(Attributes.ControlChar.VSTATUS);
+ return tio;
+ }
+
+ protected Attributes toAttributes(CLibrary.Termios tio) {
+ Attributes attr = new Attributes();
+ // Input flags
+ EnumSet iflag = attr.getInputFlags();
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNBRK, IGNBRK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNBRK, IGNBRK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.BRKINT, BRKINT);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNPAR, IGNPAR);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.PARMRK, PARMRK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.INPCK, INPCK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.ISTRIP, ISTRIP);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.INLCR, INLCR);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNCR, IGNCR);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.ICRNL, ICRNL);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IXON, IXON);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IXOFF, IXOFF);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IXANY, IXANY);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IMAXBEL, IMAXBEL);
+ // addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IUTF8, IUTF8);
+ // Output flags
+ EnumSet oflag = attr.getOutputFlags();
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OPOST, OPOST);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONLCR, ONLCR);
+ // addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OXTABS, OXTABS);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONOEOT, ONOEOT);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OCRNL, OCRNL);
+ // addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONOCR, ONOCR);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONLRET, ONLRET);
+ // addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OFILL, OFILL);
+ // addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.NLDLY, NLDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.TABDLY, TABDLY);
+ // addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.CRDLY, CRDLY);
+ // addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.FFDLY, FFDLY);
+ // addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.BSDLY, BSDLY);
+ // addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.VTDLY, VTDLY);
+ // addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OFDEL, OFDEL);
+ // Control flags
+ EnumSet cflag = attr.getControlFlags();
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CIGNORE, CIGNORE);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS5, CS5);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS6, CS6);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS7, CS7);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS8, CS8);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CSTOPB, CSTOPB);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CREAD, CREAD);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.PARENB, PARENB);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.PARODD, PARODD);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.HUPCL, HUPCL);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CLOCAL, CLOCAL);
+ // addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CCTS_OFLOW, CCTS_OFLOW);
+ // addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CRTS_IFLOW, CRTS_IFLOW);
+ // addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CDSR_OFLOW, CDSR_OFLOW);
+ // addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CCAR_OFLOW, CCAR_OFLOW);
+ // Local flags
+ EnumSet lflag = attr.getLocalFlags();
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOKE, ECHOKE);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOE, ECHOE);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOK, ECHOK);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHO, ECHO);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHONL, ECHONL);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOPRT, ECHOPRT);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOCTL, ECHOCTL);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ISIG, ISIG);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ICANON, ICANON);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ALTWERASE, ALTWERASE);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.IEXTEN, IEXTEN);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.EXTPROC, EXTPROC);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.TOSTOP, TOSTOP);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.FLUSHO, FLUSHO);
+ // addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.NOKERNINFO, NOKERNINFO);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.PENDIN, PENDIN);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.NOFLSH, NOFLSH);
+ // Control chars
+ EnumMap cc = attr.getControlChars();
+ cc.put(Attributes.ControlChar.VEOF, (int) tio.c_cc[VEOF]);
+ cc.put(Attributes.ControlChar.VEOL, (int) tio.c_cc[VEOL]);
+ cc.put(Attributes.ControlChar.VEOL2, (int) tio.c_cc[VEOL2]);
+ cc.put(Attributes.ControlChar.VERASE, (int) tio.c_cc[VERASE]);
+ cc.put(Attributes.ControlChar.VWERASE, (int) tio.c_cc[VWERASE]);
+ cc.put(Attributes.ControlChar.VKILL, (int) tio.c_cc[VKILL]);
+ cc.put(Attributes.ControlChar.VREPRINT, (int) tio.c_cc[VREPRINT]);
+ cc.put(Attributes.ControlChar.VINTR, (int) tio.c_cc[VINTR]);
+ cc.put(Attributes.ControlChar.VQUIT, (int) tio.c_cc[VQUIT]);
+ cc.put(Attributes.ControlChar.VSUSP, (int) tio.c_cc[VSUSP]);
+ // cc.put(Attributes.ControlChar.VDSUSP, (int) tio.c_cc[VDSUSP]);
+ cc.put(Attributes.ControlChar.VSTART, (int) tio.c_cc[VSTART]);
+ cc.put(Attributes.ControlChar.VSTOP, (int) tio.c_cc[VSTOP]);
+ cc.put(Attributes.ControlChar.VLNEXT, (int) tio.c_cc[VLNEXT]);
+ cc.put(Attributes.ControlChar.VDISCARD, (int) tio.c_cc[VDISCARD]);
+ cc.put(Attributes.ControlChar.VMIN, (int) tio.c_cc[VMIN]);
+ cc.put(Attributes.ControlChar.VTIME, (int) tio.c_cc[VTIME]);
+ // cc.put(Attributes.ControlChar.VSTATUS, (int) tio.c_cc[VSTATUS]);
+ // Return
+ return attr;
+ }
+
+ private static long setFlag(boolean flag, long value, long org) {
+ return flag ? org | value : org;
+ }
+
+ private static > void addFlag(long value, EnumSet flags, T flag, int v) {
+ if ((value & v) != 0) {
+ flags.add(flag);
+ }
+ }
+}
diff --git a/terminal-jni/src/main/java/org/jline/terminal/impl/jni/linux/LinuxNativePty.java b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/linux/LinuxNativePty.java
new file mode 100644
index 000000000..537fca079
--- /dev/null
+++ b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/linux/LinuxNativePty.java
@@ -0,0 +1,393 @@
+/*
+ * Copyright (c) 2002-2017, 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 org.jline.terminal.impl.jni.linux;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.EnumMap;
+import java.util.EnumSet;
+
+import org.jline.nativ.CLibrary;
+import org.jline.terminal.Attributes;
+import org.jline.terminal.Size;
+import org.jline.terminal.impl.jni.JniNativePty;
+import org.jline.terminal.spi.SystemStream;
+import org.jline.terminal.spi.TerminalProvider;
+
+public class LinuxNativePty extends JniNativePty {
+
+ public static LinuxNativePty current(TerminalProvider provider, SystemStream systemStream) throws IOException {
+ try {
+ switch (systemStream) {
+ case Output:
+ return new LinuxNativePty(
+ provider, systemStream, -1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname(1));
+ case Error:
+ return new LinuxNativePty(
+ provider, systemStream, -1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname(2));
+ default:
+ throw new IllegalArgumentException("Unsupport stream for console: " + systemStream);
+ }
+ } catch (IOException e) {
+ throw new IOException("Not a tty", e);
+ }
+ }
+
+ public static LinuxNativePty open(TerminalProvider provider, Attributes attr, Size size) throws IOException {
+ int[] master = new int[1];
+ int[] slave = new int[1];
+ byte[] buf = new byte[64];
+ CLibrary.openpty(
+ master,
+ slave,
+ buf,
+ attr != null ? termios(attr) : null,
+ size != null ? new CLibrary.WinSize((short) size.getRows(), (short) size.getColumns()) : null);
+ int len = 0;
+ while (buf[len] != 0) {
+ len++;
+ }
+ String name = new String(buf, 0, len);
+ return new LinuxNativePty(
+ provider,
+ null,
+ master[0],
+ newDescriptor(master[0]),
+ slave[0],
+ newDescriptor(slave[0]),
+ 2,
+ FileDescriptor.err,
+ name);
+ }
+
+ public LinuxNativePty(
+ TerminalProvider provider,
+ SystemStream systemStream,
+ int master,
+ FileDescriptor masterFD,
+ int slave,
+ FileDescriptor slaveFD,
+ int slaveOut,
+ FileDescriptor slaveOutFD,
+ String name) {
+ super(provider, systemStream, master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name);
+ }
+ // CONSTANTS
+
+ private static final int VINTR = 0;
+ private static final int VQUIT = 1;
+ private static final int VERASE = 2;
+ private static final int VKILL = 3;
+ private static final int VEOF = 4;
+ private static final int VTIME = 5;
+ private static final int VMIN = 6;
+ private static final int VSWTC = 7;
+ private static final int VSTART = 8;
+ private static final int VSTOP = 9;
+ private static final int VSUSP = 10;
+ private static final int VEOL = 11;
+ private static final int VREPRINT = 12;
+ private static final int VDISCARD = 13;
+ private static final int VWERASE = 14;
+ private static final int VLNEXT = 15;
+ private static final int VEOL2 = 16;
+
+ private static final int IGNBRK = 0x0000001;
+ private static final int BRKINT = 0x0000002;
+ private static final int IGNPAR = 0x0000004;
+ private static final int PARMRK = 0x0000008;
+ private static final int INPCK = 0x0000010;
+ private static final int ISTRIP = 0x0000020;
+ private static final int INLCR = 0x0000040;
+ private static final int IGNCR = 0x0000080;
+ private static final int ICRNL = 0x0000100;
+ private static final int IUCLC = 0x0000200;
+ private static final int IXON = 0x0000400;
+ private static final int IXANY = 0x0000800;
+ private static final int IXOFF = 0x0001000;
+ private static final int IMAXBEL = 0x0002000;
+ private static final int IUTF8 = 0x0004000;
+
+ private static final int OPOST = 0x0000001;
+ private static final int OLCUC = 0x0000002;
+ private static final int ONLCR = 0x0000004;
+ private static final int OCRNL = 0x0000008;
+ private static final int ONOCR = 0x0000010;
+ private static final int ONLRET = 0x0000020;
+ private static final int OFILL = 0x0000040;
+ private static final int OFDEL = 0x0000080;
+ private static final int NLDLY = 0x0000100;
+ private static final int NL0 = 0x0000000;
+ private static final int NL1 = 0x0000100;
+ private static final int CRDLY = 0x0000600;
+ private static final int CR0 = 0x0000000;
+ private static final int CR1 = 0x0000200;
+ private static final int CR2 = 0x0000400;
+ private static final int CR3 = 0x0000600;
+ private static final int TABDLY = 0x0001800;
+ private static final int TAB0 = 0x0000000;
+ private static final int TAB1 = 0x0000800;
+ private static final int TAB2 = 0x0001000;
+ private static final int TAB3 = 0x0001800;
+ private static final int XTABS = 0x0001800;
+ private static final int BSDLY = 0x0002000;
+ private static final int BS0 = 0x0000000;
+ private static final int BS1 = 0x0002000;
+ private static final int VTDLY = 0x0004000;
+ private static final int VT0 = 0x0000000;
+ private static final int VT1 = 0x0004000;
+ private static final int FFDLY = 0x0008000;
+ private static final int FF0 = 0x0000000;
+ private static final int FF1 = 0x0008000;
+
+ private static final int CBAUD = 0x000100f;
+ private static final int B0 = 0x0000000;
+ private static final int B50 = 0x0000001;
+ private static final int B75 = 0x0000002;
+ private static final int B110 = 0x0000003;
+ private static final int B134 = 0x0000004;
+ private static final int B150 = 0x0000005;
+ private static final int B200 = 0x0000006;
+ private static final int B300 = 0x0000007;
+ private static final int B600 = 0x0000008;
+ private static final int B1200 = 0x0000009;
+ private static final int B1800 = 0x000000a;
+ private static final int B2400 = 0x000000b;
+ private static final int B4800 = 0x000000c;
+ private static final int B9600 = 0x000000d;
+ private static final int B19200 = 0x000000e;
+ private static final int B38400 = 0x000000f;
+ private static final int EXTA = B19200;
+ private static final int EXTB = B38400;
+ private static final int CSIZE = 0x0000030;
+ private static final int CS5 = 0x0000000;
+ private static final int CS6 = 0x0000010;
+ private static final int CS7 = 0x0000020;
+ private static final int CS8 = 0x0000030;
+ private static final int CSTOPB = 0x0000040;
+ private static final int CREAD = 0x0000080;
+ private static final int PARENB = 0x0000100;
+ private static final int PARODD = 0x0000200;
+ private static final int HUPCL = 0x0000400;
+ private static final int CLOCAL = 0x0000800;
+
+ private static final int ISIG = 0x0000001;
+ private static final int ICANON = 0x0000002;
+ private static final int XCASE = 0x0000004;
+ private static final int ECHO = 0x0000008;
+ private static final int ECHOE = 0x0000010;
+ private static final int ECHOK = 0x0000020;
+ private static final int ECHONL = 0x0000040;
+ private static final int NOFLSH = 0x0000080;
+ private static final int TOSTOP = 0x0000100;
+ private static final int ECHOCTL = 0x0000200;
+ private static final int ECHOPRT = 0x0000400;
+ private static final int ECHOKE = 0x0000800;
+ private static final int FLUSHO = 0x0001000;
+ private static final int PENDIN = 0x0002000;
+ private static final int IEXTEN = 0x0008000;
+ private static final int EXTPROC = 0x0010000;
+
+ protected CLibrary.Termios toTermios(Attributes t) {
+ return termios(t);
+ }
+
+ static CLibrary.Termios termios(Attributes t) {
+ CLibrary.Termios tio = new CLibrary.Termios();
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IGNBRK), IGNBRK, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.BRKINT), BRKINT, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IGNPAR), IGNPAR, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.PARMRK), PARMRK, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.INPCK), INPCK, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.ISTRIP), ISTRIP, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.INLCR), INLCR, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IGNCR), IGNCR, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.ICRNL), ICRNL, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IXON), IXON, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IXOFF), IXOFF, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IXANY), IXANY, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IMAXBEL), IMAXBEL, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IUTF8), IUTF8, tio.c_iflag);
+ // Output flags
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OPOST), OPOST, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONLCR), ONLCR, tio.c_oflag);
+ // tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OXTABS), OXTABS, tio.c_oflag);
+ // tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONOEOT), ONOEOT, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OCRNL), OCRNL, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONOCR), ONOCR, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONLRET), ONLRET, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OFILL), OFILL, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.NLDLY), NLDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.TABDLY), TABDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.CRDLY), CRDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.FFDLY), FFDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.BSDLY), BSDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.VTDLY), VTDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OFDEL), OFDEL, tio.c_oflag);
+ // Control flags
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CIGNORE), CIGNORE, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS5), CS5, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS6), CS6, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS7), CS7, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS8), CS8, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CSTOPB), CSTOPB, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CREAD), CREAD, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.PARENB), PARENB, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.PARODD), PARODD, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.HUPCL), HUPCL, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CLOCAL), CLOCAL, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CCTS_OFLOW), CCTS_OFLOW, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CRTS_IFLOW), CRTS_IFLOW, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CDTR_IFLOW), CDTR_IFLOW, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CDSR_OFLOW), CDSR_OFLOW, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CCAR_OFLOW), CCAR_OFLOW, tio.c_cflag);
+ // Local flags
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOKE), ECHOKE, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOE), ECHOE, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOK), ECHOK, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHO), ECHO, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHONL), ECHONL, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOPRT), ECHOPRT, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOCTL), ECHOCTL, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ISIG), ISIG, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ICANON), ICANON, tio.c_lflag);
+ // tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ALTWERASE), ALTWERASE, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.IEXTEN), IEXTEN, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.EXTPROC), EXTPROC, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.TOSTOP), TOSTOP, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.FLUSHO), FLUSHO, tio.c_lflag);
+ // tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.NOKERNINFO), NOKERNINFO, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.PENDIN), PENDIN, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.NOFLSH), NOFLSH, tio.c_lflag);
+ // Control chars
+ tio.c_cc[VEOF] = (byte) t.getControlChar(Attributes.ControlChar.VEOF);
+ tio.c_cc[VEOL] = (byte) t.getControlChar(Attributes.ControlChar.VEOL);
+ tio.c_cc[VEOL2] = (byte) t.getControlChar(Attributes.ControlChar.VEOL2);
+ tio.c_cc[VERASE] = (byte) t.getControlChar(Attributes.ControlChar.VERASE);
+ tio.c_cc[VWERASE] = (byte) t.getControlChar(Attributes.ControlChar.VWERASE);
+ tio.c_cc[VKILL] = (byte) t.getControlChar(Attributes.ControlChar.VKILL);
+ tio.c_cc[VREPRINT] = (byte) t.getControlChar(Attributes.ControlChar.VREPRINT);
+ tio.c_cc[VINTR] = (byte) t.getControlChar(Attributes.ControlChar.VINTR);
+ tio.c_cc[VQUIT] = (byte) t.getControlChar(Attributes.ControlChar.VQUIT);
+ tio.c_cc[VSUSP] = (byte) t.getControlChar(Attributes.ControlChar.VSUSP);
+ tio.c_cc[VSTART] = (byte) t.getControlChar(Attributes.ControlChar.VSTART);
+ tio.c_cc[VSTOP] = (byte) t.getControlChar(Attributes.ControlChar.VSTOP);
+ tio.c_cc[VLNEXT] = (byte) t.getControlChar(Attributes.ControlChar.VLNEXT);
+ tio.c_cc[VDISCARD] = (byte) t.getControlChar(Attributes.ControlChar.VDISCARD);
+ tio.c_cc[VMIN] = (byte) t.getControlChar(Attributes.ControlChar.VMIN);
+ tio.c_cc[VTIME] = (byte) t.getControlChar(Attributes.ControlChar.VTIME);
+ // tio.c_cc[VSTATUS] = (byte) t.getControlChar(Attributes.ControlChar.VSTATUS);
+ return tio;
+ }
+
+ protected Attributes toAttributes(CLibrary.Termios tio) {
+ Attributes attr = new Attributes();
+ // Input flags
+ EnumSet iflag = attr.getInputFlags();
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNBRK, IGNBRK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNBRK, IGNBRK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.BRKINT, BRKINT);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNPAR, IGNPAR);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.PARMRK, PARMRK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.INPCK, INPCK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.ISTRIP, ISTRIP);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.INLCR, INLCR);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNCR, IGNCR);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.ICRNL, ICRNL);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IXON, IXON);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IXOFF, IXOFF);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IXANY, IXANY);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IMAXBEL, IMAXBEL);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IUTF8, IUTF8);
+ // Output flags
+ EnumSet oflag = attr.getOutputFlags();
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OPOST, OPOST);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONLCR, ONLCR);
+ // addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OXTABS, OXTABS);
+ // addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONOEOT, ONOEOT);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OCRNL, OCRNL);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONOCR, ONOCR);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONLRET, ONLRET);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OFILL, OFILL);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.NLDLY, NLDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.TABDLY, TABDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.CRDLY, CRDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.FFDLY, FFDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.BSDLY, BSDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.VTDLY, VTDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OFDEL, OFDEL);
+ // Control flags
+ EnumSet cflag = attr.getControlFlags();
+ // addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CIGNORE, CIGNORE);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS5, CS5);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS6, CS6);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS7, CS7);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS8, CS8);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CSTOPB, CSTOPB);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CREAD, CREAD);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.PARENB, PARENB);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.PARODD, PARODD);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.HUPCL, HUPCL);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CLOCAL, CLOCAL);
+ // addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CCTS_OFLOW, CCTS_OFLOW);
+ // addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CRTS_IFLOW, CRTS_IFLOW);
+ // addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CDSR_OFLOW, CDSR_OFLOW);
+ // addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CCAR_OFLOW, CCAR_OFLOW);
+ // Local flags
+ EnumSet lflag = attr.getLocalFlags();
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOKE, ECHOKE);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOE, ECHOE);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOK, ECHOK);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHO, ECHO);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHONL, ECHONL);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOPRT, ECHOPRT);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOCTL, ECHOCTL);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ISIG, ISIG);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ICANON, ICANON);
+ // addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ALTWERASE, ALTWERASE);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.IEXTEN, IEXTEN);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.EXTPROC, EXTPROC);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.TOSTOP, TOSTOP);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.FLUSHO, FLUSHO);
+ // addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.NOKERNINFO, NOKERNINFO);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.PENDIN, PENDIN);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.NOFLSH, NOFLSH);
+ // Control chars
+ EnumMap cc = attr.getControlChars();
+ cc.put(Attributes.ControlChar.VEOF, (int) tio.c_cc[VEOF]);
+ cc.put(Attributes.ControlChar.VEOL, (int) tio.c_cc[VEOL]);
+ cc.put(Attributes.ControlChar.VEOL2, (int) tio.c_cc[VEOL2]);
+ cc.put(Attributes.ControlChar.VERASE, (int) tio.c_cc[VERASE]);
+ cc.put(Attributes.ControlChar.VWERASE, (int) tio.c_cc[VWERASE]);
+ cc.put(Attributes.ControlChar.VKILL, (int) tio.c_cc[VKILL]);
+ cc.put(Attributes.ControlChar.VREPRINT, (int) tio.c_cc[VREPRINT]);
+ cc.put(Attributes.ControlChar.VINTR, (int) tio.c_cc[VINTR]);
+ cc.put(Attributes.ControlChar.VQUIT, (int) tio.c_cc[VQUIT]);
+ cc.put(Attributes.ControlChar.VSUSP, (int) tio.c_cc[VSUSP]);
+ cc.put(Attributes.ControlChar.VSTART, (int) tio.c_cc[VSTART]);
+ cc.put(Attributes.ControlChar.VSTOP, (int) tio.c_cc[VSTOP]);
+ cc.put(Attributes.ControlChar.VLNEXT, (int) tio.c_cc[VLNEXT]);
+ cc.put(Attributes.ControlChar.VDISCARD, (int) tio.c_cc[VDISCARD]);
+ cc.put(Attributes.ControlChar.VMIN, (int) tio.c_cc[VMIN]);
+ cc.put(Attributes.ControlChar.VTIME, (int) tio.c_cc[VTIME]);
+ // cc.put(Attributes.ControlChar.VSTATUS, (int) tio.c_cc[VSTATUS]);
+ // Return
+ return attr;
+ }
+
+ private static long setFlag(boolean flag, long value, long org) {
+ return flag ? org | value : org;
+ }
+
+ private static > void addFlag(long value, EnumSet flags, T flag, int v) {
+ if ((value & v) != 0) {
+ flags.add(flag);
+ }
+ }
+}
diff --git a/terminal-jni/src/main/java/org/jline/terminal/impl/jni/osx/OsXNativePty.java b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/osx/OsXNativePty.java
new file mode 100644
index 000000000..8cf4accf0
--- /dev/null
+++ b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/osx/OsXNativePty.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2002-2017, 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 org.jline.terminal.impl.jni.osx;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.EnumMap;
+import java.util.EnumSet;
+
+import org.jline.nativ.CLibrary;
+import org.jline.terminal.Attributes;
+import org.jline.terminal.Size;
+import org.jline.terminal.impl.jni.JniNativePty;
+import org.jline.terminal.spi.SystemStream;
+import org.jline.terminal.spi.TerminalProvider;
+
+public class OsXNativePty extends JniNativePty {
+
+ public static OsXNativePty current(TerminalProvider provider, SystemStream systemStream) throws IOException {
+ try {
+ switch (systemStream) {
+ case Output:
+ return new OsXNativePty(
+ provider,
+ SystemStream.Output,
+ -1,
+ null,
+ 0,
+ FileDescriptor.in,
+ 1,
+ FileDescriptor.out,
+ ttyname(1));
+ case Error:
+ return new OsXNativePty(
+ provider,
+ SystemStream.Error,
+ -1,
+ null,
+ 0,
+ FileDescriptor.in,
+ 2,
+ FileDescriptor.err,
+ ttyname(2));
+ default:
+ throw new IllegalArgumentException("Unsupport stream for console: " + systemStream);
+ }
+ } catch (IOException e) {
+ throw new IOException("Not a tty", e);
+ }
+ }
+
+ public static OsXNativePty open(TerminalProvider provider, Attributes attr, Size size) throws IOException {
+ int[] master = new int[1];
+ int[] slave = new int[1];
+ byte[] buf = new byte[64];
+ CLibrary.openpty(
+ master,
+ slave,
+ buf,
+ attr != null ? termios(attr) : null,
+ size != null ? new CLibrary.WinSize((short) size.getRows(), (short) size.getColumns()) : null);
+ int len = 0;
+ while (buf[len] != 0) {
+ len++;
+ }
+ String name = new String(buf, 0, len);
+ return new OsXNativePty(
+ provider, null, master[0], newDescriptor(master[0]), slave[0], newDescriptor(slave[0]), name);
+ }
+
+ public OsXNativePty(
+ TerminalProvider provider,
+ SystemStream systemStream,
+ int master,
+ FileDescriptor masterFD,
+ int slave,
+ FileDescriptor slaveFD,
+ String name) {
+ super(provider, systemStream, master, masterFD, slave, slaveFD, name);
+ }
+
+ public OsXNativePty(
+ TerminalProvider provider,
+ SystemStream systemStream,
+ int master,
+ FileDescriptor masterFD,
+ int slave,
+ FileDescriptor slaveFD,
+ int slaveOut,
+ FileDescriptor slaveOutFD,
+ String name) {
+ super(provider, systemStream, master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name);
+ }
+
+ // CONSTANTS
+
+ private static final int VEOF = 0;
+ private static final int VEOL = 1;
+ private static final int VEOL2 = 2;
+ private static final int VERASE = 3;
+ private static final int VWERASE = 4;
+ private static final int VKILL = 5;
+ private static final int VREPRINT = 6;
+ private static final int VINTR = 8;
+ private static final int VQUIT = 9;
+ private static final int VSUSP = 10;
+ private static final int VDSUSP = 11;
+ private static final int VSTART = 12;
+ private static final int VSTOP = 13;
+ private static final int VLNEXT = 14;
+ private static final int VDISCARD = 15;
+ private static final int VMIN = 16;
+ private static final int VTIME = 17;
+ private static final int VSTATUS = 18;
+
+ private static final int IGNBRK = 0x00000001;
+ private static final int BRKINT = 0x00000002;
+ private static final int IGNPAR = 0x00000004;
+ private static final int PARMRK = 0x00000008;
+ private static final int INPCK = 0x00000010;
+ private static final int ISTRIP = 0x00000020;
+ private static final int INLCR = 0x00000040;
+ private static final int IGNCR = 0x00000080;
+ private static final int ICRNL = 0x00000100;
+ private static final int IXON = 0x00000200;
+ private static final int IXOFF = 0x00000400;
+ private static final int IXANY = 0x00000800;
+ private static final int IMAXBEL = 0x00002000;
+ private static final int IUTF8 = 0x00004000;
+
+ private static final int OPOST = 0x00000001;
+ private static final int ONLCR = 0x00000002;
+ private static final int OXTABS = 0x00000004;
+ private static final int ONOEOT = 0x00000008;
+ private static final int OCRNL = 0x00000010;
+ private static final int ONOCR = 0x00000020;
+ private static final int ONLRET = 0x00000040;
+ private static final int OFILL = 0x00000080;
+ private static final int NLDLY = 0x00000300;
+ private static final int TABDLY = 0x00000c04;
+ private static final int CRDLY = 0x00003000;
+ private static final int FFDLY = 0x00004000;
+ private static final int BSDLY = 0x00008000;
+ private static final int VTDLY = 0x00010000;
+ private static final int OFDEL = 0x00020000;
+
+ private static final int CIGNORE = 0x00000001;
+ private static final int CS5 = 0x00000000;
+ private static final int CS6 = 0x00000100;
+ private static final int CS7 = 0x00000200;
+ private static final int CS8 = 0x00000300;
+ private static final int CSTOPB = 0x00000400;
+ private static final int CREAD = 0x00000800;
+ private static final int PARENB = 0x00001000;
+ private static final int PARODD = 0x00002000;
+ private static final int HUPCL = 0x00004000;
+ private static final int CLOCAL = 0x00008000;
+ private static final int CCTS_OFLOW = 0x00010000;
+ private static final int CRTS_IFLOW = 0x00020000;
+ private static final int CDTR_IFLOW = 0x00040000;
+ private static final int CDSR_OFLOW = 0x00080000;
+ private static final int CCAR_OFLOW = 0x00100000;
+
+ private static final int ECHOKE = 0x00000001;
+ private static final int ECHOE = 0x00000002;
+ private static final int ECHOK = 0x00000004;
+ private static final int ECHO = 0x00000008;
+ private static final int ECHONL = 0x00000010;
+ private static final int ECHOPRT = 0x00000020;
+ private static final int ECHOCTL = 0x00000040;
+ private static final int ISIG = 0x00000080;
+ private static final int ICANON = 0x00000100;
+ private static final int ALTWERASE = 0x00000200;
+ private static final int IEXTEN = 0x00000400;
+ private static final int EXTPROC = 0x00000800;
+ private static final int TOSTOP = 0x00400000;
+ private static final int FLUSHO = 0x00800000;
+ private static final int NOKERNINFO = 0x02000000;
+ private static final int PENDIN = 0x20000000;
+ private static final int NOFLSH = 0x80000000;
+
+ protected CLibrary.Termios toTermios(Attributes t) {
+ return termios(t);
+ }
+
+ static CLibrary.Termios termios(Attributes t) {
+ CLibrary.Termios tio = new CLibrary.Termios();
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IGNBRK), IGNBRK, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.BRKINT), BRKINT, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IGNPAR), IGNPAR, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.PARMRK), PARMRK, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.INPCK), INPCK, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.ISTRIP), ISTRIP, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.INLCR), INLCR, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IGNCR), IGNCR, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.ICRNL), ICRNL, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IXON), IXON, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IXOFF), IXOFF, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IXANY), IXANY, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IMAXBEL), IMAXBEL, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IUTF8), IUTF8, tio.c_iflag);
+ // Output flags
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OPOST), OPOST, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONLCR), ONLCR, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OXTABS), OXTABS, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONOEOT), ONOEOT, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OCRNL), OCRNL, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONOCR), ONOCR, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONLRET), ONLRET, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OFILL), OFILL, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.NLDLY), NLDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.TABDLY), TABDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.CRDLY), CRDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.FFDLY), FFDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.BSDLY), BSDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.VTDLY), VTDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OFDEL), OFDEL, tio.c_oflag);
+ // Control flags
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CIGNORE), CIGNORE, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS5), CS5, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS6), CS6, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS7), CS7, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS8), CS8, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CSTOPB), CSTOPB, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CREAD), CREAD, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.PARENB), PARENB, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.PARODD), PARODD, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.HUPCL), HUPCL, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CLOCAL), CLOCAL, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CCTS_OFLOW), CCTS_OFLOW, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CRTS_IFLOW), CRTS_IFLOW, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CDTR_IFLOW), CDTR_IFLOW, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CDSR_OFLOW), CDSR_OFLOW, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CCAR_OFLOW), CCAR_OFLOW, tio.c_cflag);
+ // Local flags
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOKE), ECHOKE, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOE), ECHOE, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOK), ECHOK, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHO), ECHO, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHONL), ECHONL, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOPRT), ECHOPRT, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOCTL), ECHOCTL, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ISIG), ISIG, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ICANON), ICANON, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ALTWERASE), ALTWERASE, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.IEXTEN), IEXTEN, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.EXTPROC), EXTPROC, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.TOSTOP), TOSTOP, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.FLUSHO), FLUSHO, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.NOKERNINFO), NOKERNINFO, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.PENDIN), PENDIN, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.NOFLSH), NOFLSH, tio.c_lflag);
+ // Control chars
+ tio.c_cc[VEOF] = (byte) t.getControlChar(Attributes.ControlChar.VEOF);
+ tio.c_cc[VEOL] = (byte) t.getControlChar(Attributes.ControlChar.VEOL);
+ tio.c_cc[VEOL2] = (byte) t.getControlChar(Attributes.ControlChar.VEOL2);
+ tio.c_cc[VERASE] = (byte) t.getControlChar(Attributes.ControlChar.VERASE);
+ tio.c_cc[VWERASE] = (byte) t.getControlChar(Attributes.ControlChar.VWERASE);
+ tio.c_cc[VKILL] = (byte) t.getControlChar(Attributes.ControlChar.VKILL);
+ tio.c_cc[VREPRINT] = (byte) t.getControlChar(Attributes.ControlChar.VREPRINT);
+ tio.c_cc[VINTR] = (byte) t.getControlChar(Attributes.ControlChar.VINTR);
+ tio.c_cc[VQUIT] = (byte) t.getControlChar(Attributes.ControlChar.VQUIT);
+ tio.c_cc[VSUSP] = (byte) t.getControlChar(Attributes.ControlChar.VSUSP);
+ tio.c_cc[VDSUSP] = (byte) t.getControlChar(Attributes.ControlChar.VDSUSP);
+ tio.c_cc[VSTART] = (byte) t.getControlChar(Attributes.ControlChar.VSTART);
+ tio.c_cc[VSTOP] = (byte) t.getControlChar(Attributes.ControlChar.VSTOP);
+ tio.c_cc[VLNEXT] = (byte) t.getControlChar(Attributes.ControlChar.VLNEXT);
+ tio.c_cc[VDISCARD] = (byte) t.getControlChar(Attributes.ControlChar.VDISCARD);
+ tio.c_cc[VMIN] = (byte) t.getControlChar(Attributes.ControlChar.VMIN);
+ tio.c_cc[VTIME] = (byte) t.getControlChar(Attributes.ControlChar.VTIME);
+ tio.c_cc[VSTATUS] = (byte) t.getControlChar(Attributes.ControlChar.VSTATUS);
+ return tio;
+ }
+
+ protected Attributes toAttributes(CLibrary.Termios tio) {
+ Attributes attr = new Attributes();
+ // Input flags
+ EnumSet iflag = attr.getInputFlags();
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNBRK, IGNBRK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNBRK, IGNBRK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.BRKINT, BRKINT);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNPAR, IGNPAR);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.PARMRK, PARMRK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.INPCK, INPCK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.ISTRIP, ISTRIP);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.INLCR, INLCR);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNCR, IGNCR);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.ICRNL, ICRNL);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IXON, IXON);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IXOFF, IXOFF);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IXANY, IXANY);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IMAXBEL, IMAXBEL);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IUTF8, IUTF8);
+ // Output flags
+ EnumSet oflag = attr.getOutputFlags();
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OPOST, OPOST);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONLCR, ONLCR);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OXTABS, OXTABS);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONOEOT, ONOEOT);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OCRNL, OCRNL);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONOCR, ONOCR);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONLRET, ONLRET);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OFILL, OFILL);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.NLDLY, NLDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.TABDLY, TABDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.CRDLY, CRDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.FFDLY, FFDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.BSDLY, BSDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.VTDLY, VTDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OFDEL, OFDEL);
+ // Control flags
+ EnumSet cflag = attr.getControlFlags();
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CIGNORE, CIGNORE);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS5, CS5);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS6, CS6);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS7, CS7);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS8, CS8);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CSTOPB, CSTOPB);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CREAD, CREAD);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.PARENB, PARENB);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.PARODD, PARODD);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.HUPCL, HUPCL);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CLOCAL, CLOCAL);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CCTS_OFLOW, CCTS_OFLOW);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CRTS_IFLOW, CRTS_IFLOW);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CDSR_OFLOW, CDSR_OFLOW);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CCAR_OFLOW, CCAR_OFLOW);
+ // Local flags
+ EnumSet lflag = attr.getLocalFlags();
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOKE, ECHOKE);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOE, ECHOE);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOK, ECHOK);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHO, ECHO);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHONL, ECHONL);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOPRT, ECHOPRT);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOCTL, ECHOCTL);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ISIG, ISIG);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ICANON, ICANON);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ALTWERASE, ALTWERASE);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.IEXTEN, IEXTEN);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.EXTPROC, EXTPROC);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.TOSTOP, TOSTOP);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.FLUSHO, FLUSHO);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.NOKERNINFO, NOKERNINFO);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.PENDIN, PENDIN);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.NOFLSH, NOFLSH);
+ // Control chars
+ EnumMap cc = attr.getControlChars();
+ cc.put(Attributes.ControlChar.VEOF, (int) tio.c_cc[VEOF]);
+ cc.put(Attributes.ControlChar.VEOL, (int) tio.c_cc[VEOL]);
+ cc.put(Attributes.ControlChar.VEOL2, (int) tio.c_cc[VEOL2]);
+ cc.put(Attributes.ControlChar.VERASE, (int) tio.c_cc[VERASE]);
+ cc.put(Attributes.ControlChar.VWERASE, (int) tio.c_cc[VWERASE]);
+ cc.put(Attributes.ControlChar.VKILL, (int) tio.c_cc[VKILL]);
+ cc.put(Attributes.ControlChar.VREPRINT, (int) tio.c_cc[VREPRINT]);
+ cc.put(Attributes.ControlChar.VINTR, (int) tio.c_cc[VINTR]);
+ cc.put(Attributes.ControlChar.VQUIT, (int) tio.c_cc[VQUIT]);
+ cc.put(Attributes.ControlChar.VSUSP, (int) tio.c_cc[VSUSP]);
+ cc.put(Attributes.ControlChar.VDSUSP, (int) tio.c_cc[VDSUSP]);
+ cc.put(Attributes.ControlChar.VSTART, (int) tio.c_cc[VSTART]);
+ cc.put(Attributes.ControlChar.VSTOP, (int) tio.c_cc[VSTOP]);
+ cc.put(Attributes.ControlChar.VLNEXT, (int) tio.c_cc[VLNEXT]);
+ cc.put(Attributes.ControlChar.VDISCARD, (int) tio.c_cc[VDISCARD]);
+ cc.put(Attributes.ControlChar.VMIN, (int) tio.c_cc[VMIN]);
+ cc.put(Attributes.ControlChar.VTIME, (int) tio.c_cc[VTIME]);
+ cc.put(Attributes.ControlChar.VSTATUS, (int) tio.c_cc[VSTATUS]);
+ // Return
+ return attr;
+ }
+
+ private static long setFlag(boolean flag, long value, long org) {
+ return flag ? org | value : org;
+ }
+
+ private static > void addFlag(long value, EnumSet flags, T flag, int v) {
+ if ((value & v) != 0) {
+ flags.add(flag);
+ }
+ }
+}
diff --git a/terminal-jni/src/main/java/org/jline/terminal/impl/jni/solaris/SolarisNativePty.java b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/solaris/SolarisNativePty.java
new file mode 100644
index 000000000..c34d11b48
--- /dev/null
+++ b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/solaris/SolarisNativePty.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2002-2017, 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 org.jline.terminal.impl.jni.solaris;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.EnumMap;
+import java.util.EnumSet;
+
+import org.jline.nativ.CLibrary;
+import org.jline.terminal.Attributes;
+import org.jline.terminal.Size;
+import org.jline.terminal.impl.jni.JniNativePty;
+import org.jline.terminal.spi.SystemStream;
+import org.jline.terminal.spi.TerminalProvider;
+
+public class SolarisNativePty extends JniNativePty {
+
+ public static SolarisNativePty current(TerminalProvider provider, SystemStream systemStream) throws IOException {
+ try {
+ switch (systemStream) {
+ case Output:
+ return new SolarisNativePty(
+ provider, systemStream, -1, null, 0, FileDescriptor.in, 1, FileDescriptor.out, ttyname(1));
+ case Error:
+ return new SolarisNativePty(
+ provider, systemStream, -1, null, 0, FileDescriptor.in, 2, FileDescriptor.err, ttyname(2));
+ default:
+ throw new IllegalArgumentException("Unsupport stream for console: " + systemStream);
+ }
+ } catch (IOException e) {
+ throw new IOException("Not a tty", e);
+ }
+ }
+
+ public static SolarisNativePty open(TerminalProvider provider, Attributes attr, Size size) throws IOException {
+ int[] master = new int[1];
+ int[] slave = new int[1];
+ byte[] buf = new byte[64];
+ CLibrary.openpty(
+ master,
+ slave,
+ buf,
+ attr != null ? termios(attr) : null,
+ size != null ? new CLibrary.WinSize((short) size.getRows(), (short) size.getColumns()) : null);
+ int len = 0;
+ while (buf[len] != 0) {
+ len++;
+ }
+ String name = new String(buf, 0, len);
+ return new SolarisNativePty(
+ provider,
+ null,
+ master[0],
+ newDescriptor(master[0]),
+ slave[0],
+ newDescriptor(slave[0]),
+ 2,
+ FileDescriptor.err,
+ name);
+ }
+
+ public SolarisNativePty(
+ TerminalProvider provider,
+ SystemStream systemStream,
+ int master,
+ FileDescriptor masterFD,
+ int slave,
+ FileDescriptor slaveFD,
+ String name) {
+ super(provider, systemStream, master, masterFD, slave, slaveFD, name);
+ }
+
+ public SolarisNativePty(
+ TerminalProvider provider,
+ SystemStream systemStream,
+ int master,
+ FileDescriptor masterFD,
+ int slave,
+ FileDescriptor slaveFD,
+ int slaveOut,
+ FileDescriptor slaveOutFD,
+ String name) {
+ super(provider, systemStream, master, masterFD, slave, slaveFD, slaveOut, slaveOutFD, name);
+ }
+ // CONSTANTS
+
+ private static final int VINTR = 0;
+ private static final int VQUIT = 1;
+ private static final int VERASE = 2;
+ private static final int VKILL = 3;
+ private static final int VEOF = 4;
+ private static final int VTIME = 5;
+ private static final int VMIN = 6;
+ private static final int VSWTC = 7;
+ private static final int VSTART = 8;
+ private static final int VSTOP = 9;
+ private static final int VSUSP = 10;
+ private static final int VEOL = 11;
+ private static final int VREPRINT = 12;
+ private static final int VDISCARD = 13;
+ private static final int VWERASE = 14;
+ private static final int VLNEXT = 15;
+ private static final int VEOL2 = 16;
+
+ private static final int IGNBRK = 0x0000001;
+ private static final int BRKINT = 0x0000002;
+ private static final int IGNPAR = 0x0000004;
+ private static final int PARMRK = 0x0000010;
+ private static final int INPCK = 0x0000020;
+ private static final int ISTRIP = 0x0000040;
+ private static final int INLCR = 0x0000100;
+ private static final int IGNCR = 0x0000200;
+ private static final int ICRNL = 0x0000400;
+ private static final int IUCLC = 0x0001000;
+ private static final int IXON = 0x0002000;
+ private static final int IXANY = 0x0004000;
+ private static final int IXOFF = 0x0010000;
+ private static final int IMAXBEL = 0x0020000;
+ private static final int IUTF8 = 0x0040000;
+
+ private static final int OPOST = 0x0000001;
+ private static final int OLCUC = 0x0000002;
+ private static final int ONLCR = 0x0000004;
+ private static final int OCRNL = 0x0000010;
+ private static final int ONOCR = 0x0000020;
+ private static final int ONLRET = 0x0000040;
+ private static final int OFILL = 0x0000100;
+ private static final int OFDEL = 0x0000200;
+ private static final int NLDLY = 0x0000400;
+ private static final int NL0 = 0x0000000;
+ private static final int NL1 = 0x0000400;
+ private static final int CRDLY = 0x0003000;
+ private static final int CR0 = 0x0000000;
+ private static final int CR1 = 0x0001000;
+ private static final int CR2 = 0x0002000;
+ private static final int CR3 = 0x0003000;
+ private static final int TABDLY = 0x0014000;
+ private static final int TAB0 = 0x0000000;
+ private static final int TAB1 = 0x0004000;
+ private static final int TAB2 = 0x0010000;
+ private static final int TAB3 = 0x0014000;
+ private static final int XTABS = 0x0014000;
+ private static final int BSDLY = 0x0020000;
+ private static final int BS0 = 0x0000000;
+ private static final int BS1 = 0x0020000;
+ private static final int VTDLY = 0x0040000;
+ private static final int VT0 = 0x0000000;
+ private static final int VT1 = 0x0040000;
+ private static final int FFDLY = 0x0100000;
+ private static final int FF0 = 0x0000000;
+ private static final int FF1 = 0x0100000;
+
+ private static final int CBAUD = 0x0010017;
+ private static final int B0 = 0x0000000;
+ private static final int B50 = 0x0000001;
+ private static final int B75 = 0x0000002;
+ private static final int B110 = 0x0000003;
+ private static final int B134 = 0x0000004;
+ private static final int B150 = 0x0000005;
+ private static final int B200 = 0x0000006;
+ private static final int B300 = 0x0000007;
+ private static final int B600 = 0x0000010;
+ private static final int B1200 = 0x0000011;
+ private static final int B1800 = 0x0000012;
+ private static final int B2400 = 0x0000013;
+ private static final int B4800 = 0x0000014;
+ private static final int B9600 = 0x0000015;
+ private static final int B19200 = 0x0000016;
+ private static final int B38400 = 0x0000017;
+ private static final int EXTA = 0xB19200;
+ private static final int EXTB = 0xB38400;
+ private static final int CSIZE = 0x0000060;
+ private static final int CS5 = 0x0000000;
+ private static final int CS6 = 0x0000020;
+ private static final int CS7 = 0x0000040;
+ private static final int CS8 = 0x0000060;
+ private static final int CSTOPB = 0x0000100;
+ private static final int CREAD = 0x0000200;
+ private static final int PARENB = 0x0000400;
+ private static final int PARODD = 0x0001000;
+ private static final int HUPCL = 0x0002000;
+ private static final int CLOCAL = 0x0004000;
+
+ private static final int ISIG = 0x0000001;
+ private static final int ICANON = 0x0000002;
+ private static final int XCASE = 0x0000004;
+ private static final int ECHO = 0x0000010;
+ private static final int ECHOE = 0x0000020;
+ private static final int ECHOK = 0x0000040;
+ private static final int ECHONL = 0x0000100;
+ private static final int NOFLSH = 0x0000200;
+ private static final int TOSTOP = 0x0000400;
+ private static final int ECHOCTL = 0x0001000;
+ private static final int ECHOPRT = 0x0002000;
+ private static final int ECHOKE = 0x0004000;
+ private static final int FLUSHO = 0x0010000;
+ private static final int PENDIN = 0x0040000;
+ private static final int IEXTEN = 0x0100000;
+ private static final int EXTPROC = 0x0200000;
+
+ protected CLibrary.Termios toTermios(Attributes t) {
+ return termios(t);
+ }
+
+ static CLibrary.Termios termios(Attributes t) {
+ CLibrary.Termios tio = new CLibrary.Termios();
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IGNBRK), IGNBRK, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.BRKINT), BRKINT, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IGNPAR), IGNPAR, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.PARMRK), PARMRK, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.INPCK), INPCK, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.ISTRIP), ISTRIP, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.INLCR), INLCR, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IGNCR), IGNCR, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.ICRNL), ICRNL, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IXON), IXON, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IXOFF), IXOFF, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IXANY), IXANY, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IMAXBEL), IMAXBEL, tio.c_iflag);
+ tio.c_iflag = setFlag(t.getInputFlag(Attributes.InputFlag.IUTF8), IUTF8, tio.c_iflag);
+ // Output flags
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OPOST), OPOST, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONLCR), ONLCR, tio.c_oflag);
+ // tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OXTABS), OXTABS, tio.c_oflag);
+ // tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONOEOT), ONOEOT, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OCRNL), OCRNL, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONOCR), ONOCR, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.ONLRET), ONLRET, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OFILL), OFILL, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.NLDLY), NLDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.TABDLY), TABDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.CRDLY), CRDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.FFDLY), FFDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.BSDLY), BSDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.VTDLY), VTDLY, tio.c_oflag);
+ tio.c_oflag = setFlag(t.getOutputFlag(Attributes.OutputFlag.OFDEL), OFDEL, tio.c_oflag);
+ // Control flags
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CIGNORE), CIGNORE, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS5), CS5, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS6), CS6, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS7), CS7, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CS8), CS8, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CSTOPB), CSTOPB, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CREAD), CREAD, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.PARENB), PARENB, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.PARODD), PARODD, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.HUPCL), HUPCL, tio.c_cflag);
+ tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CLOCAL), CLOCAL, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CCTS_OFLOW), CCTS_OFLOW, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CRTS_IFLOW), CRTS_IFLOW, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CDTR_IFLOW), CDTR_IFLOW, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CDSR_OFLOW), CDSR_OFLOW, tio.c_cflag);
+ // tio.c_cflag = setFlag(t.getControlFlag(Attributes.ControlFlag.CCAR_OFLOW), CCAR_OFLOW, tio.c_cflag);
+ // Local flags
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOKE), ECHOKE, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOE), ECHOE, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOK), ECHOK, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHO), ECHO, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHONL), ECHONL, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOPRT), ECHOPRT, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ECHOCTL), ECHOCTL, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ISIG), ISIG, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ICANON), ICANON, tio.c_lflag);
+ // tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.ALTWERASE), ALTWERASE, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.IEXTEN), IEXTEN, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.EXTPROC), EXTPROC, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.TOSTOP), TOSTOP, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.FLUSHO), FLUSHO, tio.c_lflag);
+ // tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.NOKERNINFO), NOKERNINFO, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.PENDIN), PENDIN, tio.c_lflag);
+ tio.c_lflag = setFlag(t.getLocalFlag(Attributes.LocalFlag.NOFLSH), NOFLSH, tio.c_lflag);
+ // Control chars
+ tio.c_cc[VEOF] = (byte) t.getControlChar(Attributes.ControlChar.VEOF);
+ tio.c_cc[VEOL] = (byte) t.getControlChar(Attributes.ControlChar.VEOL);
+ tio.c_cc[VEOL2] = (byte) t.getControlChar(Attributes.ControlChar.VEOL2);
+ tio.c_cc[VERASE] = (byte) t.getControlChar(Attributes.ControlChar.VERASE);
+ tio.c_cc[VWERASE] = (byte) t.getControlChar(Attributes.ControlChar.VWERASE);
+ tio.c_cc[VKILL] = (byte) t.getControlChar(Attributes.ControlChar.VKILL);
+ tio.c_cc[VREPRINT] = (byte) t.getControlChar(Attributes.ControlChar.VREPRINT);
+ tio.c_cc[VINTR] = (byte) t.getControlChar(Attributes.ControlChar.VINTR);
+ tio.c_cc[VQUIT] = (byte) t.getControlChar(Attributes.ControlChar.VQUIT);
+ tio.c_cc[VSUSP] = (byte) t.getControlChar(Attributes.ControlChar.VSUSP);
+ // tio.c_cc[VDSUSP] = (byte) t.getControlChar(Attributes.ControlChar.VDSUSP);
+ tio.c_cc[VSTART] = (byte) t.getControlChar(Attributes.ControlChar.VSTART);
+ tio.c_cc[VSTOP] = (byte) t.getControlChar(Attributes.ControlChar.VSTOP);
+ tio.c_cc[VLNEXT] = (byte) t.getControlChar(Attributes.ControlChar.VLNEXT);
+ tio.c_cc[VDISCARD] = (byte) t.getControlChar(Attributes.ControlChar.VDISCARD);
+ tio.c_cc[VMIN] = (byte) t.getControlChar(Attributes.ControlChar.VMIN);
+ tio.c_cc[VTIME] = (byte) t.getControlChar(Attributes.ControlChar.VTIME);
+ // tio.c_cc[VSTATUS] = (byte) t.getControlChar(Attributes.ControlChar.VSTATUS);
+ return tio;
+ }
+
+ protected Attributes toAttributes(CLibrary.Termios tio) {
+ Attributes attr = new Attributes();
+ // Input flags
+ EnumSet iflag = attr.getInputFlags();
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNBRK, IGNBRK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNBRK, IGNBRK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.BRKINT, BRKINT);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNPAR, IGNPAR);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.PARMRK, PARMRK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.INPCK, INPCK);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.ISTRIP, ISTRIP);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.INLCR, INLCR);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IGNCR, IGNCR);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.ICRNL, ICRNL);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IXON, IXON);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IXOFF, IXOFF);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IXANY, IXANY);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IMAXBEL, IMAXBEL);
+ addFlag(tio.c_iflag, iflag, Attributes.InputFlag.IUTF8, IUTF8);
+ // Output flags
+ EnumSet oflag = attr.getOutputFlags();
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OPOST, OPOST);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONLCR, ONLCR);
+ // addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OXTABS, OXTABS);
+ // addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONOEOT, ONOEOT);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OCRNL, OCRNL);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONOCR, ONOCR);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.ONLRET, ONLRET);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OFILL, OFILL);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.NLDLY, NLDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.TABDLY, TABDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.CRDLY, CRDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.FFDLY, FFDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.BSDLY, BSDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.VTDLY, VTDLY);
+ addFlag(tio.c_oflag, oflag, Attributes.OutputFlag.OFDEL, OFDEL);
+ // Control flags
+ EnumSet cflag = attr.getControlFlags();
+ // addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CIGNORE, CIGNORE);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS5, CS5);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS6, CS6);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS7, CS7);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CS8, CS8);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CSTOPB, CSTOPB);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CREAD, CREAD);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.PARENB, PARENB);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.PARODD, PARODD);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.HUPCL, HUPCL);
+ addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CLOCAL, CLOCAL);
+ // addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CCTS_OFLOW, CCTS_OFLOW);
+ // addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CRTS_IFLOW, CRTS_IFLOW);
+ // addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CDSR_OFLOW, CDSR_OFLOW);
+ // addFlag(tio.c_cflag, cflag, Attributes.ControlFlag.CCAR_OFLOW, CCAR_OFLOW);
+ // Local flags
+ EnumSet lflag = attr.getLocalFlags();
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOKE, ECHOKE);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOE, ECHOE);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOK, ECHOK);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHO, ECHO);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHONL, ECHONL);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOPRT, ECHOPRT);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ECHOCTL, ECHOCTL);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ISIG, ISIG);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ICANON, ICANON);
+ // addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.ALTWERASE, ALTWERASE);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.IEXTEN, IEXTEN);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.EXTPROC, EXTPROC);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.TOSTOP, TOSTOP);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.FLUSHO, FLUSHO);
+ // addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.NOKERNINFO, NOKERNINFO);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.PENDIN, PENDIN);
+ addFlag(tio.c_lflag, lflag, Attributes.LocalFlag.NOFLSH, NOFLSH);
+ // Control chars
+ EnumMap cc = attr.getControlChars();
+ cc.put(Attributes.ControlChar.VEOF, (int) tio.c_cc[VEOF]);
+ cc.put(Attributes.ControlChar.VEOL, (int) tio.c_cc[VEOL]);
+ cc.put(Attributes.ControlChar.VEOL2, (int) tio.c_cc[VEOL2]);
+ cc.put(Attributes.ControlChar.VERASE, (int) tio.c_cc[VERASE]);
+ cc.put(Attributes.ControlChar.VWERASE, (int) tio.c_cc[VWERASE]);
+ cc.put(Attributes.ControlChar.VKILL, (int) tio.c_cc[VKILL]);
+ cc.put(Attributes.ControlChar.VREPRINT, (int) tio.c_cc[VREPRINT]);
+ cc.put(Attributes.ControlChar.VINTR, (int) tio.c_cc[VINTR]);
+ cc.put(Attributes.ControlChar.VQUIT, (int) tio.c_cc[VQUIT]);
+ cc.put(Attributes.ControlChar.VSUSP, (int) tio.c_cc[VSUSP]);
+ // cc.put(Attributes.ControlChar.VDSUSP, (int) tio.c_cc[VDSUSP]);
+ cc.put(Attributes.ControlChar.VSTART, (int) tio.c_cc[VSTART]);
+ cc.put(Attributes.ControlChar.VSTOP, (int) tio.c_cc[VSTOP]);
+ cc.put(Attributes.ControlChar.VLNEXT, (int) tio.c_cc[VLNEXT]);
+ cc.put(Attributes.ControlChar.VDISCARD, (int) tio.c_cc[VDISCARD]);
+ cc.put(Attributes.ControlChar.VMIN, (int) tio.c_cc[VMIN]);
+ cc.put(Attributes.ControlChar.VTIME, (int) tio.c_cc[VTIME]);
+ // cc.put(Attributes.ControlChar.VSTATUS, (int) tio.c_cc[VSTATUS]);
+ // Return
+ return attr;
+ }
+
+ private static long setFlag(boolean flag, long value, long org) {
+ return flag ? org | value : org;
+ }
+
+ private static > void addFlag(long value, EnumSet flags, T flag, int v) {
+ if ((value & v) != 0) {
+ flags.add(flag);
+ }
+ }
+}
diff --git a/terminal-jni/src/main/java/org/jline/terminal/impl/jni/win/NativeWinConsoleWriter.java b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/win/NativeWinConsoleWriter.java
new file mode 100644
index 000000000..fa4a9f6e2
--- /dev/null
+++ b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/win/NativeWinConsoleWriter.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2002-2017, 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 org.jline.terminal.impl.jni.win;
+
+import java.io.IOException;
+
+import org.jline.nativ.Kernel32;
+import org.jline.terminal.impl.AbstractWindowsConsoleWriter;
+
+class NativeWinConsoleWriter extends AbstractWindowsConsoleWriter {
+
+ private final long console;
+ private final int[] writtenChars = new int[1];
+
+ public NativeWinConsoleWriter(long console) {
+ this.console = console;
+ }
+
+ @Override
+ protected void writeConsole(char[] text, int len) throws IOException {
+ if (Kernel32.WriteConsoleW(console, text, len, writtenChars, 0) == 0) {
+ throw new IOException("Failed to write to console: " + Kernel32.getLastErrorMessage());
+ }
+ }
+}
diff --git a/terminal-jni/src/main/java/org/jline/terminal/impl/jni/win/NativeWinSysTerminal.java b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/win/NativeWinSysTerminal.java
new file mode 100644
index 000000000..6e8abfad6
--- /dev/null
+++ b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/win/NativeWinSysTerminal.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2002-2020, 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 org.jline.terminal.impl.jni.win;
+
+import java.io.BufferedWriter;
+import java.io.IOError;
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.function.IntConsumer;
+
+import org.jline.nativ.Kernel32;
+import org.jline.nativ.Kernel32.CONSOLE_SCREEN_BUFFER_INFO;
+import org.jline.nativ.Kernel32.INPUT_RECORD;
+import org.jline.nativ.Kernel32.KEY_EVENT_RECORD;
+import org.jline.terminal.Cursor;
+import org.jline.terminal.Size;
+import org.jline.terminal.impl.AbstractWindowsTerminal;
+import org.jline.terminal.spi.SystemStream;
+import org.jline.terminal.spi.TerminalProvider;
+import org.jline.utils.InfoCmp;
+import org.jline.utils.OSUtils;
+
+import static org.jline.nativ.Kernel32.FORMAT_MESSAGE_FROM_SYSTEM;
+import static org.jline.nativ.Kernel32.FormatMessageW;
+import static org.jline.nativ.Kernel32.GetConsoleScreenBufferInfo;
+import static org.jline.nativ.Kernel32.GetLastError;
+import static org.jline.nativ.Kernel32.GetStdHandle;
+import static org.jline.nativ.Kernel32.INVALID_HANDLE_VALUE;
+import static org.jline.nativ.Kernel32.STD_ERROR_HANDLE;
+import static org.jline.nativ.Kernel32.STD_INPUT_HANDLE;
+import static org.jline.nativ.Kernel32.STD_OUTPUT_HANDLE;
+import static org.jline.nativ.Kernel32.WaitForSingleObject;
+import static org.jline.nativ.Kernel32.readConsoleInputHelper;
+
+public class NativeWinSysTerminal extends AbstractWindowsTerminal {
+
+ private static final long consoleIn = GetStdHandle(STD_INPUT_HANDLE);
+ private static final long consoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ private static final long consoleErr = GetStdHandle(STD_ERROR_HANDLE);
+
+ public static NativeWinSysTerminal createTerminal(
+ TerminalProvider provider,
+ SystemStream systemStream,
+ String name,
+ String type,
+ boolean ansiPassThrough,
+ Charset encoding,
+ boolean nativeSignals,
+ SignalHandler signalHandler,
+ boolean paused)
+ throws IOException {
+ // Get input console mode
+ int[] inMode = new int[1];
+ if (Kernel32.GetConsoleMode(consoleIn, inMode) == 0) {
+ throw new IOException("Failed to get console mode: " + getLastErrorMessage());
+ }
+ // Get output console and mode
+ long console = getConsole(systemStream);
+ int[] outMode = new int[1];
+ if (Kernel32.GetConsoleMode(console, outMode) == 0) {
+ throw new IOException("Failed to get console mode: " + getLastErrorMessage());
+ }
+ // Create writer
+ Writer writer;
+ if (ansiPassThrough) {
+ type = type != null ? type : OSUtils.IS_CONEMU ? TYPE_WINDOWS_CONEMU : TYPE_WINDOWS;
+ writer = newConsoleWriter(console);
+ } else {
+ if (enableVtp(console, outMode[0])) {
+ type = type != null ? type : TYPE_WINDOWS_VTP;
+ writer = newConsoleWriter(console);
+ } else if (OSUtils.IS_CONEMU) {
+ type = type != null ? type : TYPE_WINDOWS_CONEMU;
+ writer = newConsoleWriter(console);
+ } else {
+ type = type != null ? type : TYPE_WINDOWS;
+ writer = new WindowsAnsiWriter(new BufferedWriter(newConsoleWriter(console)));
+ }
+ }
+ // Create terminal
+ NativeWinSysTerminal terminal = new NativeWinSysTerminal(
+ provider,
+ systemStream,
+ writer,
+ name,
+ type,
+ encoding,
+ nativeSignals,
+ signalHandler,
+ consoleIn,
+ inMode[0],
+ console,
+ outMode[0]);
+ // Start input pump thread
+ if (!paused) {
+ terminal.resume();
+ }
+ return terminal;
+ }
+
+ public static long getConsole(SystemStream systemStream) {
+ long console;
+ switch (systemStream) {
+ case Output:
+ console = consoleOut;
+ break;
+ case Error:
+ console = consoleErr;
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported stream for console: " + systemStream);
+ }
+ return console;
+ }
+
+ private static boolean enableVtp(long console, int outMode) {
+ return Kernel32.SetConsoleMode(console, outMode | AbstractWindowsTerminal.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+ != 0;
+ }
+
+ private static Writer newConsoleWriter(long console) {
+ return new NativeWinConsoleWriter(console);
+ }
+
+ public static boolean isWindowsSystemStream(SystemStream stream) {
+ int[] mode = new int[1];
+ long console;
+ switch (stream) {
+ case Input:
+ console = consoleIn;
+ break;
+ case Output:
+ console = consoleOut;
+ break;
+ case Error:
+ console = consoleErr;
+ break;
+ default:
+ return false;
+ }
+ return Kernel32.GetConsoleMode(console, mode) != 0;
+ }
+
+ NativeWinSysTerminal(
+ TerminalProvider provider,
+ SystemStream systemStream,
+ Writer writer,
+ String name,
+ String type,
+ Charset encoding,
+ boolean nativeSignals,
+ SignalHandler signalHandler,
+ long inConsole,
+ int inMode,
+ long outConsole,
+ int outMode)
+ throws IOException {
+ super(
+ provider,
+ systemStream,
+ writer,
+ name,
+ type,
+ encoding,
+ nativeSignals,
+ signalHandler,
+ inConsole,
+ inMode,
+ outConsole,
+ outMode);
+ }
+
+ @Override
+ protected int getConsoleMode(Long console) {
+ int[] mode = new int[1];
+ if (Kernel32.GetConsoleMode(console, mode) == 0) {
+ return -1;
+ }
+ return mode[0];
+ }
+
+ @Override
+ protected void setConsoleMode(Long console, int mode) {
+ Kernel32.SetConsoleMode(console, mode);
+ }
+
+ public Size getSize() {
+ CONSOLE_SCREEN_BUFFER_INFO info = new CONSOLE_SCREEN_BUFFER_INFO();
+ Kernel32.GetConsoleScreenBufferInfo(outConsole, info);
+ return new Size(info.windowWidth(), info.windowHeight());
+ }
+
+ @Override
+ public Size getBufferSize() {
+ CONSOLE_SCREEN_BUFFER_INFO info = new CONSOLE_SCREEN_BUFFER_INFO();
+ Kernel32.GetConsoleScreenBufferInfo(outConsole, info);
+ return new Size(info.size.x, info.size.y);
+ }
+
+ protected boolean processConsoleInput() throws IOException {
+ INPUT_RECORD[] events;
+ if (inConsole != INVALID_HANDLE_VALUE && WaitForSingleObject(inConsole, 100) == 0) {
+ events = readConsoleInputHelper(inConsole, 1, false);
+ } else {
+ return false;
+ }
+
+ boolean flush = false;
+ for (INPUT_RECORD event : events) {
+ if (event.eventType == INPUT_RECORD.KEY_EVENT) {
+ KEY_EVENT_RECORD keyEvent = event.keyEvent;
+ processKeyEvent(keyEvent.keyDown, keyEvent.keyCode, keyEvent.uchar, keyEvent.controlKeyState);
+ flush = true;
+ } else if (event.eventType == INPUT_RECORD.WINDOW_BUFFER_SIZE_EVENT) {
+ raise(Signal.WINCH);
+ } else if (event.eventType == INPUT_RECORD.MOUSE_EVENT) {
+ processMouseEvent(event.mouseEvent);
+ flush = true;
+ } else if (event.eventType == INPUT_RECORD.FOCUS_EVENT) {
+ processFocusEvent(event.focusEvent.setFocus);
+ }
+ }
+
+ return flush;
+ }
+
+ private char[] focus = new char[] {'\033', '[', ' '};
+
+ private void processFocusEvent(boolean hasFocus) throws IOException {
+ if (focusTracking) {
+ focus[2] = hasFocus ? 'I' : 'O';
+ slaveInputPipe.write(focus);
+ }
+ }
+
+ private char[] mouse = new char[] {'\033', '[', 'M', ' ', ' ', ' '};
+
+ private void processMouseEvent(Kernel32.MOUSE_EVENT_RECORD mouseEvent) throws IOException {
+ int dwEventFlags = mouseEvent.eventFlags;
+ int dwButtonState = mouseEvent.buttonState;
+ if (tracking == MouseTracking.Off
+ || tracking == MouseTracking.Normal && dwEventFlags == Kernel32.MOUSE_EVENT_RECORD.MOUSE_MOVED
+ || tracking == MouseTracking.Button
+ && dwEventFlags == Kernel32.MOUSE_EVENT_RECORD.MOUSE_MOVED
+ && dwButtonState == 0) {
+ return;
+ }
+ int cb = 0;
+ dwEventFlags &= ~Kernel32.MOUSE_EVENT_RECORD.DOUBLE_CLICK; // Treat double-clicks as normal
+ if (dwEventFlags == Kernel32.MOUSE_EVENT_RECORD.MOUSE_WHEELED) {
+ cb |= 64;
+ if ((dwButtonState >> 16) < 0) {
+ cb |= 1;
+ }
+ } else if (dwEventFlags == Kernel32.MOUSE_EVENT_RECORD.MOUSE_HWHEELED) {
+ return;
+ } else if ((dwButtonState & Kernel32.MOUSE_EVENT_RECORD.FROM_LEFT_1ST_BUTTON_PRESSED) != 0) {
+ cb |= 0x00;
+ } else if ((dwButtonState & Kernel32.MOUSE_EVENT_RECORD.RIGHTMOST_BUTTON_PRESSED) != 0) {
+ cb |= 0x01;
+ } else if ((dwButtonState & Kernel32.MOUSE_EVENT_RECORD.FROM_LEFT_2ND_BUTTON_PRESSED) != 0) {
+ cb |= 0x02;
+ } else {
+ cb |= 0x03;
+ }
+ int cx = mouseEvent.mousePosition.x;
+ int cy = mouseEvent.mousePosition.y;
+ mouse[3] = (char) (' ' + cb);
+ mouse[4] = (char) (' ' + cx + 1);
+ mouse[5] = (char) (' ' + cy + 1);
+ slaveInputPipe.write(mouse);
+ }
+
+ @Override
+ public Cursor getCursorPosition(IntConsumer discarded) {
+ CONSOLE_SCREEN_BUFFER_INFO info = new CONSOLE_SCREEN_BUFFER_INFO();
+ if (GetConsoleScreenBufferInfo(outConsole, info) == 0) {
+ throw new IOError(new IOException("Could not get the cursor position: " + getLastErrorMessage()));
+ }
+ return new Cursor(info.cursorPosition.x, info.cursorPosition.y);
+ }
+
+ public void disableScrolling() {
+ strings.remove(InfoCmp.Capability.insert_line);
+ strings.remove(InfoCmp.Capability.parm_insert_line);
+ strings.remove(InfoCmp.Capability.delete_line);
+ strings.remove(InfoCmp.Capability.parm_delete_line);
+ }
+
+ static String getLastErrorMessage() {
+ int errorCode = GetLastError();
+ return getErrorMessage(errorCode);
+ }
+
+ static String getErrorMessage(int errorCode) {
+ int bufferSize = 160;
+ byte[] data = new byte[bufferSize];
+ FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, 0, errorCode, 0, data, bufferSize, null);
+ return new String(data, StandardCharsets.UTF_16LE).trim();
+ }
+}
diff --git a/terminal-jni/src/main/java/org/jline/terminal/impl/jni/win/WindowsAnsiWriter.java b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/win/WindowsAnsiWriter.java
new file mode 100644
index 000000000..32d2a32e3
--- /dev/null
+++ b/terminal-jni/src/main/java/org/jline/terminal/impl/jni/win/WindowsAnsiWriter.java
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2009-2018, 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 org.jline.terminal.impl.jni.win;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.jline.nativ.Kernel32;
+import org.jline.utils.AnsiWriter;
+import org.jline.utils.Colors;
+
+import static org.jline.nativ.Kernel32.*;
+
+/**
+ * A Windows ANSI escape processor, that uses JNA to access native platform
+ * API's to change the console attributes.
+ *
+ * @since 1.0
+ * @author Hiram Chirino
+ * @author Joris Kuipers
+ */
+public final class WindowsAnsiWriter extends AnsiWriter {
+
+ private static final long console = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ private static final short FOREGROUND_BLACK = 0;
+ private static final short FOREGROUND_YELLOW = (short) (FOREGROUND_RED | FOREGROUND_GREEN);
+ private static final short FOREGROUND_MAGENTA = (short) (FOREGROUND_BLUE | FOREGROUND_RED);
+ private static final short FOREGROUND_CYAN = (short) (FOREGROUND_BLUE | FOREGROUND_GREEN);
+ private static final short FOREGROUND_WHITE = (short) (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+
+ private static final short BACKGROUND_BLACK = 0;
+ private static final short BACKGROUND_YELLOW = (short) (BACKGROUND_RED | BACKGROUND_GREEN);
+ private static final short BACKGROUND_MAGENTA = (short) (BACKGROUND_BLUE | BACKGROUND_RED);
+ private static final short BACKGROUND_CYAN = (short) (BACKGROUND_BLUE | BACKGROUND_GREEN);
+ private static final short BACKGROUND_WHITE = (short) (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
+
+ private static final short[] ANSI_FOREGROUND_COLOR_MAP = {
+ FOREGROUND_BLACK,
+ FOREGROUND_RED,
+ FOREGROUND_GREEN,
+ FOREGROUND_YELLOW,
+ FOREGROUND_BLUE,
+ FOREGROUND_MAGENTA,
+ FOREGROUND_CYAN,
+ FOREGROUND_WHITE,
+ };
+
+ private static final short[] ANSI_BACKGROUND_COLOR_MAP = {
+ BACKGROUND_BLACK,
+ BACKGROUND_RED,
+ BACKGROUND_GREEN,
+ BACKGROUND_YELLOW,
+ BACKGROUND_BLUE,
+ BACKGROUND_MAGENTA,
+ BACKGROUND_CYAN,
+ BACKGROUND_WHITE,
+ };
+
+ private final CONSOLE_SCREEN_BUFFER_INFO info = new CONSOLE_SCREEN_BUFFER_INFO();
+ private final short originalColors;
+
+ private boolean negative;
+ private boolean bold;
+ private boolean underline;
+ private short savedX = -1;
+ private short savedY = -1;
+
+ public WindowsAnsiWriter(Writer out) throws IOException {
+ super(out);
+ getConsoleInfo();
+ originalColors = info.attributes;
+ }
+
+ private void getConsoleInfo() throws IOException {
+ out.flush();
+ if (GetConsoleScreenBufferInfo(console, info) == 0) {
+ throw new IOException("Could not get the screen info: " + Kernel32.getLastErrorMessage());
+ }
+ if (negative) {
+ info.attributes = invertAttributeColors(info.attributes);
+ }
+ }
+
+ private void applyAttribute() throws IOException {
+ out.flush();
+ short attributes = info.attributes;
+ // bold is simulated by high foreground intensity
+ if (bold) {
+ attributes |= FOREGROUND_INTENSITY;
+ }
+ // underline is simulated by high foreground intensity
+ if (underline) {
+ attributes |= BACKGROUND_INTENSITY;
+ }
+ if (negative) {
+ attributes = invertAttributeColors(attributes);
+ }
+ if (SetConsoleTextAttribute(console, attributes) == 0) {
+ throw new IOException(Kernel32.getLastErrorMessage());
+ }
+ }
+
+ private short invertAttributeColors(short attributes) {
+ // Swap the the Foreground and Background bits.
+ int fg = 0x000F & attributes;
+ fg <<= 4;
+ int bg = 0X00F0 & attributes;
+ bg >>= 4;
+ attributes = (short) ((attributes & 0xFF00) | fg | bg);
+ return attributes;
+ }
+
+ private void applyCursorPosition() throws IOException {
+ info.cursorPosition.x = (short) Math.max(0, Math.min(info.size.x - 1, info.cursorPosition.x));
+ info.cursorPosition.y = (short) Math.max(0, Math.min(info.size.y - 1, info.cursorPosition.y));
+ if (SetConsoleCursorPosition(console, info.cursorPosition.copy()) == 0) {
+ throw new IOException(Kernel32.getLastErrorMessage());
+ }
+ }
+
+ @Override
+ protected void processEraseScreen(int eraseOption) throws IOException {
+ getConsoleInfo();
+ int[] written = new int[1];
+ switch (eraseOption) {
+ case ERASE_SCREEN:
+ COORD topLeft = new COORD();
+ topLeft.x = 0;
+ topLeft.y = info.window.top;
+ int screenLength = info.window.height() * info.size.x;
+ FillConsoleOutputAttribute(console, originalColors, screenLength, topLeft, written);
+ FillConsoleOutputCharacterW(console, ' ', screenLength, topLeft, written);
+ break;
+ case ERASE_SCREEN_TO_BEGINING:
+ COORD topLeft2 = new COORD();
+ topLeft2.x = 0;
+ topLeft2.y = info.window.top;
+ int lengthToCursor = (info.cursorPosition.y - info.window.top) * info.size.x + info.cursorPosition.x;
+ FillConsoleOutputAttribute(console, originalColors, lengthToCursor, topLeft2, written);
+ FillConsoleOutputCharacterW(console, ' ', lengthToCursor, topLeft2, written);
+ break;
+ case ERASE_SCREEN_TO_END:
+ int lengthToEnd = (info.window.bottom - info.cursorPosition.y) * info.size.x
+ + (info.size.x - info.cursorPosition.x);
+ FillConsoleOutputAttribute(console, originalColors, lengthToEnd, info.cursorPosition.copy(), written);
+ FillConsoleOutputCharacterW(console, ' ', lengthToEnd, info.cursorPosition.copy(), written);
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ protected void processEraseLine(int eraseOption) throws IOException {
+ getConsoleInfo();
+ int[] written = new int[1];
+ switch (eraseOption) {
+ case ERASE_LINE:
+ COORD leftColCurrRow = info.cursorPosition.copy();
+ leftColCurrRow.x = 0;
+ FillConsoleOutputAttribute(console, originalColors, info.size.x, leftColCurrRow, written);
+ FillConsoleOutputCharacterW(console, ' ', info.size.x, leftColCurrRow, written);
+ break;
+ case ERASE_LINE_TO_BEGINING:
+ COORD leftColCurrRow2 = info.cursorPosition.copy();
+ leftColCurrRow2.x = 0;
+ FillConsoleOutputAttribute(console, originalColors, info.cursorPosition.x, leftColCurrRow2, written);
+ FillConsoleOutputCharacterW(console, ' ', info.cursorPosition.x, leftColCurrRow2, written);
+ break;
+ case ERASE_LINE_TO_END:
+ int lengthToLastCol = info.size.x - info.cursorPosition.x;
+ FillConsoleOutputAttribute(
+ console, originalColors, lengthToLastCol, info.cursorPosition.copy(), written);
+ FillConsoleOutputCharacterW(console, ' ', lengthToLastCol, info.cursorPosition.copy(), written);
+ break;
+ default:
+ break;
+ }
+ }
+
+ protected void processCursorUpLine(int count) throws IOException {
+ getConsoleInfo();
+ info.cursorPosition.x = 0;
+ info.cursorPosition.y -= (short) count;
+ applyCursorPosition();
+ }
+
+ protected void processCursorDownLine(int count) throws IOException {
+ getConsoleInfo();
+ info.cursorPosition.x = 0;
+ info.cursorPosition.y += (short) count;
+ applyCursorPosition();
+ }
+
+ @Override
+ protected void processCursorLeft(int count) throws IOException {
+ getConsoleInfo();
+ info.cursorPosition.x -= (short) count;
+ applyCursorPosition();
+ }
+
+ @Override
+ protected void processCursorRight(int count) throws IOException {
+ getConsoleInfo();
+ info.cursorPosition.x += (short) count;
+ applyCursorPosition();
+ }
+
+ @Override
+ protected void processCursorDown(int count) throws IOException {
+ getConsoleInfo();
+ int nb = Math.max(0, info.cursorPosition.y + count - info.size.y + 1);
+ if (nb != count) {
+ info.cursorPosition.y += (short) count;
+ applyCursorPosition();
+ }
+ if (nb > 0) {
+ SMALL_RECT scroll = info.window.copy();
+ scroll.top = 0;
+ COORD org = new COORD();
+ org.x = 0;
+ org.y = (short) (-nb);
+ CHAR_INFO info = new CHAR_INFO();
+ info.unicodeChar = ' ';
+ info.attributes = originalColors;
+ ScrollConsoleScreenBuffer(console, scroll, scroll, org, info);
+ }
+ }
+
+ @Override
+ protected void processCursorUp(int count) throws IOException {
+ getConsoleInfo();
+ info.cursorPosition.y -= (short) count;
+ applyCursorPosition();
+ }
+
+ @Override
+ protected void processCursorTo(int row, int col) throws IOException {
+ getConsoleInfo();
+ info.cursorPosition.y = (short) (info.window.top + row - 1);
+ info.cursorPosition.x = (short) (col - 1);
+ applyCursorPosition();
+ }
+
+ @Override
+ protected void processCursorToColumn(int x) throws IOException {
+ getConsoleInfo();
+ info.cursorPosition.x = (short) (x - 1);
+ applyCursorPosition();
+ }
+
+ @Override
+ protected void processSetForegroundColorExt(int paletteIndex) throws IOException {
+ int color = Colors.roundColor(paletteIndex, 16);
+ info.attributes = (short) ((info.attributes & ~0x0007) | ANSI_FOREGROUND_COLOR_MAP[color & 0x07]);
+ info.attributes = (short) ((info.attributes & ~FOREGROUND_INTENSITY) | (color >= 8 ? FOREGROUND_INTENSITY : 0));
+ applyAttribute();
+ }
+
+ @Override
+ protected void processSetBackgroundColorExt(int paletteIndex) throws IOException {
+ int color = Colors.roundColor(paletteIndex, 16);
+ info.attributes = (short) ((info.attributes & ~0x0070) | ANSI_BACKGROUND_COLOR_MAP[color & 0x07]);
+ info.attributes = (short) ((info.attributes & ~BACKGROUND_INTENSITY) | (color >= 8 ? BACKGROUND_INTENSITY : 0));
+ applyAttribute();
+ }
+
+ @Override
+ protected void processDefaultTextColor() throws IOException {
+ info.attributes = (short) ((info.attributes & ~0x000F) | (originalColors & 0xF));
+ info.attributes = (short) (info.attributes & ~FOREGROUND_INTENSITY);
+ applyAttribute();
+ }
+
+ @Override
+ protected void processDefaultBackgroundColor() throws IOException {
+ info.attributes = (short) ((info.attributes & ~0x00F0) | (originalColors & 0xF0));
+ info.attributes = (short) (info.attributes & ~BACKGROUND_INTENSITY);
+ applyAttribute();
+ }
+
+ @Override
+ protected void processAttributeRest() throws IOException {
+ info.attributes = (short) ((info.attributes & ~0x00FF) | originalColors);
+ this.negative = false;
+ this.bold = false;
+ this.underline = false;
+ applyAttribute();
+ }
+
+ @Override
+ protected void processSetAttribute(int attribute) throws IOException {
+ switch (attribute) {
+ case ATTRIBUTE_INTENSITY_BOLD:
+ bold = true;
+ applyAttribute();
+ break;
+ case ATTRIBUTE_INTENSITY_NORMAL:
+ bold = false;
+ applyAttribute();
+ break;
+
+ case ATTRIBUTE_UNDERLINE:
+ underline = true;
+ applyAttribute();
+ break;
+ case ATTRIBUTE_UNDERLINE_OFF:
+ underline = false;
+ applyAttribute();
+ break;
+
+ case ATTRIBUTE_NEGATIVE_ON:
+ negative = true;
+ applyAttribute();
+ break;
+ case ATTRIBUTE_NEGATIVE_OFF:
+ negative = false;
+ applyAttribute();
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ protected void processSaveCursorPosition() throws IOException {
+ getConsoleInfo();
+ savedX = info.cursorPosition.x;
+ savedY = info.cursorPosition.y;
+ }
+
+ @Override
+ protected void processRestoreCursorPosition() throws IOException {
+ // restore only if there was a save operation first
+ if (savedX != -1 && savedY != -1) {
+ out.flush();
+ info.cursorPosition.x = savedX;
+ info.cursorPosition.y = savedY;
+ applyCursorPosition();
+ }
+ }
+
+ @Override
+ protected void processInsertLine(int optionInt) throws IOException {
+ getConsoleInfo();
+ SMALL_RECT scroll = info.window.copy();
+ scroll.top = info.cursorPosition.y;
+ COORD org = new COORD();
+ org.x = 0;
+ org.y = (short) (info.cursorPosition.y + optionInt);
+ CHAR_INFO info = new CHAR_INFO();
+ info.attributes = originalColors;
+ info.unicodeChar = ' ';
+ if (ScrollConsoleScreenBuffer(console, scroll, scroll, org, info) == 0) {
+ throw new IOException(Kernel32.getLastErrorMessage());
+ }
+ }
+
+ @Override
+ protected void processDeleteLine(int optionInt) throws IOException {
+ getConsoleInfo();
+ SMALL_RECT scroll = info.window.copy();
+ scroll.top = info.cursorPosition.y;
+ COORD org = new COORD();
+ org.x = 0;
+ org.y = (short) (info.cursorPosition.y - optionInt);
+ CHAR_INFO info = new CHAR_INFO();
+ info.attributes = originalColors;
+ info.unicodeChar = ' ';
+ if (ScrollConsoleScreenBuffer(console, scroll, scroll, org, info) == 0) {
+ throw new IOException(Kernel32.getLastErrorMessage());
+ }
+ }
+
+ @Override
+ protected void processChangeWindowTitle(String title) {
+ SetConsoleTitle(title);
+ }
+}
diff --git a/terminal-jni/src/main/resources/META-INF/native-image/org.jline/jline-terminal-jni/native-image.properties b/terminal-jni/src/main/resources/META-INF/native-image/org.jline/jline-terminal-jni/native-image.properties
new file mode 100644
index 000000000..1a4e8e5a5
--- /dev/null
+++ b/terminal-jni/src/main/resources/META-INF/native-image/org.jline/jline-terminal-jni/native-image.properties
@@ -0,0 +1 @@
+Args = -H:ResourceConfigurationResources=${.}/resource-config.json -H:ReflectionConfigurationResources=${.}/reflection-config.json
diff --git a/terminal-jni/src/main/resources/META-INF/native-image/org.jline/jline-terminal-jni/reflection-config.json b/terminal-jni/src/main/resources/META-INF/native-image/org.jline/jline-terminal-jni/reflection-config.json
new file mode 100644
index 000000000..d769687cc
--- /dev/null
+++ b/terminal-jni/src/main/resources/META-INF/native-image/org.jline/jline-terminal-jni/reflection-config.json
@@ -0,0 +1,11 @@
+[
+ {
+ "name" : "org.jline.terminal.impl.jni.JniTerminalProvider",
+ "allDeclaredConstructors" : true,
+ "allPublicConstructors" : true,
+ "allDeclaredMethods" : false,
+ "allPublicMethods" : false,
+ "allDeclaredFields" : false,
+ "allPublicFields" : false
+ }
+]
\ No newline at end of file
diff --git a/terminal-jni/src/main/resources/META-INF/native-image/org.jline/jline-terminal-jni/resource-config.json b/terminal-jni/src/main/resources/META-INF/native-image/org.jline/jline-terminal-jni/resource-config.json
new file mode 100644
index 000000000..f187ea298
--- /dev/null
+++ b/terminal-jni/src/main/resources/META-INF/native-image/org.jline/jline-terminal-jni/resource-config.json
@@ -0,0 +1,5 @@
+{
+ "resources": [
+ {"pattern": "META-INF/services/org/jline/terminal/provider/.*"}
+ ]
+}
\ No newline at end of file
diff --git a/terminal-jni/src/main/resources/META-INF/services/org/jline/terminal/provider/jni b/terminal-jni/src/main/resources/META-INF/services/org/jline/terminal/provider/jni
new file mode 100644
index 000000000..10de0e864
--- /dev/null
+++ b/terminal-jni/src/main/resources/META-INF/services/org/jline/terminal/provider/jni
@@ -0,0 +1,16 @@
+#
+# Copyright (C) 2022 the original author(s).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+class = org.jline.terminal.impl.jni.JniTerminalProvider
diff --git a/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java b/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java
index 32993ba98..fd952afc6 100644
--- a/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java
+++ b/terminal/src/main/java/org/jline/terminal/TerminalBuilder.java
@@ -51,9 +51,10 @@ public final class TerminalBuilder {
public static final String PROP_CODEPAGE = "org.jline.terminal.codepage";
public static final String PROP_TYPE = "org.jline.terminal.type";
public static final String PROP_PROVIDERS = "org.jline.terminal.providers";
- public static final String PROP_PROVIDERS_DEFAULT = "ffm,jansi,jna,exec";
+ public static final String PROP_PROVIDERS_DEFAULT = "ffm,jni,jansi,jna,exec";
public static final String PROP_JNA = "org.jline.terminal.jna";
public static final String PROP_JANSI = "org.jline.terminal.jansi";
+ public static final String PROP_JNI = "org.jline.terminal.jni";
public static final String PROP_EXEC = "org.jline.terminal.exec";
public static final String PROP_FFM = "org.jline.terminal.ffm";
public static final String PROP_DUMB = "org.jline.terminal.dumb";
@@ -140,6 +141,7 @@ public static TerminalBuilder builder() {
private String providers;
private Boolean jna;
private Boolean jansi;
+ private Boolean jni;
private Boolean exec;
private Boolean ffm;
private Boolean dumb;
@@ -193,7 +195,12 @@ public TerminalBuilder jna(boolean jna) {
}
public TerminalBuilder jansi(boolean jansi) {
- this.jansi = jansi;
+ this.jansi = this.jansi;
+ return this;
+ }
+
+ public TerminalBuilder jni(boolean jni) {
+ this.jni = this.jni;
return this;
}
@@ -387,6 +394,10 @@ private Terminal doBuild() throws IOException {
if (jansi == null) {
jansi = getBoolean(PROP_JANSI, true);
}
+ Boolean nativ = this.jni;
+ if (nativ == null) {
+ nativ = getBoolean(PROP_JNI, true);
+ }
Boolean exec = this.exec;
if (exec == null) {
exec = getBoolean(PROP_EXEC, true);
@@ -431,6 +442,16 @@ private Terminal doBuild() throws IOException {
exception.addSuppressed(t);
}
}
+ if (nativ) {
+ try {
+ TerminalProvider provider = TerminalProvider.load("nativ");
+ provider.isSystemStream(SystemStream.Output);
+ providers.add(provider);
+ } catch (Throwable t) {
+ Log.debug("Unable to load Native support: ", t);
+ exception.addSuppressed(t);
+ }
+ }
if (exec) {
try {
TerminalProvider provider = TerminalProvider.load("exec");
@@ -532,7 +553,7 @@ private Terminal doBuild() throws IOException {
}
}
}
- if (terminal == null && OSUtils.IS_WINDOWS && !jna && !jansi && (dumb == null || !dumb)) {
+ if (terminal == null && OSUtils.IS_WINDOWS && !jna && !jansi && !nativ && (dumb == null || !dumb)) {
throw new IllegalStateException("Unable to create a system terminal. On windows, either "
+ "JNA or JANSI library is required. Make sure to add one of those in the classpath.");
}
diff --git a/terminal/src/main/java/org/jline/terminal/impl/Diag.java b/terminal/src/main/java/org/jline/terminal/impl/Diag.java
index b35e62555..ecef6c13f 100644
--- a/terminal/src/main/java/org/jline/terminal/impl/Diag.java
+++ b/terminal/src/main/java/org/jline/terminal/impl/Diag.java
@@ -82,6 +82,16 @@ static void diag(PrintStream out) {
}
out.println();
+ out.println("JniSupport");
+ out.println("=================");
+ try {
+ TerminalProvider provider = TerminalProvider.load("jni");
+ testProvider(out, provider);
+ } catch (Throwable t) {
+ out.println("JNI support not available: " + t);
+ }
+ out.println();
+
// Exec
out.println("Exec Support");
out.println("=================");