diff --git a/src/main/cpp/win.cpp b/src/main/cpp/win.cpp index dbab1ba..b9baebb 100755 --- a/src/main/cpp/win.cpp +++ b/src/main/cpp/win.cpp @@ -51,11 +51,11 @@ Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_isConsole( } JNIEXPORT void JNICALL -Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_getConsoleSize (JNIEnv *env, jclass target, jint output, jobject dimension, jobject result) { +Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_getConsoleSize(JNIEnv *env, jclass target, jint output, jobject dimension, jobject result) { CONSOLE_SCREEN_BUFFER_INFO console_info; HANDLE handle = getHandle(env, output, result); if (handle == NULL) { - mark_failed_with_message(env, "not a terminal", result); + mark_failed_with_message(env, "not a console", result); return; } if (!GetConsoleScreenBufferInfo(handle, &console_info)) { @@ -156,4 +156,81 @@ Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_foreground } } +JNIEXPORT void JNICALL +Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_left(JNIEnv *env, jclass target, jint count, jobject result) { + CONSOLE_SCREEN_BUFFER_INFO console_info; + if (!GetConsoleScreenBufferInfo(current_console, &console_info)) { + mark_failed_with_errno(env, "could not get console buffer", result); + return; + } + console_info.dwCursorPosition.X -= count; + if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) { + mark_failed_with_errno(env, "could not set cursor position", result); + } +} + +JNIEXPORT void JNICALL +Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_right(JNIEnv *env, jclass target, jint count, jobject result) { + CONSOLE_SCREEN_BUFFER_INFO console_info; + if (!GetConsoleScreenBufferInfo(current_console, &console_info)) { + mark_failed_with_errno(env, "could not get console buffer", result); + return; + } + console_info.dwCursorPosition.X += count; + if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) { + mark_failed_with_errno(env, "could not set cursor position", result); + } +} + +JNIEXPORT void JNICALL +Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_up(JNIEnv *env, jclass target, jint count, jobject result) { + CONSOLE_SCREEN_BUFFER_INFO console_info; + if (!GetConsoleScreenBufferInfo(current_console, &console_info)) { + mark_failed_with_errno(env, "could not get console buffer", result); + return; + } + console_info.dwCursorPosition.Y -= count; + if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) { + mark_failed_with_errno(env, "could not set cursor position", result); + } +} + +JNIEXPORT void JNICALL +Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_down(JNIEnv *env, jclass target, jint count, jobject result) { + CONSOLE_SCREEN_BUFFER_INFO console_info; + if (!GetConsoleScreenBufferInfo(current_console, &console_info)) { + mark_failed_with_errno(env, "could not get console buffer", result); + return; + } + console_info.dwCursorPosition.Y += count; + if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) { + mark_failed_with_errno(env, "could not set cursor position", result); + } +} + +JNIEXPORT void JNICALL +Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_startLine(JNIEnv *env, jclass target, jobject result) { + CONSOLE_SCREEN_BUFFER_INFO console_info; + if (!GetConsoleScreenBufferInfo(current_console, &console_info)) { + mark_failed_with_errno(env, "could not get console buffer", result); + return; + } + console_info.dwCursorPosition.X = 0; + if (!SetConsoleCursorPosition(current_console, console_info.dwCursorPosition)) { + mark_failed_with_errno(env, "could not set cursor position", result); + } +} + +JNIEXPORT void JNICALL +Java_net_rubygrapefruit_platform_internal_jni_WindowsConsoleFunctions_clearToEndOfLine(JNIEnv *env, jclass target, jobject result) { + CONSOLE_SCREEN_BUFFER_INFO console_info; + if (!GetConsoleScreenBufferInfo(current_console, &console_info)) { + mark_failed_with_errno(env, "could not get console buffer", result); + return; + } + for (int i = console_info.dwCursorPosition.X; i < console_info.dwSize.X; i++) { + WriteConsole(current_console, " ", 1, NULL, NULL); + } +} + #endif diff --git a/src/main/java/net/rubygrapefruit/platform/internal/WindowsTerminal.java b/src/main/java/net/rubygrapefruit/platform/internal/WindowsTerminal.java index da24fae..e237e19 100755 --- a/src/main/java/net/rubygrapefruit/platform/internal/WindowsTerminal.java +++ b/src/main/java/net/rubygrapefruit/platform/internal/WindowsTerminal.java @@ -1,110 +1,141 @@ -package net.rubygrapefruit.platform.internal; - -import net.rubygrapefruit.platform.NativeException; -import net.rubygrapefruit.platform.Terminal; -import net.rubygrapefruit.platform.TerminalAccess; -import net.rubygrapefruit.platform.TerminalSize; -import net.rubygrapefruit.platform.internal.jni.WindowsConsoleFunctions; - -public class WindowsTerminal extends AbstractTerminal { - private final TerminalAccess.Output output; - - public WindowsTerminal(TerminalAccess.Output output) { - this.output = output; - } - - @Override - public String toString() { - return output.toString().toLowerCase(); - } - - @Override - protected void doInit() { - FunctionResult result = new FunctionResult(); - WindowsConsoleFunctions.initConsole(output.ordinal(), result); - if (result.isFailed()) { - throw new NativeException(String.format("Could not open console for %s: %s", this, result.getMessage())); - } - } - - @Override - public TerminalSize getTerminalSize() { - FunctionResult result = new FunctionResult(); - MutableTerminalSize size = new MutableTerminalSize(); - WindowsConsoleFunctions.getConsoleSize(output.ordinal(), size, result); - if (result.isFailed()) { - throw new NativeException(String.format("Could not determine console size for %s: %s", this, result.getMessage())); - } - return size; - } - - @Override - public Terminal bold() { - FunctionResult result = new FunctionResult(); - WindowsConsoleFunctions.bold(result); - if (result.isFailed()) { - throw new NativeException(String.format("Could not switch console to bold mode for %s: %s", this, result.getMessage())); - } - return this; - } - - @Override - public Terminal foreground(Color color) { - FunctionResult result = new FunctionResult(); - WindowsConsoleFunctions.foreground(color.ordinal(), result); - if (result.isFailed()) { - throw new NativeException(String.format("Could not change console foreground color for %s: %s", this, result.getMessage())); - } - return this; - } - - @Override - public Terminal normal() { - FunctionResult result = new FunctionResult(); - WindowsConsoleFunctions.normal(result); - if (result.isFailed()) { - throw new NativeException(String.format("Could not switch console to normal mode for %s: %s", this, result.getMessage())); - } - return this; - } - - @Override - public Terminal reset() { - FunctionResult result = new FunctionResult(); - WindowsConsoleFunctions.reset(result); - if (result.isFailed()) { - throw new NativeException(String.format("Could not reset console for %s: %s", this, result.getMessage())); - } - return this; - } - - @Override - public Terminal cursorDown(int count) throws NativeException { - throw new UnsupportedOperationException(); - } - - @Override - public Terminal cursorUp(int count) throws NativeException { - throw new UnsupportedOperationException(); - } - - @Override - public Terminal cursorLeft(int count) throws NativeException { - throw new UnsupportedOperationException(); - } - - @Override - public Terminal cursorRight(int count) throws NativeException { - throw new UnsupportedOperationException(); - } - - @Override - public Terminal cursorStartOfLine() throws NativeException { - throw new UnsupportedOperationException(); - } - - @Override - public Terminal clearToEndOfLine() throws NativeException { - throw new UnsupportedOperationException(); - } -} +package net.rubygrapefruit.platform.internal; + +import net.rubygrapefruit.platform.NativeException; +import net.rubygrapefruit.platform.Terminal; +import net.rubygrapefruit.platform.TerminalAccess; +import net.rubygrapefruit.platform.TerminalSize; +import net.rubygrapefruit.platform.internal.jni.TerminfoFunctions; +import net.rubygrapefruit.platform.internal.jni.WindowsConsoleFunctions; + +public class WindowsTerminal extends AbstractTerminal { + private final TerminalAccess.Output output; + + public WindowsTerminal(TerminalAccess.Output output) { + this.output = output; + } + + @Override + public String toString() { + return output.toString().toLowerCase(); + } + + @Override + protected void doInit() { + FunctionResult result = new FunctionResult(); + WindowsConsoleFunctions.initConsole(output.ordinal(), result); + if (result.isFailed()) { + throw new NativeException(String.format("Could not open console for %s: %s", this, result.getMessage())); + } + } + + @Override + public TerminalSize getTerminalSize() { + FunctionResult result = new FunctionResult(); + MutableTerminalSize size = new MutableTerminalSize(); + WindowsConsoleFunctions.getConsoleSize(output.ordinal(), size, result); + if (result.isFailed()) { + throw new NativeException(String.format("Could not determine console size for %s: %s", this, result.getMessage())); + } + return size; + } + + @Override + public Terminal bold() { + FunctionResult result = new FunctionResult(); + WindowsConsoleFunctions.bold(result); + if (result.isFailed()) { + throw new NativeException(String.format("Could not switch console to bold mode for %s: %s", this, result.getMessage())); + } + return this; + } + + @Override + public Terminal foreground(Color color) { + FunctionResult result = new FunctionResult(); + WindowsConsoleFunctions.foreground(color.ordinal(), result); + if (result.isFailed()) { + throw new NativeException(String.format("Could not change console foreground color for %s: %s", this, result.getMessage())); + } + return this; + } + + @Override + public Terminal normal() { + FunctionResult result = new FunctionResult(); + WindowsConsoleFunctions.normal(result); + if (result.isFailed()) { + throw new NativeException(String.format("Could not switch console to normal mode for %s: %s", this, result.getMessage())); + } + return this; + } + + @Override + public Terminal reset() { + FunctionResult result = new FunctionResult(); + WindowsConsoleFunctions.reset(result); + if (result.isFailed()) { + throw new NativeException(String.format("Could not reset console for %s: %s", this, result.getMessage())); + } + return this; + } + + @Override + public Terminal cursorDown(int count) throws NativeException { + FunctionResult result = new FunctionResult(); + WindowsConsoleFunctions.down(count, result); + if (result.isFailed()) { + throw new NativeException(String.format("Could not move cursor down for %s: %s", this, result.getMessage())); + } + return this; + } + + @Override + public Terminal cursorUp(int count) throws NativeException { + FunctionResult result = new FunctionResult(); + WindowsConsoleFunctions.up(count, result); + if (result.isFailed()) { + throw new NativeException(String.format("Could not move cursor up for %s: %s", this, result.getMessage())); + } + return this; + } + + @Override + public Terminal cursorLeft(int count) throws NativeException { + FunctionResult result = new FunctionResult(); + WindowsConsoleFunctions.left(count, result); + if (result.isFailed()) { + throw new NativeException(String.format("Could not move cursor left for %s: %s", this, result.getMessage())); + } + return this; + } + + @Override + public Terminal cursorRight(int count) throws NativeException { + FunctionResult result = new FunctionResult(); + WindowsConsoleFunctions.right(count, result); + if (result.isFailed()) { + throw new NativeException(String.format("Could not move cursor right for %s: %s", this, result.getMessage())); + } + return this; + } + + @Override + public Terminal cursorStartOfLine() throws NativeException { + FunctionResult result = new FunctionResult(); + WindowsConsoleFunctions.startLine(result); + if (result.isFailed()) { + throw new NativeException(String.format("Could not move cursor to start of line for %s: %s", this, result.getMessage())); + } + return this; + } + + @Override + public Terminal clearToEndOfLine() throws NativeException { + FunctionResult result = new FunctionResult(); + WindowsConsoleFunctions.clearToEndOfLine(result); + if (result.isFailed()) { + throw new NativeException(String.format("Could clear to end of line for %s: %s", this, result.getMessage())); + } + return this; + } +} diff --git a/src/main/java/net/rubygrapefruit/platform/internal/jni/WindowsConsoleFunctions.java b/src/main/java/net/rubygrapefruit/platform/internal/jni/WindowsConsoleFunctions.java index eb0fc12..2ad3f3e 100755 --- a/src/main/java/net/rubygrapefruit/platform/internal/jni/WindowsConsoleFunctions.java +++ b/src/main/java/net/rubygrapefruit/platform/internal/jni/WindowsConsoleFunctions.java @@ -17,4 +17,16 @@ public class WindowsConsoleFunctions { public static native void reset(FunctionResult result); public static native void foreground(int ansiColor, FunctionResult result); + + public static native void left(int count, FunctionResult result); + + public static native void right(int count, FunctionResult result); + + public static native void up(int count, FunctionResult result); + + public static native void down(int count, FunctionResult result); + + public static native void startLine(FunctionResult result); + + public static native void clearToEndOfLine(FunctionResult result); }