javarustinteropncursesjava-ffm

Non-Blocking ncurses getch() in Java FFM


I have a Rust function named init that calls the following ncurses functions (in the following order): initscr(), cbreak(), keypad(stdscr, TRUE), getch() followed by endwin().

The init function looks something like this:

#[unsafe(no_mangle)]
pub extern "C" fn init() {
    unsafe {
        _init();
    }
}

Where _init is an ffi function declared as so:

#[link(...)]
unsafe extern "C" {
    pub fn _init();
}

This function is implemented in C as such:

void _init() {
    initscr();
    cbreak();
    keypad(stdscr, TRUE);
    getch();
    endwin();
}

This rust library is compiled as a dynamic C library (.so)

My Java code looks like this:

public class Init {
  public void init() throws RuntimeException {
    Linker linker = Linker.nativeLinker();

    try(Arena arena = Arena.ofConfined()) {
      SymbolLookup lookup = SymbolLookup.libraryLookup(Path.of(...), arena);

      Optional<MemorySegment> optionalInitAddress = lookup.find("init");

      if(optionalInitAddress.isPresent()) {
        MemorySegment initAddr = optionalInitAddress.get();
        FunctionDescriptor initDesc = FunctionDescriptor.ofVoid();
        MethodHandle init = linker.downcallHandle(initAddr, initDesc);

        init.invoke();
      } else {
        throw new NoSuchElementException();
      }
    } catch(Throwable e) {
      throw new RuntimeException(e);
    }
  }
}

When I call this function from Java using the FFM API, my terminal just flickers and the program ends without waiting for getch().

On further inspection, the getch and cbreak functions are giving an error code of -1 (only when executed from Java), and the other functions are giving an error code of 0.

I'm not sure why Java is exhibiting this weird behaviour.

I am compiling and running this Java program via gradle.

Some insight on this would be helpful.


Solution

  • This issue was happening because the application was run using gradle with the run task defined by the application plugin.

    The issue was fixed when I ran the program (executable jar) directly via the terminal, without using gradle.