Как правильно обработать KeyEvent для клавиши Esc

178
27 апреля 2018, 15:23

Читаем *.properties-файлы. Чтение только один раз. После чтения файла, работать с ним через консоль, пока не нажата клавиша ESC.

Знаю что слегка топорно написано, но пока все что могу...

Пример кода main класса:

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import java.util.Scanner;
public class main {
public static void main(String[] args) {
    boolean bError = true;
    Mykey a = new Mykey();
    boolean enabled = a.keyPressed(); //каким образом тут надо взаимодействие определить
    Properties prop;
    do {
        System.out.println("Enter name file: ");
        Scanner config = new Scanner(System.in);
        String c = config.nextLine();
        final String PATH_TO_PROPERTIES = "src/" + c + ".properties";
        FileInputStream fileInputStream;
        prop = new Properties();
        try {
            fileInputStream = new FileInputStream(PATH_TO_PROPERTIES);
            bError = false;
            prop.load(fileInputStream);
        } catch (IOException e) {
            System.out.println("Ошибка в программе: файл " + PATH_TO_PROPERTIES + " не обнаружено");
            e.printStackTrace();
        }
    } while (bError);
    while (enabled) { //цикл связанный с KeyEvent (пока не true или false - повторять
            System.out.println("Enter key1, key2: ");
            Scanner key1 = new Scanner(System.in);
            Scanner key2 = new Scanner(System.in);
            String k1 = prop.getProperty(key1.nextLine());
            String k2 = prop.getProperty(key2.nextLine());
            if (k1 == null) {
                System.out.println("Первый ключ задан неправильный\n");
            }
            if (k2 == null) {
                System.out.println("Второй ключ задан неправильный\n");
            }
            System.out.println("key1: " + k1 + "\nkey2: " + k2);
        }
   // System.exit(0);
    }
}

Пример кода обработчика клавиши:

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Mykey implements KeyListener {
boolean enabled = false;
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
    if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
    {
        enabled = true;
        //return;
    }
}
@Override
public void keyReleased(KeyEvent e) {
}
}
Answer 1

Как правильно заметил JVic, консольная java-программа не сможет среагировать на нажатие клавиши escape. Но смогла бы среагировать программа на C. Мостик к этой возможности можно прокинуть через JNI. Не думаю, что это подходящее решение данной проблемы, но всё же приведу его в просветительских целях и баловства ради. Первым делом нам нужен сам java-код. Поместим его в ExitOnEscape.java:

public class ExitOnEscape implements Runnable {
    private volatile 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 -h . ExitOnEscape.java

Ключ -h указывает в какой каталог сгенерировать заголовочный файл для нашей будущей библиотеки. В рабочем каталоге должен появиться файл 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

READ ALSO
Уроки по Spring

Уроки по Spring

Посоветуйте хорошую литературу или видеоуроки по Spring Boot для расширенного изучения на русском языкеПодробно объясняющую книгу

195
Как поместить кнопку меню в панель кнопок если нет хардварной кнопки меню?

Как поместить кнопку меню в панель кнопок если нет хардварной кнопки меню?

У меня имеется ToolBar и кнопка меню на нем, но помимо меню он не выполняет никакой ролиКак поместить кнопку меню в строку управляющих кнопок?...

186
AsyncTask когда дисплей выключен

AsyncTask когда дисплей выключен

Я хочу сделать приложение, которое будет работать когда дисплей телефона будет выключенНужно ли использовать asynstask или можно обойтись без...

143