IntelliJ系列IDE模态对话框中兼容IME的键盘按键码监听与文本插入实现问题咨询
IntelliJ系列IDE模态对话框中兼容IME的键盘按键码监听与文本插入实现问题咨询
大家好,我现在在开发IntelliJ系列IDE的插件,需求是模态对话框打开时监听键盘输入,按下特定键后插入指定字符串到代码编辑标签页,同时关闭对话框,而且必须兼容所有输入语言(包括非拉丁字符语言)和激活的IME输入法——所以核心是要基于按键码而非输入字符来判断。
我已经写了一段代码,非IME状态下(不管是拉丁还是非拉丁语言)都能正常工作,但一旦激活IME输入法,键盘事件就无法被正确捕获处理了,想请教下怎么修改才能兼容IME模式?
现有代码情况
我的SimpleDialog类核心代码如下:
package com.nnn import com.intellij.openapi.ui.DialogWrapper import com.intellij.openapi.editor.Document import com.intellij.openapi.project.Project import com.intellij.openapi.command.WriteCommandAction import com.intellij.ide.ui.LafManager import com.intellij.openapi.fileEditor.FileEditorManager import java.awt.event.KeyEvent import java.awt.Toolkit import java.awt.KeyboardFocusManager import java.awt.KeyEventDispatcher import java.awt.event.InputMethodEvent import java.awt.event.InputMethodListener import java.awt.im.InputMethodRequests import javax.swing.JComponent import javax.swing.JLabel import javax.swing.JPanel import javax.swing.Action import javax.swing.ImageIcon import java.awt.Rectangle import java.awt.font.TextHitInfo import java.text.AttributedCharacterIterator import java.text.AttributedString class SimpleDialog(private val project: Project) : DialogWrapper(true), InputMethodRequests { private var textInserted = false private var keyProcessed = false companion object { const val DEFINABLE_TERM = "#[+DefinableTerm--YDID \$END\$]" const val IMPORTANT_ENTITY = "#[+ImportantEntity--YDID \$END\$]" const val KEYWORD = "#[+Keyword--YDID \$END\$]" const val KEYPHRASE = "#[+Keyphrase--YDID \$END\$]" const val SECONDARY_ENTITY = "#[+SecondaryEntity--YDID \$END\$]" const val TERM = "#[+Term--YDID \$END\$]" const val KEYWORD_CONTRAST = "#[+Keyword__Contrast--YDID \$END\$]" const val IMPORTANT_ENTITY_CODE = "#[+ImportantEntity__Code--YDID \$END\$]" const val SECONDARY_ENTITY_CODE = "#[+SecondaryEntity__Code--YDID \$END\$]" const val TERM_CONTRAST = "#[+Term__Contrast--YDID \$END\$]" } private val keyEventDispatcher = KeyEventDispatcher { keyEvent -> println("KeyEventDispatcher: ${ keyEvent.keyCode }, character: ${ keyEvent.keyChar }") println(keyEvent.id) println(keyEvent.id == KeyEvent.KEY_TYPED) println(keyEvent.id == KeyEvent.KEY_PRESSED) if (keyEvent.id == KeyEvent.KEY_TYPED || keyEvent.id == KeyEvent.KEY_PRESSED) { println("Checkpoint 1") onKeyPressed(keyEvent) } println("Checkpoint 2") println("===============================") false } private fun onKeyPressed(keyEvent: KeyEvent) { println("onKeyPressed: ${ keyEvent.keyCode }, character: ${ keyEvent.keyChar }") if (textInserted) { return } if (keyEvent.isControlDown) { handleControlKeyCombinations(keyEvent) } else if (keyEvent.id == KeyEvent.KEY_TYPED) { handleCharacterInput(keyEvent.keyChar) } else if (keyEvent.id == KeyEvent.KEY_PRESSED) { handleKeyPress(keyEvent.keyCode) } } override fun show() { println("Dialog shown") KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(keyEventDispatcher) super.show() } // 省略其他实现方法(如handleControlKeyCombinations、handleCharacterInput等) }
问题现象
- 非IME正常情况:比如按下
t键,控制台输出如下,能正常触发onKeyPressed并完成文本插入:
Dialog shown KeyEventDispatcher: 84, character: t 401 false true Checkpoint 1 onKeyPressed: 84, character: t handleKeyPress: 84 Inserting text: #[+Term--YDID $END$] Dialog disposed Checkpoint 2 ===============================
- IME激活异常情况:同样按下
t键,控制台输出显示keyEvent.id既不是KEY_TYPED也不是KEY_PRESSED,导致onKeyPressed完全没被调用:
Dialog shown KeyEventDispatcher: 84, character: t 402 false false Checkpoint 2 ===============================
我的初步分析
从输出看,IME激活时捕获到的keyEvent.id是402,对应KeyEvent.KEY_RELEASED,而我的代码只处理了KEY_TYPED和KEY_PRESSED事件。但直接把KEY_RELEASED加入判断的话,会不会和正常的事件流程冲突?或者有没有更适配IME的键盘事件监听方案?
有没有大佬能指点下怎么修改代码,才能在IME激活时也能正确捕获按键码并完成后续的文本插入逻辑?
内容来源于stack exchange
相关产品推荐
相关产品推荐

