глобальный KeyListener с использованием JNA

У меня есть план создания программы на Java, работающей под Windows, которая может отображать разные «макросы» на разные клавиши, работающие в фоновом режиме. Проблема в том, как заставить Java слушать нажатия клавиш, когда приложение не сфокусировано.

Я нашел много мнений, что это невозможно. Но я также нашел это, написанное Стефано здесь, на SO . Это решение для меня недостаточно хорошее, по крайней мере, нет одной важной информации. Функция MsgWaitForMultipleObjects() возвращает одно значение, если клавиша не нажата... это нормально. После нажатия клавиши она возвращает другое значение... это было бы нормально, если бы функция не возвращала одно и то же значение, что бы ни происходило после события нажатия клавиши.

Вот поток тестирования этого:

public class KeyListener extends Thread {

    /**
     * Constructor
     */
    public KeyListener() {
        super();
    }

    /**
     * RUN method
     */
    @Override
    public void run() {
        int x;
        User32 user32 = User32.INSTANCE;

        boolean res = user32.RegisterHotKey(Pointer.NULL, 1, User32.MOD_ALT | User32.MOD_CONTROL, WinKeys.VK_X);
        if (!res) {
            System.out.println("Couldn't register hotkey");
        }
        System.out.println("Starting and waiting");

        while (!isInterrupted()) {
            x = user32.MsgWaitForMultipleObjects(0, Pointer.NULL, true, 1000, User32.QS_HOTKEY);

            if (x == 0) {
                System.out.println("Key pressed");
            }
        }
    }
}

Эта маленькая программа (использующая этот поток) реагирует на нажатие ALT+X. После этого на консоль выводится текст Key pressed до остановки программы (функция все время возвращает 0). Возможным решением, на мой взгляд, является некоторый «сброс» функции, поэтому она будет ждать повторного нажатия клавиши и снова возвращать 258 (258 == ожидание). Но я понятия не имею, как это сделать.

Если кто-то знает, как это сделать, или есть другое решение, буду признателен за любую информацию.


person Erveron    schedule 30.05.2011    source источник


Ответы (1)


Я не знаю о решении JNA, но есть хорошо зарекомендовавшая себя глобальная библиотека горячих клавиш под названием JIntelliType

РЕДАКТИРОВАТЬ: правильный ответ на эту проблему заключался в использовании GetMessage вместо MsgWaitForMultipleObjects. Я написал простой пример с использованием BridJ, и он отлично работает:

       if (!RegisterHotKey(null, id, MOD_ALT | MOD_NOREPEAT, 0x42)) {
            System.out.println("Error");
            return;
        }

        Pointer<MSG> msgPointer = Pointer.allocate(MSG.class);

        try {
            while (GetMessage(msgPointer, null, 0, 0) != 0) {
                MSG msg = msgPointer.get();
                if (msg.message() == WM_HOTKEY && msg.wParam() == id) {
                    System.out.println("YEAH");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            UnregisterHotKey(null, id);
        }
person Denis Tulskiy    schedule 30.05.2011
comment
После первых тестов JIntelliType я должен сказать, что доволен. Работа с этой библиотекой выглядит намного проще и работает нормально. Спасибо. - person Erveron; 30.05.2011
comment
@James: если вы все еще заинтересованы в решении JNA, посмотрите мое редактирование: использование GetMessage должно заставить ваш код работать нормально. - person Denis Tulskiy; 07.06.2011
comment
Спасибо, но теперь я полностью доволен JIntellyType. - person Erveron; 08.06.2011
comment
Просто предупреждение для будущих читателей. JIntellitype НЕ является кроссплатформенным, что означает, что он будет работать только в среде Windows. JNA, с другой стороны, в этом аспекте находится на более высоком уровне, поэтому вам остается принять вышеупомянутое решение о совместимости ОС. - person Roger; 28.05.2017