Я использую следующий код для прослушивания глобальных ключевых событий:Ключевой прослушиватель написан на Java JNA. Не удается остановить нить
Win32HookManager.java
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HMODULE;
import com.sun.jna.platform.win32.WinDef.LRESULT;
import com.sun.jna.platform.win32.WinDef.WPARAM;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.platform.win32.WinUser.HHOOK;
import com.sun.jna.platform.win32.WinUser.KBDLLHOOKSTRUCT;
import com.sun.jna.platform.win32.WinUser.LowLevelKeyboardProc;
import com.sun.jna.platform.win32.WinUser.MSG;
import java.awt.event.KeyEvent;
public class Win32HookManager {
private static HHOOK keyboardHook;
public static boolean installKeyboardHook(final NativeKeyboardListener listener) {
final User32 lib = User32.INSTANCE;
final HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
final LowLevelKeyboardProc keyboardHookProc = new LowLevelKeyboardProc() {
@Override
public LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT info) {
NativeKeyboardEvent ev = null;
long ti = System.currentTimeMillis();
boolean nh = true;
if (nCode >= 0) {
switch (wParam.intValue()) {
case WinUser.WM_KEYDOWN:
case WinUser.WM_SYSKEYDOWN:
ev = new NativeKeyboardEvent(KeyEvent.KEY_PRESSED, ti, 0, info.vkCode);
nh = listener.keyPressed(ev);
break;
case WinUser.WM_KEYUP:
case WinUser.WM_SYSKEYUP:
ev = new NativeKeyboardEvent(KeyEvent.KEY_RELEASED, ti, 0, info.vkCode);
nh = listener.keyReleased(ev);
break;
}
}
if(nh) {
return lib.CallNextHookEx(keyboardHook, nCode, wParam, info.getPointer());
}
return new LRESULT(1);
}
};
new Thread() {
@Override
public void run() {
keyboardHook = lib.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL, keyboardHookProc, hMod, 0);
msgLoop();
lib.UnhookWindowsHookEx(keyboardHook);
}
}.start();
return keyboardHook != null;
}
public static boolean uninstallKeyboardHook() {
if(keyboardHook != null) {
return User32.INSTANCE.UnhookWindowsHookEx(keyboardHook);
}
return false;
}
private static void msgLoop()
{
final User32 lib = User32.INSTANCE;
int result;
MSG msg = new MSG();
while ((result = lib.GetMessage(msg, null, 0, 0)) != 0) {
if (result == -1) {
System.err.println("error in get message");
break;
}
else {
System.err.println("got message");
lib.TranslateMessage(msg);
lib.DispatchMessage(msg);
}
}
}
}
NativeKeyboardListener
public interface NativeKeyboardListener {
public boolean keyPressed (NativeKeyboardEvent e);
public boolean keyReleased(NativeKeyboardEvent e);
}
NativeKeyboardEvent
public class NativeKeyboardEvent {
private int id;
private int keyCode;
public NativeKeyboardEvent(int id, long when, int modifiers, int keyCode) {
this.id = id;
this.keyCode = keyCode;
}
public int getId() {
return id;
}
public int getKeyCode() {
return keyCode;
}
}
К сожалению, он не работает, как я то есть он обнаруживает, когда клавиша нажата/отпущена, но она не может завершить поток, запущенный методом installKeyboardHook() из-за GetMessage() в методе msgLoop. Да, я могу перестать слушать ключевые события, но я не могу остановить поток. Однако, похоже, что в этом коде требуется GetMessage(). Вы видите какие-либо способы решения этой проблемы?
Спасибо!
Это не сработает. Без GetMessage метод не уведомляет о ключевых событиях. И это блокировка потоков. – peter
@ user389658: Вы неправильно поняли мой ответ. Используйте поле флага для завершения цикла, когда хотите. 'if (shouldQuit) break;' – SLaks
@ user389658 Вы можете установить логическое значение 'true', а затем прервать поток ... – Romain