是否可以使用javafx方法实现jnativehook .setOnKeyPressed()?
例如,这是在应用程序聚焦时它如何监听按键操作:
ListView<String> list = new ListView<String>();
list.setOnKeyPressed(new EventHandler<KeyEvent>() {
@override
public void handle(KeyEvent event){
if (event.getCode() == KeyCode.U) {
//Go Up list..
}
event.consume();
}
});
但是我希望它能够在关注全局按键时关注另一个应用程序,所以理想情况下我希望它看起来像这样:
list.setOnKeyPressed(new EventHandler<NativeKeyEvent>() {
@override
public void handle(NativeKeyEvent event){
if (event.getKeyCode() == NativeKeyEvent.VC_U) {
//Go Up list..
}
event.consume();
}
});
但是第一行标记了错误:
1. The method setOnKeyPressed(EventHandler <? super KeyEvent>) in the type Node is not applicable for the arguments (new EventHandler<NativeKeyEvent>(){})
2. Bound mismatch: The type NativeKeyEvent is not a valid substitute for the bounded parameter <T extends Event> of the type EventHandler<T>
我确定我需要重载方法以考虑这些参数,但是我不知道如何处理它以及如何处理第二个错误。
对于jnativehook,方法.consume()也是unsupported。
或者是否有另一种方法可以在不使用这些方法的情况下在javafx中上下查看listview并与jnativehook兼容?
答案 0 :(得分:0)
首先,让我们谈谈事件传递和UI线程,因为您必须了解在线程和内存之间共享的情况下进行的上下文切换。
几乎所有其他应用程序设计的Java都使用单个线程来处理所有UI事件。其原因是well documented遍布互联网。因此,如果您使用的是AWT / Swing或Java FX,您的事件将分别在AWT / Swing或Java FX平台线程上发送,并且没有其他线程应该进行交互或期望这些事件。
JNativeHook使用自己的调度线程,完全独立于Java的UI。这主要是出于兼容性原因而完成的,因为我不想在实现用户上强制使用特定的UI API。因此,如果您想使用AWT / Swing,Java FX或其他东西,则必须在负责UI的线程上下文中调度本机事件。库中内置了一个Spring调度程序,我发布了here的Java FX调度程序,通过默认的调度方法,通过向GlobalScreen注册调度程序,可以进行非常简单的上下文切换。
你可能会问自己,&#34;如果我想在调度之前修改事件该怎么办?&#34;这也应该是可能的,但需要更多努力来注册调度类。您应该能够扩展GlobalScreen类及其匿名内部类,以完成您需要的任何其他内容。例如,如果要调度Swing InputEvents而不是NativeInputEvents,则可以执行以下操作:
public class CustomScreen extends GlobalScreen {
// Static blocks are run when the class is loaded.
static {
// Add adaptors to the listener to convert the events.
addNativeKeyListener(new KeyAdapter());
addNativeMouseListener(new MouseAdapter());
setEventDispatcher(new SwingDispatchService());
}
private static class KeyAdapter extends SwingKeyAdapter {
public void keyTyped(KeyEvent keyEvent) {
KeyListener[] listeners = eventListeners.getListeners(KeyListener.class);
for (int i = 0; i < listeners.length; i++) {
listeners[i].keyTyped(keyEvent);
}
}
public void keyPressed(KeyEvent keyEvent) {
KeyListener[] listeners = eventListeners.getListeners(KeyListener.class);
for (int i = 0; i < listeners.length; i++) {
listeners[i].keyPressed(keyEvent);
}
}
public void keyReleased(KeyEvent keyEvent) {
KeyListener[] listeners = eventListeners.getListeners(KeyListener.class);
for (int i = 0; i < listeners.length; i++) {
listeners[i].keyReleased(keyEvent);
}
}
}
private static class MouseAdapter extends SwingMouseAdapter {
public void mouseClicked(MouseEvent mouseEvent) {
MouseListener[] listeners = eventListeners.getListeners(MouseListener.class);
for (int i = 0; i < listeners.length; i++) {
listeners[i].mouseClicked(mouseEvent);
}
}
public void mousePressed(MouseEvent mouseEvent) {
MouseListener[] listeners = eventListeners.getListeners(MouseListener.class);
for (int i = 0; i < listeners.length; i++) {
listeners[i].mousePressed(mouseEvent);
}
}
public void mouseReleased(MouseEvent mouseEvent) {
MouseListener[] listeners = eventListeners.getListeners(MouseListener.class);
for (int i = 0; i < listeners.length; i++) {
listeners[i].mouseReleased(mouseEvent);
}
}
public void mouseEntered(MouseEvent mouseEvent) {
MouseListener[] listeners = eventListeners.getListeners(MouseListener.class);
for (int i = 0; i < listeners.length; i++) {
listeners[i].mouseEntered(mouseEvent);
}
}
public void mouseExited(MouseEvent mouseEvent) {
MouseListener[] listeners = eventListeners.getListeners(MouseListener.class);
for (int i = 0; i < listeners.length; i++) {
listeners[i].mouseExited(mouseEvent);
}
}
}
public static void addSwingKeyListener(KeyListener listener) {
if (listener != null) {
eventListeners.add(KeyListener.class, listener);
}
}
public static void removeKeyListener(KeyListener listener) {
if (listener != null) {
eventListeners.remove(KeyListener.class, listener);
}
}
public static void addMouseListener(MouseListener listener) {
if (listener != null) {
eventListeners.add(MouseListener.class, listener);
}
}
public static void removeMouseListener(MouseListener listener) {
if (listener != null) {
eventListeners.remove(MouseListener.class, listener);
}
}
}
所有这一切都是使用父全局屏幕注册库中包含的几个适配器类,并调度到适配器中的swing侦听器。还有其他方法可以更强大,比如扩展GlobalScreen.NativeHookThread匿名内部类,但这会占用更多代码。
处理Java FX与swing非常相似,您可以在我之前的帖子中找到一个示例调度程序:https://stackoverflow.com/a/45423466/773849
就.consume()
而言,是的,这是不受支持的,但在某些平台上仍然可行。如果您使用的是Windows或OS X,则可以使用wiki中概述的一些聪明代码来停止事件传播。这将要求您覆盖前面提到的NativeHookThread内部类,并且您必须快速处理事件,因为在这种情况下NativeHookThread实际上不是一个线程并且将阻止操作系统。这种方法在Linux上不可用,因为linux目前无法执行此功能。