From 30c1297c026e5bad2f418466db8d6027d135f687 Mon Sep 17 00:00:00 2001 From: Xinhe Wang Date: Thu, 25 Sep 2025 13:44:26 +0100 Subject: [PATCH 1/3] Click target center instead of invoking accessible action if hint is selected --- .../vim/extension/hints/ToggleHintsAction.kt | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/maddyhome/idea/vim/extension/hints/ToggleHintsAction.kt b/src/main/java/com/maddyhome/idea/vim/extension/hints/ToggleHintsAction.kt index 597fed49f7..ad5ba810a9 100644 --- a/src/main/java/com/maddyhome/idea/vim/extension/hints/ToggleHintsAction.kt +++ b/src/main/java/com/maddyhome/idea/vim/extension/hints/ToggleHintsAction.kt @@ -11,17 +11,22 @@ package com.maddyhome.idea.vim.extension.hints import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.PlatformDataKeys +import com.intellij.openapi.editor.impl.EditorComponentImpl import com.intellij.openapi.project.DumbAwareToggleAction import com.intellij.openapi.ui.popup.JBPopupFactory import com.intellij.openapi.ui.popup.JBPopupListener import com.intellij.openapi.ui.popup.LightweightWindowEvent import com.intellij.openapi.wm.impl.IdeGlassPaneImpl import com.intellij.ui.JBColor +import com.intellij.ui.treeStructure.Tree import com.intellij.util.Alarm import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.extension.ShortcutDispatcher import com.maddyhome.idea.vim.newapi.globalIjOptions import java.awt.Color +import java.awt.Point +import java.awt.Robot +import java.awt.event.InputEvent import javax.swing.JComponent import javax.swing.JLabel import javax.swing.JPanel @@ -78,12 +83,19 @@ class ToggleHintsAction : DumbAwareToggleAction() { ShortcutDispatcher("hints", targets.associateBy { it.hint.lowercase() }, { target -> popup.closeOk(null) alarm.cancelAllRequests() - target.component.accessibleContext?.apply { - if (accessibleAction?.doAccessibleAction(0) == null && !accessibleComponent.isFocusTraversable) return@apply - accessibleComponent.requestFocus() - highlight.setTarget(target) - alarm.addRequest({ highlight.setTarget(null) }, highlightDuration) + if (target.component is Tree || target.component is EditorComponentImpl) { + target.component.requestFocusInWindow() + } else { + // Click the center of the target component + val robot = Robot() + val location = Point(target.bounds.location) + SwingUtilities.convertPointToScreen(location, glassPane) + robot.mouseMove(location.x + target.bounds.width / 2, location.y + target.bounds.height / 2) + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK) + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK) } + highlight.setTarget(target) + alarm.addRequest({ highlight.setTarget(null) }, highlightDuration) }, { popup.cancel() injector.messages.indicateError() From fd724758a0f10f2ed96cfda915ae53f6dc0c26a4 Mon Sep 17 00:00:00 2001 From: Xinhe Wang Date: Thu, 25 Sep 2025 14:07:56 +0100 Subject: [PATCH 2/3] Specify hint action in HintGenerator instead of actionPerformed --- .../idea/vim/extension/hints/HintGenerator.kt | 8 +++++++- .../idea/vim/extension/hints/HintTarget.kt | 19 ++++++++++++++++++ .../vim/extension/hints/ToggleHintsAction.kt | 20 +++---------------- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/maddyhome/idea/vim/extension/hints/HintGenerator.kt b/src/main/java/com/maddyhome/idea/vim/extension/hints/HintGenerator.kt index 2de6dbccb5..5e243b1092 100644 --- a/src/main/java/com/maddyhome/idea/vim/extension/hints/HintGenerator.kt +++ b/src/main/java/com/maddyhome/idea/vim/extension/hints/HintGenerator.kt @@ -8,6 +8,7 @@ package com.maddyhome.idea.vim.extension.hints +import com.intellij.openapi.editor.impl.EditorComponentImpl import com.intellij.ui.treeStructure.Tree import java.awt.Component import java.awt.Point @@ -77,7 +78,12 @@ private fun collectTargets( targets[component].let { // For some reason, the same component may appear multiple times in the accessible tree. if (it == null || it.depth > depth) { - targets[component] = HintTarget(component, location, size, depth) + targets[component] = HintTarget(component, location, size, depth).apply { + action = when (component) { + is Tree, is EditorComponentImpl -> ({ component.requestFocusInWindow() }) + else -> HintTarget::clickCenter + } + } } } } diff --git a/src/main/java/com/maddyhome/idea/vim/extension/hints/HintTarget.kt b/src/main/java/com/maddyhome/idea/vim/extension/hints/HintTarget.kt index dc851d5dcf..ef32f86de3 100644 --- a/src/main/java/com/maddyhome/idea/vim/extension/hints/HintTarget.kt +++ b/src/main/java/com/maddyhome/idea/vim/extension/hints/HintTarget.kt @@ -11,10 +11,29 @@ package com.maddyhome.idea.vim.extension.hints import java.awt.Dimension import java.awt.Point import java.awt.Rectangle +import java.awt.Robot +import java.awt.event.InputEvent import javax.accessibility.Accessible internal data class HintTarget(val component: Accessible, val location: Point, val size: Dimension, val depth: Int) { var hint: String = "" val bounds: Rectangle get() = Rectangle(location, size) + + /** + * The action to execute when the hint is selected. + * + * @return `true` if the action succeeded, `false` otherwise + */ + var action: Function1 = { false } + fun action() = action(this) + + fun clickCenter(): Boolean { + val robot = Robot() + val locationOnScreen = component.accessibleContext?.accessibleComponent?.locationOnScreen ?: return false + robot.mouseMove(locationOnScreen.x + bounds.width / 2, locationOnScreen.y + bounds.height / 2) + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK) + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK) + return true + } } diff --git a/src/main/java/com/maddyhome/idea/vim/extension/hints/ToggleHintsAction.kt b/src/main/java/com/maddyhome/idea/vim/extension/hints/ToggleHintsAction.kt index ad5ba810a9..0d5465531a 100644 --- a/src/main/java/com/maddyhome/idea/vim/extension/hints/ToggleHintsAction.kt +++ b/src/main/java/com/maddyhome/idea/vim/extension/hints/ToggleHintsAction.kt @@ -11,22 +11,17 @@ package com.maddyhome.idea.vim.extension.hints import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.editor.impl.EditorComponentImpl import com.intellij.openapi.project.DumbAwareToggleAction import com.intellij.openapi.ui.popup.JBPopupFactory import com.intellij.openapi.ui.popup.JBPopupListener import com.intellij.openapi.ui.popup.LightweightWindowEvent import com.intellij.openapi.wm.impl.IdeGlassPaneImpl import com.intellij.ui.JBColor -import com.intellij.ui.treeStructure.Tree import com.intellij.util.Alarm import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.extension.ShortcutDispatcher import com.maddyhome.idea.vim.newapi.globalIjOptions import java.awt.Color -import java.awt.Point -import java.awt.Robot -import java.awt.event.InputEvent import javax.swing.JComponent import javax.swing.JLabel import javax.swing.JPanel @@ -83,19 +78,10 @@ class ToggleHintsAction : DumbAwareToggleAction() { ShortcutDispatcher("hints", targets.associateBy { it.hint.lowercase() }, { target -> popup.closeOk(null) alarm.cancelAllRequests() - if (target.component is Tree || target.component is EditorComponentImpl) { - target.component.requestFocusInWindow() - } else { - // Click the center of the target component - val robot = Robot() - val location = Point(target.bounds.location) - SwingUtilities.convertPointToScreen(location, glassPane) - robot.mouseMove(location.x + target.bounds.width / 2, location.y + target.bounds.height / 2) - robot.mousePress(InputEvent.BUTTON1_DOWN_MASK) - robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK) + if (target.action()) { + highlight.setTarget(target) + alarm.addRequest({ highlight.setTarget(null) }, highlightDuration) } - highlight.setTarget(target) - alarm.addRequest({ highlight.setTarget(null) }, highlightDuration) }, { popup.cancel() injector.messages.indicateError() From 320cfbd0fa47122ea8012ac68de4c06b8953ec36 Mon Sep 17 00:00:00 2001 From: Xinhe Wang Date: Thu, 25 Sep 2025 14:32:23 +0100 Subject: [PATCH 3/3] Support hints for status bar widgets The project switching and version control menus in the top-left corner remain unavailable due to accessibility issues (failure to implement the Accessible interface, specifically) with the ToolbarComboButton component in the IntelliJ platform. --- .../com/maddyhome/idea/vim/extension/hints/HintGenerator.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/maddyhome/idea/vim/extension/hints/HintGenerator.kt b/src/main/java/com/maddyhome/idea/vim/extension/hints/HintGenerator.kt index 5e243b1092..bbb488525c 100644 --- a/src/main/java/com/maddyhome/idea/vim/extension/hints/HintGenerator.kt +++ b/src/main/java/com/maddyhome/idea/vim/extension/hints/HintGenerator.kt @@ -9,6 +9,7 @@ package com.maddyhome.idea.vim.extension.hints import com.intellij.openapi.editor.impl.EditorComponentImpl +import com.intellij.openapi.wm.impl.status.TextPanel import com.intellij.ui.treeStructure.Tree import java.awt.Component import java.awt.Point @@ -74,7 +75,7 @@ private fun collectTargets( val location = location + (accessible.location ?: return) accessible.size?.let { size -> - if (accessible.isShowing && (component.isClickable() || component is Tree)) { + if (accessible.isShowing && (component.isClickable() || component is Tree || component is TextPanel)) { targets[component].let { // For some reason, the same component may appear multiple times in the accessible tree. if (it == null || it.depth > depth) {