import { isCloud } from '@/platform/distribution/types' import { useSettingStore } from '@/platform/settings/settingStore' import { useCommandStore } from '@/stores/commandStore' import { useDialogStore } from '@/stores/dialogStore' import { CORE_KEYBINDINGS } from './defaults' import { KeyComboImpl } from './keyCombo' import { KeybindingImpl } from './keybinding' import { useKeybindingStore } from './keybindingStore' export function useKeybindingService() { const keybindingStore = useKeybindingStore() const commandStore = useCommandStore() const settingStore = useSettingStore() const dialogStore = useDialogStore() async function keybindHandler(event: KeyboardEvent) { const keyCombo = KeyComboImpl.fromEvent(event) if (keyCombo.isModifier) { return } const target = event.composedPath()[0] as HTMLElement if ( keyCombo.isReservedByTextInput && (target.tagName === 'TEXTAREA' || target.tagName === 'INPUT' || target.contentEditable === 'true' || (target.tagName === 'SPAN' && target.classList.contains('property_value'))) ) { return } const keybinding = keybindingStore.getKeybinding(keyCombo) if (keybinding) { const targetElementId = keybinding.targetElementId === 'graph-canvas' ? 'graph-canvas-container' : keybinding.targetElementId if (targetElementId) { const container = document.getElementById(targetElementId) if (!container?.contains(target)) { return } } if ( event.key === 'Escape' && !event.ctrlKey && !event.altKey && !event.metaKey ) { if (dialogStore.dialogStack.length > 0) { return } } event.preventDefault() const runCommandIds = new Set([ 'Comfy.QueuePrompt', 'Comfy.QueuePromptFront', 'Comfy.QueueSelectedOutputNodes' ]) if (runCommandIds.has(keybinding.commandId)) { await commandStore.execute(keybinding.commandId, { metadata: { trigger_source: 'keybinding' } }) } else { await commandStore.execute(keybinding.commandId) } return } if (event.ctrlKey || event.altKey || event.metaKey) { return } if (event.key === 'Escape') { const modals = document.querySelectorAll('.comfy-modal') for (const modal of modals) { const modalDisplay = window .getComputedStyle(modal) .getPropertyValue('display') if (modalDisplay !== 'none') { modal.style.display = 'none' break } } for (const d of document.querySelectorAll('dialog')) d.close() } } function registerCoreKeybindings() { for (const keybinding of CORE_KEYBINDINGS) { if ( isCloud && keybinding.commandId === 'Workspace.ToggleBottomPanelTab.logs-terminal' ) { continue } keybindingStore.addDefaultKeybinding(new KeybindingImpl(keybinding)) } } function registerUserKeybindings() { const unsetBindings = settingStore.get('Comfy.Keybinding.UnsetBindings') for (const keybinding of unsetBindings) { keybindingStore.unsetKeybinding(new KeybindingImpl(keybinding)) } const newBindings = settingStore.get('Comfy.Keybinding.NewBindings') for (const keybinding of newBindings) { if ( isCloud && keybinding.commandId === 'Workspace.ToggleBottomPanelTab.logs-terminal' ) { continue } keybindingStore.addUserKeybinding(new KeybindingImpl(keybinding)) } } async function persistUserKeybindings() { const toPlain = (b: KeybindingImpl) => ({ commandId: b.commandId, combo: { key: b.combo.key, ctrl: b.combo.ctrl, alt: b.combo.alt, shift: b.combo.shift }, ...(b.targetElementId !== undefined && { targetElementId: b.targetElementId }) }) await settingStore.setMany({ 'Comfy.Keybinding.NewBindings': Object.values( keybindingStore.getUserKeybindings() ).map(toPlain), 'Comfy.Keybinding.UnsetBindings': Object.values( keybindingStore.getUserUnsetKeybindings() ).map(toPlain) }) } return { keybindHandler, registerCoreKeybindings, registerUserKeybindings, persistUserKeybindings } }