mirror of
https://github.com/sotam0316/drawNET.git
synced 2026-04-25 03:58:37 +09:00
Initial commit: drawNET Alpha v1.0 - Professional Topology Designer with Full i18n and Performance Optimizations
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
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
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user