1
0
mirror of https://github.com/chylex/IntelliJ-Keyboard-Master.git synced 2025-05-01 08:34:09 +02:00

Implement vim-style navigation for menu popups

This commit is contained in:
chylex 2024-05-05 05:16:39 +02:00
parent d3989a0e87
commit 5ca46cf8b2
Signed by: chylex
GPG Key ID: 4DE42C8F19A80548
2 changed files with 42 additions and 4 deletions
src/main/kotlin/com/chylex/intellij/keyboardmaster
configuration
feature/vimNavigation

View File

@ -37,7 +37,7 @@ class PluginConfiguration : PersistentStateComponent<PluginConfiguration> {
private fun update(instance: PluginConfiguration) = with(instance) { private fun update(instance: PluginConfiguration) = with(instance) {
CodeCompletionPopupConfiguration.updateShortcuts(codeCompletionItemShortcuts, codeCompletionNextPageShortcut, codeCompletionPrevPageShortcut) CodeCompletionPopupConfiguration.updateShortcuts(codeCompletionItemShortcuts, codeCompletionNextPageShortcut, codeCompletionPrevPageShortcut)
VimNavigation.isEnabled = enableVimNavigation VimNavigation.setEnabled(enableVimNavigation)
} }
} }

View File

@ -4,18 +4,22 @@ import com.chylex.intellij.keyboardmaster.PluginDisposableService
import com.chylex.intellij.keyboardmaster.feature.vimNavigation.components.VimListNavigation import com.chylex.intellij.keyboardmaster.feature.vimNavigation.components.VimListNavigation
import com.chylex.intellij.keyboardmaster.feature.vimNavigation.components.VimTableNavigation import com.chylex.intellij.keyboardmaster.feature.vimNavigation.components.VimTableNavigation
import com.chylex.intellij.keyboardmaster.feature.vimNavigation.components.VimTreeNavigation import com.chylex.intellij.keyboardmaster.feature.vimNavigation.components.VimTreeNavigation
import com.intellij.ide.ui.UISettings
import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ApplicationManager
import com.intellij.ui.UiInterceptors import com.intellij.ui.UiInterceptors
import com.intellij.util.ui.StartupUiUtil import com.intellij.util.ui.StartupUiUtil
import java.awt.AWTEvent import java.awt.AWTEvent
import java.awt.event.FocusEvent import java.awt.event.FocusEvent
import java.util.concurrent.atomic.AtomicBoolean
import javax.swing.JList import javax.swing.JList
import javax.swing.JTable import javax.swing.JTable
import javax.swing.JTree import javax.swing.JTree
import javax.swing.KeyStroke
import javax.swing.UIManager
object VimNavigation { object VimNavigation {
@Volatile private val isEnabled = AtomicBoolean(false)
var isEnabled = false private var originalPopupBindings: Array<*>? = null
fun register() { fun register() {
val disposable = ApplicationManager.getApplication().getService(PluginDisposableService::class.java) val disposable = ApplicationManager.getApplication().getService(PluginDisposableService::class.java)
@ -24,8 +28,42 @@ object VimNavigation {
UiInterceptors.registerPersistent(disposable, PopupInterceptor) UiInterceptors.registerPersistent(disposable, PopupInterceptor)
} }
fun setEnabled(enabled: Boolean) {
if (!isEnabled.compareAndSet(!enabled, enabled)) {
return
}
ApplicationManager.getApplication().invokeLater {
if (enabled) {
val originalBindings = (UIManager.get("PopupMenu.selectedWindowInputMapBindings") as Array<*>).also { originalPopupBindings = it }
val updatedBindings = mutableListOf(*originalBindings)
updatedBindings.add(KeyStroke.getKeyStroke('h'))
updatedBindings.add("selectParent")
updatedBindings.add(KeyStroke.getKeyStroke('j'))
updatedBindings.add("selectNext")
updatedBindings.add(KeyStroke.getKeyStroke('k'))
updatedBindings.add("selectPrevious")
updatedBindings.add(KeyStroke.getKeyStroke('l'))
updatedBindings.add("selectChild")
updatedBindings.add(KeyStroke.getKeyStroke('q'))
updatedBindings.add("cancel")
UIManager.put("PopupMenu.selectedWindowInputMapBindings", updatedBindings.toTypedArray())
UISettings.getInstance().disableMnemonics = true
}
else {
UIManager.put("PopupMenu.selectedWindowInputMapBindings", originalPopupBindings)
}
}
}
private fun handleEvent(event: AWTEvent) { private fun handleEvent(event: AWTEvent) {
if (event is FocusEvent && event.id == FocusEvent.FOCUS_GAINED && isEnabled) { if (event is FocusEvent && event.id == FocusEvent.FOCUS_GAINED && isEnabled.get()) {
when (val source = event.source) { when (val source = event.source) {
is JList<*> -> VimListNavigation.install(source) is JList<*> -> VimListNavigation.install(source)
is JTree -> VimTreeNavigation.install(source) is JTree -> VimTreeNavigation.install(source)