ProzillaOS/src/hooks/utils/keyboard.js
2023-08-11 16:27:12 +02:00

91 lines
No EOL
2.1 KiB
JavaScript

import { useEffect, useState } from "react";
import { removeFromArray } from "../../features/utils/array.js";
/**
* @param {object} params
* @param {Function} params.onKeyDown
* @param {Function} params.onKeyUp
*/
export function useKeyboardListener({ onKeyDown, onKeyUp }) {
useEffect(() => {
if (onKeyDown)
document.addEventListener("keydown", onKeyDown);
if (onKeyUp)
document.addEventListener("keyup", onKeyUp);
return () => {
if (onKeyDown)
document.removeEventListener("keydown", onKeyDown);
if (onKeyUp)
document.removeEventListener("keyup", onKeyUp);
};
}, [onKeyDown, onKeyUp]);
}
/**
* @param {object} props
* @param {Object<string, Object<string, Function>>} props.options
* @param {Object<string, Object<string, string[]>>} props.shortcuts
* @param {boolean} props.useCategories
*/
export function useShortcuts({ options, shortcuts, useCategories = true }) {
const [activeKeys, setActiveKeys] = useState([]);
const checkShortcuts = (event, allowExecution = true) => {
if (!shortcuts)
return;
const checkGroup = (group, category) => {
for (const [name, shortcut] of Object.entries(group)) {
let active = true;
shortcut.forEach((key) => {
if (!activeKeys.includes(key) && event.key !== key)
return active = false;
});
if (!active)
continue;
event.preventDefault();
if (!shortcut.includes(event.key) || !allowExecution)
continue;
if (category != null) {
options?.[category]?.[name]?.();
} else {
options?.[name]?.();
}
}
};
if (useCategories) {
for (const [category, group] of Object.entries(shortcuts)) {
checkGroup(group, category);
}
} else {
checkGroup(shortcuts);
}
};
const onKeyDown = (event) => {
const isRepeated = activeKeys.includes(event.key);
checkShortcuts(event, isRepeated);
if (!isRepeated)
setActiveKeys(activeKeys.concat([event.key]));
};
const onKeyUp = (event) => {
checkShortcuts(event);
if (activeKeys.includes(event.key)) {
const keys = [...activeKeys];
removeFromArray(event.key, keys);
setActiveKeys(keys);
}
};
useKeyboardListener({ onKeyDown, onKeyUp });
}