excalidraw/packages/excalidraw/keys.ts
Marcel Mraz 21ffaf4d76
All checks were successful
Tests / test (push) Successful in 4m38s
refactor: auto ordered imports (#9163)
2025-03-12 15:23:31 +01:00

151 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { isDarwin } from "./constants";
import type { ValueOf } from "./utility-types";
export const CODES = {
EQUAL: "Equal",
MINUS: "Minus",
NUM_ADD: "NumpadAdd",
NUM_SUBTRACT: "NumpadSubtract",
NUM_ZERO: "Numpad0",
BRACKET_RIGHT: "BracketRight",
BRACKET_LEFT: "BracketLeft",
ONE: "Digit1",
TWO: "Digit2",
THREE: "Digit3",
NINE: "Digit9",
QUOTE: "Quote",
ZERO: "Digit0",
SLASH: "Slash",
C: "KeyC",
D: "KeyD",
H: "KeyH",
V: "KeyV",
Z: "KeyZ",
Y: "KeyY",
R: "KeyR",
S: "KeyS",
} as const;
export const KEYS = {
ARROW_DOWN: "ArrowDown",
ARROW_LEFT: "ArrowLeft",
ARROW_RIGHT: "ArrowRight",
ARROW_UP: "ArrowUp",
PAGE_UP: "PageUp",
PAGE_DOWN: "PageDown",
BACKSPACE: "Backspace",
ALT: "Alt",
CTRL_OR_CMD: isDarwin ? "metaKey" : "ctrlKey",
DELETE: "Delete",
ENTER: "Enter",
ESCAPE: "Escape",
QUESTION_MARK: "?",
SPACE: " ",
TAB: "Tab",
CHEVRON_LEFT: "<",
CHEVRON_RIGHT: ">",
PERIOD: ".",
COMMA: ",",
SUBTRACT: "-",
SLASH: "/",
A: "a",
C: "c",
D: "d",
E: "e",
F: "f",
G: "g",
H: "h",
I: "i",
L: "l",
O: "o",
P: "p",
Q: "q",
R: "r",
S: "s",
T: "t",
V: "v",
X: "x",
Y: "y",
Z: "z",
K: "k",
W: "w",
0: "0",
1: "1",
2: "2",
3: "3",
4: "4",
5: "5",
6: "6",
7: "7",
8: "8",
9: "9",
} as const;
export type Key = keyof typeof KEYS;
// defines key code mapping for matching codes as fallback to respective keys on non-latin keyboard layouts
export const KeyCodeMap = new Map<ValueOf<typeof KEYS>, ValueOf<typeof CODES>>([
[KEYS.Z, CODES.Z],
[KEYS.Y, CODES.Y],
]);
export const isLatinChar = (key: string) => /^[a-z]$/.test(key.toLowerCase());
/**
* Used to match key events for any keyboard layout, especially on Windows and Linux,
* where non-latin character with modified (CMD) is not substituted with latin-based alternative.
*
* Uses `event.key` when it's latin, otherwise fallbacks to `event.code` (if mapping exists).
*
* Example of pressing "z" on different layouts, with the chosen key or code highlighted in []:
*
* Layout | Code | Key | Comment
* --------------------- | ----- | --- | -------
* U.S. | KeyZ | [z] |
* Czech | KeyY | [z] |
* Turkish | KeyN | [z] |
* French | KeyW | [z] |
* Macedonian | [KeyZ] | з | z with cmd; з is Cyrillic equivalent of z
* Russian | [KeyZ] | я | z with cmd
* Serbian | [KeyZ] | ѕ | z with cmd
* Greek | [KeyZ] | ζ | z with cmd; also ζ is Greek equivalent of z
* Hebrew | [KeyZ] | ז | z with cmd; also ז is Hebrew equivalent of z
* Pinyin - Simplified | KeyZ | [z] | due to IME
* Cangije - Traditional | [KeyZ] | 重 | z with cmd
* Japanese | [KeyZ] | つ | z with cmd
* 2-Set Korean | [KeyZ] | ㅋ | z with cmd
*
* More details in https://github.com/excalidraw/excalidraw/pull/5944
*/
export const matchKey = (
event: KeyboardEvent | React.KeyboardEvent<Element>,
key: ValueOf<typeof KEYS>,
): boolean => {
// for latin layouts use key
if (key === event.key.toLowerCase()) {
return true;
}
// non-latin layouts fallback to code
const code = KeyCodeMap.get(key);
return Boolean(code && !isLatinChar(event.key) && event.code === code);
};
export const isArrowKey = (key: string) =>
key === KEYS.ARROW_LEFT ||
key === KEYS.ARROW_RIGHT ||
key === KEYS.ARROW_DOWN ||
key === KEYS.ARROW_UP;
export const shouldResizeFromCenter = (event: MouseEvent | KeyboardEvent) =>
event.altKey;
export const shouldMaintainAspectRatio = (event: MouseEvent | KeyboardEvent) =>
event.shiftKey;
export const shouldRotateWithDiscreteAngle = (
event: MouseEvent | KeyboardEvent | React.PointerEvent<HTMLCanvasElement>,
) => event.shiftKey;