Это невозможно без использования JNI. Если использование нативных вызовов для вас приемлимо, то первым делом нам нужен сам java-код. Поместим его в
ExitOnEscape.java:
public class ExitOnEscape implements Runnable {
private boolean doTheStuff = true; // Флаг активности рабочего потока
public native boolean readConsole();
public void run() { // Рабочий поток
while (doTheStuff) { // Работать пока установлен флаг
System.out.println("Doing something..."); // Основная логика программы
try {
Thread.sleep(500);
}
catch (InterruptedException exc) {}
}
}
public void doSomething() {
new Thread(this).start(); // Запускаем рабочий поток
while(true) { // В главном потоке читаем консоль нативной функцией в бесконечном цикле
if(readConsole()) { // Если нажат escape
doTheStuff = false; // Сбрасываем флаг активности
break; // И выходим из цикла
}
}
}
public static void main(String[] args) {
System.loadLibrary("ExitOnEscape");
ExitOnEscape exitOnEscape = new ExitOnEscape();
exitOnEscape.doSomething();
}
}
Как видно, в коде есть только две строки отличающиеся от того, с чем приходится сталкиваться ежедневно. Это объявление нативного метода
public native boolean readConsole();
и загрузка библиотеки
System.loadLibrary("ExitOnEscape");
Компилируем его:
javac ExitOnEscape.java
Теперь необходимо из полученного класса сгенерировать заголовочный файл для нашей будущей библиотеки. В этом нам поможет утилита
javah входящая в состав JDK:
javah ExitOnEscape
В рабочем каталоге должен появиться файл ExitOnEscape.h со следующим содержимым:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class ExitOnEscape */
#ifndef _Included_ExitOnEscape
#define _Included_ExitOnEscape
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: ExitOnEscape
* Method: readConsole
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_ExitOnEscape_readConsole
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
В нём интересно только объявление функции, имеющее вид
Java_<имя класса>_<имя метода>. Первый параметр функции
JNIEnv - это указатель на таблицу функций механизма JNI, служащих для обеспечения взаимодействия между java- и c-кодом. Второй параметр имеет тип
jobject и принимает экземпляр класса
ExitOnEscape. Возвращает функция
jboolean соответствующий типу
boolean в java.
JNIEXPORT и
JNICALL - это зависимые от компилятора макро-определения для экспортирования функций, особого внимания они не заслуживают.
А теперь самая интересная часть - реализация этой функции. Опишем её в файле
ExitOnEscape.c:
#include <stdio.h>
#include <conio.h>
#include "ExitOnEscape.h"
JNIEXPORT jboolean JNICALL Java_ExitOnEscape_readConsole(JNIEnv* env, jobject obj) {
char c = getch(); // Считываем введённый символ
if (c == 27) // Если это escape
return JNI_TRUE; // Возвращаем true
else
return JNI_FALSE; // Иначе false
}
Для компиляции в Windows я использовал
MinGW-w64:
gcc -Wl,--add-stdcall-alias ^
-I"%JAVA_HOME%\include" ^
-I"%JAVA_HOME%\include\win32" ^
-shared -o ExitOnEscape.dll ExitOnEscape.c
В рабочем каталоге должен появиться файл
ExitOnEscape.dll. После этого можно запускать java-программу.
java ExitOnEscape