chromatic-lattice/src/features/hotkey.tsx

112 lines
2.9 KiB
TypeScript
Raw Normal View History

2022-03-04 03:39:48 +00:00
import { hasWon } from "data/projEntry";
import { globalBus } from "game/events";
import player from "game/player";
2022-03-11 22:38:49 +00:00
import { registerInfoComponent } from "game/settings";
2022-01-14 04:25:47 +00:00
import {
Computable,
GetComputableTypeWithDefault,
GetComputableType,
ProcessedComputable,
processComputable
2022-03-04 03:39:48 +00:00
} from "util/computed";
import { createLazyProxy } from "util/proxies";
2022-03-11 22:38:49 +00:00
import { shallowReactive, unref } from "vue";
import { findFeatures, jsx, Replace, setDefault } from "./feature";
2022-01-14 04:25:47 +00:00
2022-03-11 22:38:49 +00:00
export const hotkeys: Record<string, GenericHotkey | undefined> = shallowReactive({});
2022-01-14 04:25:47 +00:00
export const HotkeyType = Symbol("Hotkey");
export interface HotkeyOptions {
enabled?: Computable<boolean>;
key: string;
description: Computable<string>;
onPress: VoidFunction;
}
2022-03-09 01:40:51 +00:00
export interface BaseHotkey {
2022-01-14 04:25:47 +00:00
type: typeof HotkeyType;
}
export type Hotkey<T extends HotkeyOptions> = Replace<
T & BaseHotkey,
{
enabled: GetComputableTypeWithDefault<T["enabled"], true>;
description: GetComputableType<T["description"]>;
}
>;
export type GenericHotkey = Replace<
Hotkey<HotkeyOptions>,
{
enabled: ProcessedComputable<boolean>;
}
>;
export function createHotkey<T extends HotkeyOptions>(
optionsFunc: () => T & ThisType<Hotkey<T>>
): Hotkey<T> {
return createLazyProxy(() => {
const hotkey: T & Partial<BaseHotkey> = optionsFunc();
hotkey.type = HotkeyType;
2022-01-14 04:25:47 +00:00
processComputable(hotkey as T, "enabled");
setDefault(hotkey, "enabled", true);
processComputable(hotkey as T, "description");
2022-01-14 04:25:47 +00:00
return hotkey as unknown as Hotkey<T>;
});
2022-01-14 04:25:47 +00:00
}
globalBus.on("addLayer", layer => {
(findFeatures(layer, HotkeyType) as GenericHotkey[]).forEach(hotkey => {
hotkeys[hotkey.key] = hotkey;
});
});
globalBus.on("removeLayer", layer => {
(findFeatures(layer, HotkeyType) as GenericHotkey[]).forEach(hotkey => {
2022-01-25 04:23:30 +00:00
hotkeys[hotkey.key] = undefined;
2022-01-14 04:25:47 +00:00
});
});
2022-01-25 04:23:30 +00:00
document.onkeydown = function (e) {
2022-01-14 04:25:47 +00:00
if ((e.target as HTMLElement | null)?.tagName === "INPUT") {
return;
}
if (hasWon.value && !player.keepGoing) {
return;
}
let key = e.key;
if (e.shiftKey) {
key = "shift+" + key;
}
if (e.ctrlKey) {
key = "ctrl+" + key;
}
const hotkey = hotkeys[key];
if (hotkey && unref(hotkey.enabled)) {
e.preventDefault();
hotkey.onPress();
}
};
2022-03-11 22:38:49 +00:00
registerInfoComponent(
jsx(() => {
const keys = Object.values(hotkeys).filter(hotkey => unref(hotkey?.enabled));
if (keys.length === 0) {
return "";
}
return (
<div>
<br />
<h4>Hotkeys</h4>
{keys.map(hotkey => (
<div>
{hotkey?.key}: {hotkey?.description}
</div>
))}
</div>
);
})
);