Files
drawNET/static/js/modules/hotkeys/index.js
T

95 lines
3.4 KiB
JavaScript

import { state } from '../state.js';
import { actionHandlers } from './handlers.js';
import { logger } from '../utils/logger.js';
/**
* initHotkeys - Initializes the keyboard shortcut system.
*/
export async function initHotkeys() {
if (window.__drawNET_Hotkeys_Initialized) {
logger.high("Hotkeys already initialized. Skipping.");
return;
}
window.__drawNET_Hotkeys_Initialized = true;
try {
const response = await fetch('/static/hotkeys.json');
const config = await response.json();
const hotkeys = config.hotkeys;
window.addEventListener('keydown', (e) => {
if (e.repeat) return;
const editableElements = ['TEXTAREA', 'INPUT'];
const isTyping = editableElements.includes(e.target.tagName) && e.target.id !== 'dark-mode-toggle';
const keyPressed = e.key.toLowerCase();
const keyCode = e.code;
for (const hk of hotkeys) {
// Match by physical code (preferred) or key string
const matchCode = hk.code && hk.code === keyCode;
const matchKey = hk.key && hk.key.toLowerCase() === keyPressed;
if (!(matchCode || matchKey)) continue;
// Match modifiers strictly
const matchCtrl = !!hk.ctrl === e.ctrlKey;
const matchAlt = !!hk.alt === e.altKey;
const matchShift = !!hk.shift === e.shiftKey;
if (matchCtrl && matchAlt && matchShift) {
const allowWhileTyping = hk.alwaysEnabled === true;
if (isTyping && !allowWhileTyping) break;
logger.info(`Hotkey Match - ${hk.action} (${hk.key})`);
if (allowWhileTyping || !isTyping) {
e.preventDefault();
}
const handler = actionHandlers[hk.action];
if (handler) {
handler();
}
return;
}
}
});
logger.high("Hotkeys module initialized (X6).");
} catch (err) {
logger.critical("Failed to load hotkeys configuration (X6).", err);
}
// Ctrl + Wheel: Zoom handling
window.addEventListener('wheel', (e) => {
if (e.ctrlKey) {
e.preventDefault();
if (!state.graph) return;
const delta = e.deltaY > 0 ? -0.1 : 0.1;
state.graph.zoom(delta, { center: { x: e.clientX, y: e.clientY } });
}
}, { passive: false });
// Global Key State Tracking (for Ctrl+Drag copy)
// Extra guard: Check e.ctrlKey/metaKey on mouse events to auto-heal mismatched state
const syncCtrlState = (e) => {
const isModifier = e.ctrlKey || e.metaKey;
if (state.isCtrlPressed !== isModifier) {
state.isCtrlPressed = isModifier;
}
};
window.addEventListener('mousedown', syncCtrlState, true);
window.addEventListener('mousemove', syncCtrlState, true);
window.addEventListener('keydown', (e) => {
if (e.key === 'Control' || e.key === 'Meta') state.isCtrlPressed = true;
}, true);
window.addEventListener('keyup', (e) => {
if (e.key === 'Control' || e.key === 'Meta') state.isCtrlPressed = false;
}, true);
window.addEventListener('blur', () => {
state.isCtrlPressed = false; // Reset on window blur to avoid stuck state
});
}