Refactor shortcuts into a central file and fix issue with caps lock

This commit is contained in:
Mitchell McCaffrey 2021-03-25 16:31:06 +11:00
parent c77db06bce
commit ad68aa7226
9 changed files with 190 additions and 85 deletions

View File

@ -42,6 +42,8 @@ import SubtractShapeAction from "../../actions/SubtractShapeAction";
import useSetting from "../../hooks/useSetting"; import useSetting from "../../hooks/useSetting";
import shortcuts from "../../shortcuts";
function MapFog({ function MapFog({
map, map,
shapes, shapes,
@ -402,16 +404,20 @@ function MapFog({
}, [toolSettings, drawingShape, onShapesCut, onShapesAdd, shapes]); }, [toolSettings, drawingShape, onShapesCut, onShapesAdd, shapes]);
// Add keyboard shortcuts // Add keyboard shortcuts
function handleKeyDown({ key }) { function handleKeyDown(event) {
if (key === "Enter" && toolSettings.type === "polygon" && drawingShape) { if (
shortcuts.fogFinishPolygon(event) &&
toolSettings.type === "polygon" &&
drawingShape
) {
finishDrawingPolygon(); finishDrawingPolygon();
} }
if (key === "Escape" && drawingShape) { if (shortcuts.fogCancelPolygon(event) && drawingShape) {
setDrawingShape(null); setDrawingShape(null);
} }
// Remove last point from polygon shape if delete pressed // Remove last point from polygon shape if delete pressed
if ( if (
(key === "Backspace" || key === "Delete") && shortcuts.delete(event) &&
drawingShape && drawingShape &&
toolSettings.type === "polygon" toolSettings.type === "polygon"
) { ) {

View File

@ -11,6 +11,8 @@ import { useKeyboard } from "../../contexts/KeyboardContext";
import Vector2 from "../../helpers/Vector2"; import Vector2 from "../../helpers/Vector2";
import shortcuts from "../../shortcuts";
function MapGridEditor({ map, onGridChange }) { function MapGridEditor({ map, onGridChange }) {
const stageScale = useDebouncedStageScale(); const stageScale = useDebouncedStageScale();
const mapWidth = useMapWidth(); const mapWidth = useMapWidth();
@ -166,20 +168,19 @@ function MapGridEditor({ map, onGridChange }) {
} }
function handleKeyDown(event) { function handleKeyDown(event) {
const { key, shiftKey } = event; const nudgeAmount = event.shiftKey ? 2 : 0.5;
const nudgeAmount = shiftKey ? 2 : 0.5; if (shortcuts.gridNudgeUp(event)) {
if (key === "ArrowUp") {
// Stop arrow up/down scrolling if overflowing // Stop arrow up/down scrolling if overflowing
event.preventDefault(); event.preventDefault();
nudgeGrid({ x: 0, y: -1 }, nudgeAmount); nudgeGrid({ x: 0, y: -1 }, nudgeAmount);
} }
if (key === "ArrowLeft") { if (shortcuts.gridNudgeLeft(event)) {
nudgeGrid({ x: -1, y: 0 }, nudgeAmount); nudgeGrid({ x: -1, y: 0 }, nudgeAmount);
} }
if (key === "ArrowRight") { if (shortcuts.gridNudgeRight(event)) {
nudgeGrid({ x: 1, y: 0 }, nudgeAmount); nudgeGrid({ x: 1, y: 0 }, nudgeAmount);
} }
if (key === "ArrowDown") { if (shortcuts.gridNudgeDown(event)) {
event.preventDefault(); event.preventDefault();
nudgeGrid({ x: 0, y: 1 }, nudgeAmount); nudgeGrid({ x: 0, y: 1 }, nudgeAmount);
} }

View File

@ -17,6 +17,8 @@ import { useMapStage } from "../../contexts/MapStageContext";
import { GridProvider } from "../../contexts/GridContext"; import { GridProvider } from "../../contexts/GridContext";
import { useKeyboard } from "../../contexts/KeyboardContext"; import { useKeyboard } from "../../contexts/KeyboardContext";
import shortcuts from "../../shortcuts";
function MapInteraction({ function MapInteraction({
map, map,
mapState, mapState,
@ -111,12 +113,12 @@ function MapInteraction({
function handleKeyDown(event) { function handleKeyDown(event) {
// Change to move tool when pressing space // Change to move tool when pressing space
if (event.key === " " && selectedToolId === "move") { if (shortcuts.move(event) && selectedToolId === "move") {
// Stop active state on move icon from being selected // Stop active state on move icon from being selected
event.preventDefault(); event.preventDefault();
} }
if ( if (
event.key === " " && shortcuts.move(event) &&
selectedToolId !== "move" && selectedToolId !== "move" &&
!disabledControls.includes("move") !disabledControls.includes("move")
) { ) {
@ -126,28 +128,28 @@ function MapInteraction({
} }
// Basic keyboard shortcuts // Basic keyboard shortcuts
if (event.key === "w" && !disabledControls.includes("move")) { if (shortcuts.moveTool(event) && !disabledControls.includes("move")) {
onSelectedToolChange("move"); onSelectedToolChange("move");
} }
if (event.key === "d" && !disabledControls.includes("drawing")) { if (shortcuts.drawingTool(event) && !disabledControls.includes("drawing")) {
onSelectedToolChange("drawing"); onSelectedToolChange("drawing");
} }
if (event.key === "f" && !disabledControls.includes("fog")) { if (shortcuts.fogTool(event) && !disabledControls.includes("fog")) {
onSelectedToolChange("fog"); onSelectedToolChange("fog");
} }
if (event.key === "m" && !disabledControls.includes("measure")) { if (shortcuts.measureTool(event) && !disabledControls.includes("measure")) {
onSelectedToolChange("measure"); onSelectedToolChange("measure");
} }
if (event.key === "q" && !disabledControls.includes("pointer")) { if (shortcuts.pointerTool(event) && !disabledControls.includes("pointer")) {
onSelectedToolChange("pointer"); onSelectedToolChange("pointer");
} }
if (event.key === "n" && !disabledControls.includes("note")) { if (shortcuts.noteTool(event) && !disabledControls.includes("note")) {
onSelectedToolChange("note"); onSelectedToolChange("note");
} }
} }
function handleKeyUp(event) { function handleKeyUp(event) {
if (event.key === " " && selectedToolId === "move") { if (shortcuts.move(event) && selectedToolId === "move") {
onSelectedToolChange(previousSelectedToolRef.current); onSelectedToolChange(previousSelectedToolRef.current);
} }
} }

View File

@ -24,6 +24,8 @@ import Divider from "../../Divider";
import { useKeyboard } from "../../../contexts/KeyboardContext"; import { useKeyboard } from "../../../contexts/KeyboardContext";
import shortcuts from "../../../shortcuts";
function DrawingToolSettings({ function DrawingToolSettings({
settings, settings,
onSettingChange, onSettingChange,
@ -31,36 +33,26 @@ function DrawingToolSettings({
disabledActions, disabledActions,
}) { }) {
// Keyboard shotcuts // Keyboard shotcuts
function handleKeyDown({ key, ctrlKey, metaKey, shiftKey }) { function handleKeyDown(event) {
if (key === "b") { if (shortcuts.drawBrush(event)) {
onSettingChange({ type: "brush" }); onSettingChange({ type: "brush" });
} else if (key === "p") { } else if (shortcuts.drawPaint(event)) {
onSettingChange({ type: "paint" }); onSettingChange({ type: "paint" });
} else if (key === "l") { } else if (shortcuts.drawLine(event)) {
onSettingChange({ type: "line" }); onSettingChange({ type: "line" });
} else if (key === "r") { } else if (shortcuts.drawRect(event)) {
onSettingChange({ type: "rectangle" }); onSettingChange({ type: "rectangle" });
} else if (key === "c") { } else if (shortcuts.drawCircle(event)) {
onSettingChange({ type: "circle" }); onSettingChange({ type: "circle" });
} else if (key === "t") { } else if (shortcuts.drawTriangle(event)) {
onSettingChange({ type: "triangle" }); onSettingChange({ type: "triangle" });
} else if (key === "e") { } else if (shortcuts.drawErase(event)) {
onSettingChange({ type: "erase" }); onSettingChange({ type: "erase" });
} else if (key === "o") { } else if (shortcuts.drawBlend(event)) {
onSettingChange({ useBlending: !settings.useBlending }); onSettingChange({ useBlending: !settings.useBlending });
} else if ( } else if (shortcuts.redo(event) && !disabledActions.includes("redo")) {
(key === "z" || key === "Z") &&
(ctrlKey || metaKey) &&
shiftKey &&
!disabledActions.includes("redo")
) {
onToolAction("mapRedo"); onToolAction("mapRedo");
} else if ( } else if (shortcuts.undo(event) && !disabledActions.includes("undo")) {
key === "z" &&
(ctrlKey || metaKey) &&
!shiftKey &&
!disabledActions.includes("undo")
) {
onToolAction("mapUndo"); onToolAction("mapUndo");
} }
} }

View File

@ -22,6 +22,8 @@ import Divider from "../../Divider";
import { useKeyboard } from "../../../contexts/KeyboardContext"; import { useKeyboard } from "../../../contexts/KeyboardContext";
import shortcuts from "../../../shortcuts";
function BrushToolSettings({ function BrushToolSettings({
settings, settings,
onSettingChange, onSettingChange,
@ -29,36 +31,26 @@ function BrushToolSettings({
disabledActions, disabledActions,
}) { }) {
// Keyboard shortcuts // Keyboard shortcuts
function handleKeyDown({ key, ctrlKey, metaKey, shiftKey }) { function handleKeyDown(event) {
if (key === "p") { if (shortcuts.fogPolygon(event)) {
onSettingChange({ type: "polygon" }); onSettingChange({ type: "polygon" });
} else if (key === "b") { } else if (shortcuts.fogBrush(event)) {
onSettingChange({ type: "brush" }); onSettingChange({ type: "brush" });
} else if (key === "t") { } else if (shortcuts.fogToggle(event)) {
onSettingChange({ type: "toggle" }); onSettingChange({ type: "toggle" });
} else if (key === "e") { } else if (shortcuts.fogErase(event)) {
onSettingChange({ type: "remove" }); onSettingChange({ type: "remove" });
} else if (key === "l") { } else if (shortcuts.fogLayer(event)) {
onSettingChange({ multilayer: !settings.multilayer }); onSettingChange({ multilayer: !settings.multilayer });
} else if (key === "f") { } else if (shortcuts.fogPreview(event)) {
onSettingChange({ preview: !settings.preview }); onSettingChange({ preview: !settings.preview });
} else if (key === "c") { } else if (shortcuts.fogCut(event)) {
onSettingChange({ useFogCut: !settings.useFogCut }); onSettingChange({ useFogCut: !settings.useFogCut });
} else if (key === "r") { } else if (shortcuts.fogRectangle(event)) {
onSettingChange({ type: "rectangle" }); onSettingChange({ type: "rectangle" });
} else if ( } else if (shortcuts.redo(event) && !disabledActions.includes("redo")) {
(key === "z" || key === "Z") &&
(ctrlKey || metaKey) &&
shiftKey &&
!disabledActions.includes("redo")
) {
onToolAction("fogRedo"); onToolAction("fogRedo");
} else if ( } else if (shortcuts.undo(event) && !disabledActions.includes("undo")) {
key === "z" &&
(ctrlKey || metaKey) &&
!shiftKey &&
!disabledActions.includes("undo")
) {
onToolAction("fogUndo"); onToolAction("fogUndo");
} }
} }

View File

@ -4,6 +4,8 @@ import normalizeWheel from "normalize-wheel";
import { useKeyboard, useBlur } from "../contexts/KeyboardContext"; import { useKeyboard, useBlur } from "../contexts/KeyboardContext";
import shortcuts from "../shortcuts";
const wheelZoomSpeed = -1; const wheelZoomSpeed = -1;
const touchZoomSpeed = 0.005; const touchZoomSpeed = 0.005;
const minZoom = 0.1; const minZoom = 0.1;
@ -184,18 +186,14 @@ function useStageInteraction(
} }
); );
function handleKeyDown({ key, ctrlKey, metaKey }) { function handleKeyDown(event) {
// TODO: Find better way to detect whether keyboard event should fire. // TODO: Find better way to detect whether keyboard event should fire.
// This one fires on all open stages // This one fires on all open stages
if (preventInteraction) { if (preventInteraction) {
return; return;
} }
if ( if (shortcuts.stageZoomIn(event) || shortcuts.stageZoomOut(event)) {
(key === "=" || key === "+" || key === "-" || key === "_") && const pixelY = shortcuts.stageZoomIn(event) ? -100 : 100;
!ctrlKey &&
!metaKey
) {
const pixelY = key === "=" || key === "+" ? -100 : 100;
const newScale = Math.min( const newScale = Math.min(
Math.max( Math.max(
stageScale + stageScale +
@ -219,13 +217,13 @@ function useStageInteraction(
onStageScaleChange(newScale); onStageScaleChange(newScale);
} }
if (key === "Shift") { if (shortcuts.stagePrecisionZoom(event)) {
setZoomSpeed(0.25); setZoomSpeed(0.25);
} }
} }
function handleKeyUp({ key }) { function handleKeyUp(event) {
if (key === "Shift") { if (shortcuts.stagePrecisionZoom(event)) {
setZoomSpeed(1); setZoomSpeed(1);
} }
} }

View File

@ -28,6 +28,8 @@ import { useMapData } from "../contexts/MapDataContext";
import { useAuth } from "../contexts/AuthContext"; import { useAuth } from "../contexts/AuthContext";
import { useKeyboard, useBlur } from "../contexts/KeyboardContext"; import { useKeyboard, useBlur } from "../contexts/KeyboardContext";
import shortcuts from "../shortcuts";
const defaultMapProps = { const defaultMapProps = {
showGrid: false, showGrid: false,
snapToGrid: true, snapToGrid: true,
@ -345,17 +347,17 @@ function SelectMapModal({
/** /**
* Shortcuts * Shortcuts
*/ */
function handleKeyDown({ key }) { function handleKeyDown(event) {
if (!isOpen) { if (!isOpen) {
return; return;
} }
if (key === "Shift") { if (shortcuts.selectRange(event)) {
setSelectMode("range"); setSelectMode("range");
} }
if (key === "Control" || key === "Meta") { if (shortcuts.selectMultiple(event)) {
setSelectMode("multiple"); setSelectMode("multiple");
} }
if (key === "Backspace" || key === "Delete") { if (shortcuts.delete(event)) {
// Selected maps and none are default // Selected maps and none are default
if ( if (
selectedMapIds.length > 0 && selectedMapIds.length > 0 &&
@ -370,14 +372,14 @@ function SelectMapModal({
} }
} }
function handleKeyUp({ key }) { function handleKeyUp(event) {
if (!isOpen) { if (!isOpen) {
return; return;
} }
if (key === "Shift" && selectMode === "range") { if (shortcuts.selectRange(event) && selectMode === "range") {
setSelectMode("single"); setSelectMode("single");
} }
if ((key === "Control" || key === "Meta") && selectMode === "multiple") { if (shortcuts.selectMultiple(event) && selectMode === "multiple") {
setSelectMode("single"); setSelectMode("single");
} }
} }

View File

@ -22,6 +22,8 @@ import { useTokenData } from "../contexts/TokenDataContext";
import { useAuth } from "../contexts/AuthContext"; import { useAuth } from "../contexts/AuthContext";
import { useKeyboard, useBlur } from "../contexts/KeyboardContext"; import { useKeyboard, useBlur } from "../contexts/KeyboardContext";
import shortcuts from "../shortcuts";
function SelectTokensModal({ isOpen, onRequestClose }) { function SelectTokensModal({ isOpen, onRequestClose }) {
const { userId } = useAuth(); const { userId } = useAuth();
const { const {
@ -186,17 +188,17 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
/** /**
* Shortcuts * Shortcuts
*/ */
function handleKeyDown({ key }) { function handleKeyDown(event) {
if (!isOpen) { if (!isOpen) {
return; return;
} }
if (key === "Shift") { if (shortcuts.selectRange(event)) {
setSelectMode("range"); setSelectMode("range");
} }
if (key === "Control" || key === "Meta") { if (shortcuts.selectMultiple(event)) {
setSelectMode("multiple"); setSelectMode("multiple");
} }
if (key === "Backspace" || key === "Delete") { if (shortcuts.delete(event)) {
// Selected tokens and none are default // Selected tokens and none are default
if ( if (
selectedTokenIds.length > 0 && selectedTokenIds.length > 0 &&
@ -210,14 +212,14 @@ function SelectTokensModal({ isOpen, onRequestClose }) {
} }
} }
function handleKeyUp({ key }) { function handleKeyUp(event) {
if (!isOpen) { if (!isOpen) {
return; return;
} }
if (key === "Shift" && selectMode === "range") { if (shortcuts.selectRange(event) && selectMode === "range") {
setSelectMode("single"); setSelectMode("single");
} }
if ((key === "Control" || key === "Meta") && selectMode === "multiple") { if (shortcuts.selectMultiple(event) && selectMode === "multiple") {
setSelectMode("single"); setSelectMode("single");
} }
} }

110
src/shortcuts.js Normal file
View File

@ -0,0 +1,110 @@
/**
* @param {KeyboardEvent} event
* @returns {boolean}
*/
function hasModifier(event) {
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
}
/**
* Key press without any modifiers and ignoring capitals
* @param {KeyboardEvent} event
* @param {string} key
* @returns {boolean}
*/
function singleKey(event, key) {
return (
!hasModifier(event) &&
(event.key === key || event.key === key.toUpperCase())
);
}
/**
* @param {Keyboard} event
*/
function undo(event) {
const { key, ctrlKey, metaKey, shiftKey } = event;
return (key === "z" || key === "Z") && (ctrlKey || metaKey) && !shiftKey;
}
/**
* @param {Keyboard} event
*/
function redo(event) {
const { key, ctrlKey, metaKey, shiftKey } = event;
return (key === "z" || key === "Z") && (ctrlKey || metaKey) && shiftKey;
}
/**
* @param {Keyboard} event
*/
function zoomIn(event) {
const { key, ctrlKey, metaKey } = event;
return (key === "=" || key === "+") && !ctrlKey && !metaKey;
}
/**
* @param {Keyboard} event
*/
function zoomOut(event) {
const { key, ctrlKey, metaKey } = event;
return (key === "-" || key === "_") && !ctrlKey && !metaKey;
}
/**
* @callback shortcut
* @param {KeyboardEvent} event
* @returns {boolean}
*/
/**
* @type {Object.<string, shortcut>}
*/
const shortcuts = {
// Tools
move: (event) => singleKey(event, " "),
moveTool: (event) => singleKey(event, "w"),
drawingTool: (event) => singleKey(event, "d"),
fogTool: (event) => singleKey(event, "f"),
measureTool: (event) => singleKey(event, "m"),
pointerTool: (event) => singleKey(event, "q"),
noteTool: (event) => singleKey(event, "n"),
// Map editor
gridNudgeUp: ({ key }) => key === "ArrowUp",
gridNudgeLeft: ({ key }) => key === "ArrowLeft",
gridNudgeRight: ({ key }) => key === "ArrowRight",
gridNudgeDown: ({ key }) => key === "ArrowDown",
// Drawing tool
drawBrush: (event) => singleKey(event, "b"),
drawPaint: (event) => singleKey(event, "p"),
drawLine: (event) => singleKey(event, "l"),
drawRect: (event) => singleKey(event, "r"),
drawCircle: (event) => singleKey(event, "c"),
drawTriangle: (event) => singleKey(event, "t"),
drawErase: (event) => singleKey(event, "e"),
drawBlend: (event) => singleKey(event, "o"),
// Fog tool
fogPolygon: (event) => singleKey(event, "p"),
fogRectangle: (event) => singleKey(event, "r"),
fogBrush: (event) => singleKey(event, "b"),
fogToggle: (event) => singleKey(event, "t"),
fogErase: (event) => singleKey(event, "e"),
fogLayer: (event) => singleKey(event, "l"),
fogPreview: (event) => singleKey(event, "f"),
fogCut: (event) => singleKey(event, "c"),
fogFinishPolygon: ({ key }) => key === "Enter",
fogCancelPolygon: ({ key }) => key === "Escape",
// Stage interaction
stageZoomIn: zoomIn,
stageZoomOut: zoomOut,
stagePrecisionZoom: ({ key }) => key === "Shift",
// Select
selectRange: ({ key }) => key === "Shift",
selectMultiple: ({ key }) => key === "Control" || key === "Meta",
// Common
undo,
redo,
delete: ({ key }) => key === "Backspace" || key === "Delete",
};
export default shortcuts;