简介
java.awt包的EventQueue
类提供了对EventQueue的发送(dispatch)机制,它会异步地从事件队列中拉取事件,调用dispatchEvent(AWTEvent)
方法。虽然是异步去发送事件,但是它保证了事件发送的有序性。
IdeEventQueue
是IntelliJ提供的事件处理类,它集成了awt的EventQueue,重写了dispatchEvent方法。它提供了EventDispatcher让我们可以对事件进行拦截处理,可以通过它提供的扩展点,或者编程式的方式来添加自己的EventDispatcher。
EventDispatcher
EventDispatcher是IntelliJ封装的函数式接口,实现它来接收AWTEvent事件,进行自定义逻辑处理。实现dispatch方法的时候,我们需要增加自己的判断逻辑,如果这个事件被我们处理了,又不想被后续其它事件处理器处理,可以返回true,否则应当返回false。
@FunctionalInterface
public interface EventDispatcher {
// 如果不希望被后续其它事件处理器处理,则返回true
boolean dispatch(@NotNull AWTEvent e);
}
注册EventDispatcher
可以通过扩展点,或者编程式方式来注册自己的EventDispatcher。使用编程式方式时,需要注意注册时机和销毁机制(指定父Disposable),避免重复注册。
- 扩展点注册EventDispatcher(扩展点定义在IdeEventQueue类)
<!-- plugin.xml -->
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<ideEventQueueDispatcher implementation="com.demo.MyEventDispatcher "/>
</extensions>
</idea-plugin>
- 编程式注册EventDispatcher
IdeEventQueue eventQueue = IdeEventQueue.getInstance();
eventQueue.addDispatcher(e -> {
if (xxx) {
// If the event meets the requirement of your condition, process it and return true to prevent it from being further processed by other EventDispatchers
... // your process business
return true;
}
return false;
}, parentDisposable);
应用示例
如果你想拦截某个指定Editor的Enter键的处理逻辑,可以通过以下代码实现。
Key<Boolean> MY_INPUT_INDICATOR = Key.create("myInputIndicator");
// create TextEditorField.
EditorTextField input = new EditorTextField();
input.addSettingsProvider(editorEx -> {
Disposable inputDisposable = Disposer.newDisposable("inputListener");
EditorUtil.disposeWithEditor(editorEx, inputDisposable);
MY_INPUT_INDICATOR.set(editorEx, true);
IdeEventQueue eventQueue = IdeEventQueue.getInstance();
eventQueue.addDispatcher(e -> {
if (e instanceof KeyEvent keyEvent) {
// 如果想拦截ctrl+Enter,需要判断keyEvent.getModifiersEx() == KeyEvent.CTRL_DOWN_MASK
if (keyEvent.getKeyCode() == KeyEvent.VK_ENTER && keyEvent.getID() == KeyEvent.KEY_PRESSED) {
... // do your business
return true;
}
return false;
}, inputDisposable);
});
以上代码仅仅是用于展示应用场景,如果你只实现想改变某个Editor的Enter键行为,不需要通过这种方式。由于EnterAction集成自EditorAction,而该类在实现AnAction的actionPerformed方法时,使用的是getHandler()方法去处理,并提供了setupHandler方法,你可以直接修改它的Handler,并在特定的时机使用自己的逻辑。
// 也可以通过工具方法:EditorActionManager.getInstance().setActionHandler(actionId, handler)
EditorAction action = (EditorAction)ActionManager.getInstance().getAction("EditorEnter");
action.setupHandler(handler);