mirror of
https://github.com/chylex/IntelliJ-Keyboard-Master.git
synced 2024-11-25 01:42:47 +01:00
Compare commits
4 Commits
ca075869eb
...
48a9159c87
Author | SHA1 | Date | |
---|---|---|---|
48a9159c87 | |||
844738794b | |||
0e2928a737 | |||
b131413c8d |
@ -8,7 +8,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "com.chylex.intellij.keyboardmaster"
|
group = "com.chylex.intellij.keyboardmaster"
|
||||||
version = "0.5.4"
|
version = "0.5.5"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
@ -8,7 +8,7 @@ import com.intellij.ui.popup.list.ListPopupImpl
|
|||||||
|
|
||||||
internal object PopupInterceptor : PersistentUiInterceptor<AbstractPopup>(AbstractPopup::class.java) {
|
internal object PopupInterceptor : PersistentUiInterceptor<AbstractPopup>(AbstractPopup::class.java) {
|
||||||
override fun shouldIntercept(component: AbstractPopup): Boolean {
|
override fun shouldIntercept(component: AbstractPopup): Boolean {
|
||||||
if (component is ListPopupImpl) {
|
if (component is ListPopupImpl && VimNavigation.isEnabled) {
|
||||||
VimListNavigation.install(component.list, component)
|
VimListNavigation.install(component.list, component)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,9 +18,12 @@ import javax.swing.KeyStroke
|
|||||||
import javax.swing.UIManager
|
import javax.swing.UIManager
|
||||||
|
|
||||||
object VimNavigation {
|
object VimNavigation {
|
||||||
private val isEnabled = AtomicBoolean(false)
|
private val isEnabledFlag = AtomicBoolean(false)
|
||||||
private var originalPopupBindings: Array<*>? = null
|
private var originalPopupBindings: Array<*>? = null
|
||||||
|
|
||||||
|
val isEnabled
|
||||||
|
get() = isEnabledFlag.get()
|
||||||
|
|
||||||
fun register() {
|
fun register() {
|
||||||
val disposable = ApplicationManager.getApplication().getService(PluginDisposableService::class.java)
|
val disposable = ApplicationManager.getApplication().getService(PluginDisposableService::class.java)
|
||||||
|
|
||||||
@ -29,7 +32,7 @@ object VimNavigation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun setEnabled(enabled: Boolean) {
|
fun setEnabled(enabled: Boolean) {
|
||||||
if (!isEnabled.compareAndSet(!enabled, enabled)) {
|
if (!isEnabledFlag.compareAndSet(!enabled, enabled)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +64,7 @@ object VimNavigation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleEvent(event: AWTEvent) {
|
private fun handleEvent(event: AWTEvent) {
|
||||||
if (event is FocusEvent && event.id == FocusEvent.FOCUS_GAINED && isEnabled.get()) {
|
if (event is FocusEvent && event.id == FocusEvent.FOCUS_GAINED && isEnabled) {
|
||||||
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)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.chylex.intellij.keyboardmaster.feature.vimNavigation
|
package com.chylex.intellij.keyboardmaster.feature.vimNavigation
|
||||||
|
|
||||||
import com.chylex.intellij.keyboardmaster.PluginDisposableService
|
import com.chylex.intellij.keyboardmaster.PluginDisposableService
|
||||||
|
import com.chylex.intellij.keyboardmaster.feature.vimNavigation.VimNavigationDispatcher.WrappedAction.ForKeyListener
|
||||||
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
import com.intellij.openapi.actionSystem.ActionUpdateThread
|
||||||
import com.intellij.openapi.actionSystem.AnAction
|
import com.intellij.openapi.actionSystem.AnAction
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||||
@ -20,15 +21,18 @@ import java.awt.event.ActionListener
|
|||||||
import java.awt.event.KeyEvent
|
import java.awt.event.KeyEvent
|
||||||
import java.beans.PropertyChangeEvent
|
import java.beans.PropertyChangeEvent
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
import javax.swing.Action
|
||||||
import javax.swing.JComponent
|
import javax.swing.JComponent
|
||||||
import javax.swing.KeyStroke
|
import javax.swing.KeyStroke
|
||||||
|
|
||||||
internal open class VimNavigationDispatcher<T : JComponent>(final override val component: T, private val rootNode: KeyStrokeNode.Parent<VimNavigationDispatcher<T>>) : DumbAwareAction(), ComponentHolder {
|
internal open class VimNavigationDispatcher<T : JComponent>(final override val component: T, private val rootNode: KeyStrokeNode.Parent<VimNavigationDispatcher<T>>) : DumbAwareAction(), ComponentHolder {
|
||||||
companion object {
|
companion object {
|
||||||
private val DISPOSABLE = ApplicationManager.getApplication().getService(PluginDisposableService::class.java)
|
private val DISPOSABLE = ApplicationManager.getApplication().getService(PluginDisposableService::class.java)
|
||||||
private val ENTER_KEY = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)
|
|
||||||
|
|
||||||
private fun findOriginalEnterAction(component: JComponent): WrappedAction? {
|
@JvmStatic
|
||||||
|
protected val ENTER_KEY: KeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)
|
||||||
|
|
||||||
|
private fun findOriginalEnterAction(component: JComponent): WrappedAction {
|
||||||
var originalEnterAction: WrappedAction? = null
|
var originalEnterAction: WrappedAction? = null
|
||||||
|
|
||||||
for (container in JBIterable.generate<Container>(component) { it.parent }) {
|
for (container in JBIterable.generate<Container>(component) { it.parent }) {
|
||||||
@ -36,7 +40,7 @@ internal open class VimNavigationDispatcher<T : JComponent>(final override val c
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
container.getActionForKeyStroke(ENTER_KEY)?.let {
|
container.getActionForKeyStroke(ENTER_KEY)?.takeUnless(::isIgnoredEnterAction)?.let {
|
||||||
originalEnterAction = WrappedAction.ForActionListener(container, it)
|
originalEnterAction = WrappedAction.ForActionListener(container, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +51,11 @@ internal open class VimNavigationDispatcher<T : JComponent>(final override val c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return originalEnterAction
|
return originalEnterAction ?: ForKeyListener(component)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isIgnoredEnterAction(action: ActionListener): Boolean {
|
||||||
|
return action is Action && action.getValue(Action.NAME) == "toggle"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UnstableApiUsage")
|
@Suppress("UnstableApiUsage")
|
||||||
@ -100,15 +108,23 @@ internal open class VimNavigationDispatcher<T : JComponent>(final override val c
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleEnterKeyPress(actionEvent: AnActionEvent, keyEvent: KeyEvent) {
|
private fun handleEnterKeyPress(actionEvent: AnActionEvent, keyEvent: KeyEvent) {
|
||||||
if (isSearching.compareAndSet(true, false)) {
|
handleEnterKeyPress { originalEnterAction.perform(actionEvent, keyEvent) }
|
||||||
when (val supply = SpeedSearchSupply.getSupply(component)) {
|
|
||||||
is SpeedSearchBase<*> -> supply.hidePopup()
|
|
||||||
is SpeedSearch -> supply.reset()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected inline fun handleEnterKeyPress(originalAction: () -> Unit) {
|
||||||
|
if (isSearching.compareAndSet(true, false)) {
|
||||||
|
stopSpeedSearch()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
currentNode = rootNode
|
currentNode = rootNode
|
||||||
originalEnterAction?.perform(actionEvent, keyEvent)
|
originalAction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun stopSpeedSearch() {
|
||||||
|
when (val supply = SpeedSearchSupply.getSupply(component)) {
|
||||||
|
is SpeedSearchBase<*> -> supply.hidePopup()
|
||||||
|
is SpeedSearch -> supply.reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +148,7 @@ internal open class VimNavigationDispatcher<T : JComponent>(final override val c
|
|||||||
private sealed interface WrappedAction {
|
private sealed interface WrappedAction {
|
||||||
fun perform(actionEvent: AnActionEvent, keyEvent: KeyEvent)
|
fun perform(actionEvent: AnActionEvent, keyEvent: KeyEvent)
|
||||||
|
|
||||||
class ForActionListener(val component: JComponent, val listener: ActionListener) : WrappedAction {
|
class ForActionListener(private val component: JComponent, private val listener: ActionListener) : WrappedAction {
|
||||||
override fun perform(actionEvent: AnActionEvent, keyEvent: KeyEvent) {
|
override fun perform(actionEvent: AnActionEvent, keyEvent: KeyEvent) {
|
||||||
listener.actionPerformed(ActionEvent(component, ActionEvent.ACTION_PERFORMED, "Enter", keyEvent.`when`, keyEvent.modifiersEx))
|
listener.actionPerformed(ActionEvent(component, ActionEvent.ACTION_PERFORMED, "Enter", keyEvent.`when`, keyEvent.modifiersEx))
|
||||||
}
|
}
|
||||||
@ -143,5 +159,12 @@ internal open class VimNavigationDispatcher<T : JComponent>(final override val c
|
|||||||
action.actionPerformed(actionEvent)
|
action.actionPerformed(actionEvent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ForKeyListener(private val component: JComponent) : WrappedAction {
|
||||||
|
override fun perform(actionEvent: AnActionEvent, keyEvent: KeyEvent) {
|
||||||
|
val unconsumedKeyEvent = KeyEvent(component, keyEvent.id, keyEvent.`when`, keyEvent.modifiersEx, keyEvent.keyCode, keyEvent.keyChar, keyEvent.keyLocation)
|
||||||
|
component.dispatchEvent(unconsumedKeyEvent)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import com.intellij.openapi.ui.getUserData
|
|||||||
import com.intellij.openapi.ui.putUserData
|
import com.intellij.openapi.ui.putUserData
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.ui.popup.WizardPopup
|
import com.intellij.ui.popup.WizardPopup
|
||||||
|
import com.intellij.ui.popup.list.ListPopupImpl
|
||||||
import com.intellij.ui.speedSearch.SpeedSearch
|
import com.intellij.ui.speedSearch.SpeedSearch
|
||||||
import com.intellij.ui.speedSearch.SpeedSearchSupply
|
import com.intellij.ui.speedSearch.SpeedSearchSupply
|
||||||
import java.awt.event.ActionEvent
|
import java.awt.event.ActionEvent
|
||||||
@ -85,6 +86,24 @@ internal object VimListNavigation {
|
|||||||
// WizardPopup only checks key codes against its input map, but key codes may be undefined for some characters.
|
// WizardPopup only checks key codes against its input map, but key codes may be undefined for some characters.
|
||||||
popup.registerAction("KeyboardMaster-VimListNavigation-PauseSpeedSearch", KeyStroke.getKeyStroke(KeyEvent.CHAR_UNDEFINED, 0), pauseAction)
|
popup.registerAction("KeyboardMaster-VimListNavigation-PauseSpeedSearch", KeyStroke.getKeyStroke(KeyEvent.CHAR_UNDEFINED, 0), pauseAction)
|
||||||
popup.registerAction("KeyboardMaster-VimListNavigation-PauseSpeedSearch", KeyStroke.getKeyStroke(KeyEvent.CHAR_UNDEFINED, KeyEvent.SHIFT_DOWN_MASK), pauseAction)
|
popup.registerAction("KeyboardMaster-VimListNavigation-PauseSpeedSearch", KeyStroke.getKeyStroke(KeyEvent.CHAR_UNDEFINED, KeyEvent.SHIFT_DOWN_MASK), pauseAction)
|
||||||
|
|
||||||
|
if (popup is ListPopupImpl) {
|
||||||
|
popup.registerAction("KeyboardMaster-VimListNavigation-Enter", ENTER_KEY, object : AbstractAction() {
|
||||||
|
override fun actionPerformed(e: ActionEvent) {
|
||||||
|
handleEnterKeyPress { popup.handleSelect(true, createEnterEvent(e)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createEnterEvent(e: ActionEvent): KeyEvent {
|
||||||
|
return KeyEvent(component, KeyEvent.KEY_PRESSED, e.`when`, e.modifiers, KeyEvent.VK_ENTER, KeyEvent.CHAR_UNDEFINED)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun stopSpeedSearch() {
|
||||||
|
val selectedValue = component.selectedValue
|
||||||
|
super.stopSpeedSearch()
|
||||||
|
component.setSelectedValue(selectedValue, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PauseSpeedSearchAction(private val dispatcher: VimNavigationDispatcher<JList<*>>, private val speedSearch: SpeedSearch) : AbstractAction() {
|
private class PauseSpeedSearchAction(private val dispatcher: VimNavigationDispatcher<JList<*>>, private val speedSearch: SpeedSearch) : AbstractAction() {
|
||||||
|
Loading…
Reference in New Issue
Block a user