From cc17bee945ab61630b47bfb46a9c5d1a47529aa7 Mon Sep 17 00:00:00 2001 From: Chenlei Hu Date: Mon, 7 Oct 2024 16:50:58 -0400 Subject: [PATCH] Manage app.ts litegraph keybindings (#1151) * Manage app.ts litegraph keybindings * nit --- src/extensions/core/keybinds.ts | 2 +- src/scripts/app.ts | 80 ++++----------------------------- src/stores/commandStore.ts | 75 ++++++++++++++++++++++++++++++- src/stores/coreKeybindings.ts | 66 +++++++++++++++++++++++++++ src/stores/keybindingStore.ts | 6 ++- src/types/keyBindingTypes.ts | 7 ++- 6 files changed, 159 insertions(+), 77 deletions(-) diff --git a/src/extensions/core/keybinds.ts b/src/extensions/core/keybinds.ts index 7cfdc5a45..736cf64bd 100644 --- a/src/extensions/core/keybinds.ts +++ b/src/extensions/core/keybinds.ts @@ -30,7 +30,7 @@ app.registerExtension({ const keybindingStore = useKeybindingStore() const commandStore = useCommandStore() const keybinding = keybindingStore.getKeybinding(keyCombo) - if (keybinding) { + if (keybinding && keybinding.targetSelector !== '#graph-canvas') { await commandStore.execute(keybinding.commandId) event.preventDefault() return diff --git a/src/scripts/app.ts b/src/scripts/app.ts index 691d962d5..17ee4c685 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -53,6 +53,8 @@ import { useWorkspaceStore } from '@/stores/workspaceStateStore' import { useExecutionStore } from '@/stores/executionStore' import { IWidget } from '@comfyorg/litegraph' import { useExtensionStore } from '@/stores/extensionStore' +import { KeyComboImpl, useKeybindingStore } from '@/stores/keybindingStore' +import { useCommandStore } from '@/stores/commandStore' export const ANIM_PREVIEW_WIDGET = '$$comfy_animation_preview' @@ -1278,13 +1280,10 @@ export class ComfyApp { /** * Handle keypress - * - * Ctrl + M mute/unmute selected nodes */ #addProcessKeyHandler() { - const self = this const origProcessKey = LGraphCanvas.prototype.processKey - LGraphCanvas.prototype.processKey = function (e) { + LGraphCanvas.prototype.processKey = function (e: KeyboardEvent) { if (!this.graph) { return } @@ -1296,54 +1295,11 @@ export class ComfyApp { } if (e.type == 'keydown' && !e.repeat) { - // Ctrl + M mute/unmute - if (e.key === 'm' && (e.metaKey || e.ctrlKey)) { - if (this.selected_nodes) { - for (var i in this.selected_nodes) { - if (this.selected_nodes[i].mode === 2) { - // never - this.selected_nodes[i].mode = 0 // always - } else { - this.selected_nodes[i].mode = 2 // never - } - } - } - block_default = true - } - - // Ctrl + B bypass - if (e.key === 'b' && (e.metaKey || e.ctrlKey)) { - if (this.selected_nodes) { - for (var i in this.selected_nodes) { - if (this.selected_nodes[i].mode === 4) { - // never - this.selected_nodes[i].mode = 0 // always - } else { - this.selected_nodes[i].mode = 4 // never - } - } - } - block_default = true - } - - // p pin/unpin - if (e.key === 'p') { - if (this.selected_nodes) { - for (const i in this.selected_nodes) { - const node = this.selected_nodes[i] - node.pin() - } - } - block_default = true - } - - // Alt + C collapse/uncollapse - if (e.key === 'c' && e.altKey) { - if (this.selected_nodes) { - for (var i in this.selected_nodes) { - this.selected_nodes[i].collapse() - } - } + const keyCombo = KeyComboImpl.fromEvent(e) + const keybindingStore = useKeybindingStore() + const keybinding = keybindingStore.getKeybinding(keyCombo) + if (keybinding && keybinding.targetSelector === '#graph-canvas') { + useCommandStore().execute(keybinding.commandId) block_default = true } @@ -1362,26 +1318,6 @@ export class ComfyApp { // Trigger onPaste return true } - - if (e.key === '+' && e.altKey) { - block_default = true - let scale = this.ds.scale * 1.1 - this.ds.changeScale(scale, [ - this.ds.element.width / 2, - this.ds.element.height / 2 - ]) - this.graph.change() - } - - if (e.key === '-' && e.altKey) { - block_default = true - let scale = (this.ds.scale * 1) / 1.1 - this.ds.changeScale(scale, [ - this.ds.element.width / 2, - this.ds.element.height / 2 - ]) - this.graph.change() - } } this.graph.change() diff --git a/src/stores/commandStore.ts b/src/stores/commandStore.ts index 7ed61e80e..9bd7ef708 100644 --- a/src/stores/commandStore.ts +++ b/src/stores/commandStore.ts @@ -17,6 +17,7 @@ import { useTitleEditorStore } from './graphStore' import { useErrorHandling } from '@/hooks/errorHooks' import { useWorkflowStore } from './workflowStore' import { type KeybindingImpl, useKeybindingStore } from './keybindingStore' +import { LGraphNode } from '@comfyorg/litegraph' export interface ComfyCommand { id: string @@ -75,6 +76,28 @@ export class ComfyCommandImpl implements ComfyCommand { const getTracker = () => app.workflowManager.activeWorkflow?.changeTracker ?? globalTracker +const getSelectedNodes = (): LGraphNode[] => { + const selectedNodes = app.canvas.selected_nodes + const result: LGraphNode[] = [] + if (selectedNodes) { + for (const i in selectedNodes) { + const node = selectedNodes[i] + result.push(node) + } + } + return result +} + +const toggleSelectedNodesMode = (mode: number) => { + getSelectedNodes().forEach((node) => { + if (node.mode === mode) { + node.mode = 0 // always + } else { + node.mode = mode + } + }) +} + export const useCommandStore = defineStore('command', () => { const settingStore = useSettingStore() @@ -248,7 +271,11 @@ export const useCommandStore = defineStore('command', () => { icon: 'pi pi-plus', label: 'Zoom In', function: () => { - app.canvas.ds.changeScale(app.canvas.ds.scale + 0.1) + const ds = app.canvas.ds + ds.changeScale(ds.scale * 1.1, [ + ds.element.width / 2, + ds.element.height / 2 + ]) app.canvas.setDirty(true, true) } }, @@ -257,7 +284,11 @@ export const useCommandStore = defineStore('command', () => { icon: 'pi pi-minus', label: 'Zoom Out', function: () => { - app.canvas.ds.changeScale(app.canvas.ds.scale - 0.1) + const ds = app.canvas.ds + ds.changeScale(ds.scale / 1.1, [ + ds.element.width / 2, + ds.element.height / 2 + ]) app.canvas.setDirty(true, true) } }, @@ -365,6 +396,46 @@ export const useCommandStore = defineStore('command', () => { function: () => { useWorkflowStore().loadPreviousOpenedWorkflow() } + }, + { + id: 'Comfy.Canvas.ToggleSelectedNodes.Mute', + icon: 'pi pi-volume-off', + label: 'Mute/Unmute Selected Nodes', + versionAdded: '1.3.11', + function: () => { + toggleSelectedNodesMode(2) // muted + } + }, + { + id: 'Comfy.Canvas.ToggleSelectedNodes.Bypass', + icon: 'pi pi-shield', + label: 'Bypass/Unbypass Selected Nodes', + versionAdded: '1.3.11', + function: () => { + toggleSelectedNodesMode(4) // bypassed + } + }, + { + id: 'Comfy.Canvas.ToggleSelectedNodes.Pin', + icon: 'pi pi-pin', + label: 'Pin/Unpin Selected Nodes', + versionAdded: '1.3.11', + function: () => { + getSelectedNodes().forEach((node) => { + node.pin(!node.pinned) + }) + } + }, + { + id: 'Comfy.Canvas.ToggleSelectedNodes.Collapse', + icon: 'pi pi-minus', + label: 'Collapse/Expand Selected Nodes', + versionAdded: '1.3.11', + function: () => { + getSelectedNodes().forEach((node) => { + node.collapse() + }) + } } ] diff --git a/src/stores/coreKeybindings.ts b/src/stores/coreKeybindings.ts index 0afea36a3..aec19029f 100644 --- a/src/stores/coreKeybindings.ts +++ b/src/stores/coreKeybindings.ts @@ -94,5 +94,71 @@ export const CORE_KEYBINDINGS: Keybinding[] = [ ctrl: true }, commandId: 'Comfy.ShowSettingsDialog' + }, + // For '=' both holding shift and not holding shift + { + combo: { + key: '=', + alt: true + }, + commandId: 'Comfy.Canvas.ZoomIn', + targetSelector: '#graph-canvas' + }, + { + combo: { + key: '+', + alt: true, + shift: true + }, + commandId: 'Comfy.Canvas.ZoomIn', + targetSelector: '#graph-canvas' + }, + // For number pad '+' + { + combo: { + key: '+', + alt: true + }, + commandId: 'Comfy.Canvas.ZoomIn', + targetSelector: '#graph-canvas' + }, + { + combo: { + key: '-', + alt: true + }, + commandId: 'Comfy.Canvas.ZoomOut', + targetSelector: '#graph-canvas' + }, + { + combo: { + key: 'p' + }, + commandId: 'Comfy.Canvas.ToggleSelectedNodes.Pin', + targetSelector: '#graph-canvas' + }, + { + combo: { + key: 'c', + alt: true + }, + commandId: 'Comfy.Canvas.ToggleSelectedNodes.Collapse', + targetSelector: '#graph-canvas' + }, + { + combo: { + key: 'b', + ctrl: true + }, + commandId: 'Comfy.Canvas.ToggleSelectedNodes.Bypass', + targetSelector: '#graph-canvas' + }, + { + combo: { + key: 'm', + ctrl: true + }, + commandId: 'Comfy.Canvas.ToggleSelectedNodes.Mute', + targetSelector: '#graph-canvas' } ] diff --git a/src/stores/keybindingStore.ts b/src/stores/keybindingStore.ts index 924b23ea6..c82cf3369 100644 --- a/src/stores/keybindingStore.ts +++ b/src/stores/keybindingStore.ts @@ -8,16 +8,20 @@ import type { ComfyExtension } from '@/types/comfy' export class KeybindingImpl implements Keybinding { commandId: string combo: KeyComboImpl + targetSelector?: string constructor(obj: Keybinding) { this.commandId = obj.commandId this.combo = new KeyComboImpl(obj.combo) + this.targetSelector = obj.targetSelector } equals(other: any): boolean { if (toRaw(other) instanceof KeybindingImpl) { return ( - this.commandId === other.commandId && this.combo.equals(other.combo) + this.commandId === other.commandId && + this.combo.equals(other.combo) && + this.targetSelector === other.targetSelector ) } return false diff --git a/src/types/keyBindingTypes.ts b/src/types/keyBindingTypes.ts index c637e2084..863cae0dd 100644 --- a/src/types/keyBindingTypes.ts +++ b/src/types/keyBindingTypes.ts @@ -12,7 +12,12 @@ export const zKeyCombo = z.object({ // Keybinding schema export const zKeybinding = z.object({ commandId: z.string(), - combo: zKeyCombo + combo: zKeyCombo, + // Optional target element CSS selector to limit keybinding to. + // Note: Currently only used to distinguish between global keybindings + // and litegraph canvas keybindings. + // Do NOT use this field in extensions as it has no effect. + targetSelector: z.string().optional() }) // Infer types from schemas