English 中文(简体)
在关键压力发生之前,利用来自贾瓦的Ncurs,改造窗户不会触发点。
原标题:Using ncurses from Java via JNI, resizing window does not trigger getch until key pressed
  • 时间:2023-12-31 23:02:46
  •  标签:
  • java
  • ncurses

My goal is create text-based applications with JVM languages,
and now I am trying to use ncurses with JNI.

When I use ncurses directly from C, resizing the terminal will trigger getch() and return 410 (KEY_RESIZE).
But I use ncurses via JNI, getch() won t do anything until pressing any other keys.

  • Is it a limitation of JVM?
  • Any workaround for this situation?
  • or shouldn t I use ncurses via JNI in the first place?

Here is the full reproducible code:

public class Main {
    public static native void init();
    public static native int  getch();
    public static native void printw(String string);
    public static native void endwin();

    public static void main(String[] args) {
        System.loadLibrary("jcurses");
        init();
        for (int key; (key = getch()) !=  q ;)
            printw("%d
".formatted(key));
        endwin();
    }
}
#include <ncurses.h>
#include "Main.h"

JNIEXPORT void JNICALL Java_Main_init(JNIEnv *env, jclass clazz) {
    initscr();
    keypad(stdscr, TRUE);
    noecho();
}

JNIEXPORT jint JNICALL Java_Main_getch(JNIEnv *env, jclass clazz) {
    return (long) getch();
}

JNIEXPORT void JNICALL Java_Main_printw(JNIEnv *env, jclass clazz, jstring javaString) {
    const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);
    printw("%s", nativeString);
    (*env)->ReleaseStringUTFChars(env, javaString, nativeString);
}

JNIEXPORT void JNICALL Java_Main_endwin(JNIEnv *env, jclass clazz) {
    endwin();
}
all:
    javac -h . Main.java
    gcc -I"$$JAVA_HOME/include" -I"$$JAVA_HOME/include/linux" jcurses.c -shared -o libjcurses.so -lncurses
run:
    java -Djava.library.path=. Main

For comparison, here is the pure C code to do the same thing.
Resizing the window will shows up 410 immediately but cannot do the same with JNI.

#include <ncurses.h>

int main() {
    initscr();
    keypad(stdscr, TRUE);
    noecho();
    for (int key; (key = getch()) !=  q ;)
        printw("%d
", key);
    endwin();
    return 0;
}

在以下装置上测试:

  • x86 ubuntu22.04, ssh from Windows 7 git bash
  • arm64 ubuntu22.04, native gnome terminal
问题回答

I found that the issue is that the JVM "consumes" the SIGWINCH signal,
so that ncurses cannot detect the changes of the size of the window.

Therefore a possible solution is using the sun.misc.Signal class to catch the signal and do the rendering stuff,
but this is an absolutely bad idea due to its deprecation.

// WARNING! this package is deprecated!
import sun.misc.Signal;

Signal.handle(new Signal("WINCH"), signal -> {
    // re-render our contents
});

(这一答案不应接受)





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签