Reputation: 1
I am building a shortcut practice application using React and am encountering a bug that I don't understand. To detect when a wrong combination is entered, I validate the maximum length of the key sequence and use validateCombination() when the length returns to 0 to check if it is incorrect. This works well, except when modifier keys are the last keys released, in which case it does not detect the wrong combination.
import React, { useEffect } from "react";
import { vsCodeShortchutMac } from "./shortcutData";
interface KeySequenceListenerProps {
keySequence: string;
setInputHistory: React.Dispatch<React.SetStateAction<{ text: string; status: "skipped" | "found" | "wrong" }[]>>;
inputHistory: { text: string; status: "skipped" | "found" | "wrong" }[];
currentShortcutIndex: number;
gameStarted: boolean;
}
const BadShortcut: React.FC<KeySequenceListenerProps> = ({
inputHistory,
setInputHistory,
currentShortcutIndex,
gameStarted,
}) => {
let numberOfKeysStillPressed = 0;
let currentKeys = "";
const currentShortcut = vsCodeShortchutMac[currentShortcutIndex];
const pressedKeys = new Set<string>(); // Track pressed keys
useEffect(() => {
if (!gameStarted) return;
const handleKeyDown = (e: KeyboardEvent) => {
e.preventDefault();
if (!pressedKeys.has(e.key)) {
pressedKeys.add(e.key);
currentKeys += e.key;
numberOfKeysStillPressed++;
console.log(`Key down: ${e.key}, currentKeys: ${currentKeys}, numberOfKeysStillPressed: ${numberOfKeysStillPressed}`);
}
};
const handleKeyUp = (e: KeyboardEvent) => {
e.preventDefault();
console.log(`Key up event: ${e.key}`); // Debugging log
if (pressedKeys.has(e.key)) {
pressedKeys.delete(e.key);
numberOfKeysStillPressed--;
console.log(`Key up: ${e.key}, numberOfKeysStillPressed: ${numberOfKeysStillPressed}`);
if (numberOfKeysStillPressed <= 0) {
validateCombination();
currentKeys = "";
numberOfKeysStillPressed = 0;
}
}
};
const validateCombination = () => {
if (currentKeys !== currentShortcut.key) {
const wrongKey = `${currentKeys} - (Wrong)`;
setInputHistory((prev) => [
...prev,
{ text: wrongKey, status: "wrong" },
]);
}
console.log("Reset currentKeys");
};
document.addEventListener("keydown", handleKeyDown);
document.addEventListener("keyup", handleKeyUp);
return () => {
document.removeEventListener("keydown", handleKeyDown);
document.removeEventListener("keyup", handleKeyUp);
};
}, [gameStarted, currentShortcut.key, setInputHistory, inputHistory, currentKeys]);
return null;
};
export default BadShortcut;
You can see in the log that when I release the modifier key last, it does not detect it, but with regular characters it will.
BadShortcut.tsx:32 Key down: Shift, currentKeys: Shift, numberOfKeysStillPressed: 1
BadShortcut.tsx:32 Key down: A, currentKeys: ShiftA, numberOfKeysStillPressed: 2
BadShortcut.tsx:38 Key up event: A
BadShortcut.tsx:42 Key up: A, numberOfKeysStillPressed: 1
BadShortcut.tsx:38 Key up event: Shift
BadShortcut.tsx:42 Key up: Shift, numberOfKeysStillPressed: 0
BadShortcut.tsx:59 Reset currentKeys
BadShortcut.tsx:32 Key down: a, currentKeys: a, numberOfKeysStillPressed: 1
BadShortcut.tsx:32 Key down: Shift, currentKeys: aShift, numberOfKeysStillPressed: 2
BadShortcut.tsx:38 Key up event: A
BadShortcut.tsx:38 Key up event: Shift
BadShortcut.tsx:42 Key up: Shift, numberOfKeysStillPressed: 1
BadShortcut.tsx:32 Key down: Shift, currentKeys: aShiftShift, numberOfKeysStillPressed: 2
BadShortcut.tsx:38 Key up event: A
BadShortcut.tsx:38 Key up event: Shift
BadShortcut.tsx:42 Key up: Shift, numberOfKeysStillPressed: 1
BadShortcut.tsx:32 Key down: Shift, currentKeys: aShiftShiftShift, numberOfKeysStillPressed: 2
BadShortcut.tsx:32 Key down: A, currentKeys: aShiftShiftShiftA, numberOfKeysStillPressed: 3
BadShortcut.tsx:38 Key up event: A
BadShortcut.tsx:42 Key up: A, numberOfKeysStillPressed: 2
BadShortcut.tsx:38 Key up event: Shift
BadShortcut.tsx:42 Key up: Shift, numberOfKeysStillPressed: 1
Upvotes: 0
Views: 31