mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-11-09 14:03:33 +09:00
fix: implement own hotkeys (#2684)
Fixes https://discord.com/channels/955905230107738152/1184660413326053426/1184660413326053426 Primitives exposed by react-hotkeys-hook are quite useless and buggy for us. Here added own simple implementation which should fit our needs.
This commit is contained in:
1 parent
297b8f1961
commit
e2d14eee72
1 file changed
+24
-23
@@ -1,4 +1,3 @@
|
||||
import { isHotkeyPressed } from "react-hotkeys-hook";
|
||||
import { atom } from "nanostores";
|
||||
import { $publisher, subscribe } from "~/shared/pubsub";
|
||||
import { clientSyncStore } from "~/shared/sync";
|
||||
@@ -44,33 +43,35 @@ export type Command<CommandName extends string> = CommandMeta<CommandName> & {
|
||||
export const $commandMetas = atom(new Map<string, CommandMeta<string>>());
|
||||
clientSyncStore.register("commandMetas", $commandMetas);
|
||||
|
||||
// this is a hack to workaround react-hotkeys-hook implementation
|
||||
// of isHotkeyPressed which matches every specified keys
|
||||
// even when more keys pressed. This resulted in cmd+z and cmd+shift+z
|
||||
// both match when only cmd+z is pressed
|
||||
//
|
||||
// here find hotkeys which have more keys pressed at a time
|
||||
const findCommandsMatchingHeaviestHotkeys = () => {
|
||||
const findCommandsMatchingHotkeys = (event: KeyboardEvent) => {
|
||||
const { key, ctrlKey, metaKey, shiftKey, altKey } = event;
|
||||
const pressedKeys = new Set<string>();
|
||||
pressedKeys.add(key.toLocaleLowerCase());
|
||||
if (ctrlKey) {
|
||||
pressedKeys.add("ctrl");
|
||||
}
|
||||
if (metaKey) {
|
||||
pressedKeys.add("meta");
|
||||
}
|
||||
if (shiftKey) {
|
||||
pressedKeys.add("shift");
|
||||
}
|
||||
if (altKey) {
|
||||
pressedKeys.add("altKey");
|
||||
}
|
||||
|
||||
const commandMetas = $commandMetas.get();
|
||||
let maxHotkeySize = 0;
|
||||
let matchingCommands = new Set<CommandMeta<string>>();
|
||||
const matchingCommands = new Set<CommandMeta<string>>();
|
||||
for (const commandMeta of commandMetas.values()) {
|
||||
if (commandMeta.defaultHotkeys === undefined) {
|
||||
continue;
|
||||
}
|
||||
for (const hotkey of commandMeta.defaultHotkeys) {
|
||||
const keys = hotkey.split("+");
|
||||
const hotkeySize = keys.length;
|
||||
if (isHotkeyPressed(keys) === false) {
|
||||
continue;
|
||||
}
|
||||
// reset commands list when found more heavy hotkey
|
||||
if (maxHotkeySize < hotkeySize) {
|
||||
maxHotkeySize = hotkeySize;
|
||||
matchingCommands = new Set();
|
||||
}
|
||||
// hotkey matches haviest one
|
||||
if (maxHotkeySize === hotkeySize) {
|
||||
const keys = hotkey.toLocaleLowerCase().split("+");
|
||||
if (
|
||||
keys.length === pressedKeys.size &&
|
||||
keys.every((key) => pressedKeys.has(key))
|
||||
) {
|
||||
matchingCommands.add(commandMeta);
|
||||
}
|
||||
}
|
||||
@@ -128,7 +129,7 @@ export const createCommandsEmitter = <CommandName extends string>({
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
let emitted = false;
|
||||
let preventDefault = true;
|
||||
for (const commandMeta of findCommandsMatchingHeaviestHotkeys()) {
|
||||
for (const commandMeta of findCommandsMatchingHotkeys(event)) {
|
||||
if (
|
||||
commandMeta.disableHotkeyOutsideApp &&
|
||||
commandHandlers.has(commandMeta.name) === false
|
||||
|
||||
Reference in new issue
Block a user