Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions client/src/pages/tools/keyboard-test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useEffect, useCallback } from "react";
import { useState, useEffect, useCallback, useRef } from "react";
import { getToolByPath } from "@/data/tools";
import { ToolExplanations } from "@/components/tool-explanations";
import { ShortcutBadge } from "@/components/ui/shortcut-badge";
Expand All @@ -22,6 +22,7 @@ export default function KeyboardTest() {
const [pressedKeys, setPressedKeys] = useState<Set<string>>(new Set());
const [keyHistory, setKeyHistory] = useState<KeyPress[]>([]);
const [isActive, setIsActive] = useState(true);
const focusAreaRef = useRef<HTMLDivElement>(null);

const handleKeyDown = useCallback(
(event: KeyboardEvent) => {
Expand Down Expand Up @@ -59,6 +60,8 @@ export default function KeyboardTest() {
if (isActive) {
window.addEventListener("keydown", handleKeyDown);
window.addEventListener("keyup", handleKeyUp);
// Auto-focus the focus area when testing becomes active
focusAreaRef.current?.focus();
}

return () => {
Expand Down Expand Up @@ -221,10 +224,21 @@ export default function KeyboardTest() {
<h3 className="text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
Currently Pressed ({pressedKeys.size})
</h3>
<div className="min-h-[60px] p-4 bg-slate-50 dark:bg-slate-800 border border-slate-200 dark:border-slate-700 flex flex-wrap gap-2">
<div
ref={focusAreaRef}
tabIndex={isActive ? 0 : -1}
className={`min-h-[60px] p-4 bg-slate-50 dark:bg-slate-800 border-2 flex flex-wrap gap-2 outline-none transition-colors ${
isActive
? "border-blue-500 dark:border-blue-400 focus:ring-2 focus:ring-blue-500/50 cursor-text"
: "border-slate-200 dark:border-slate-700"
}`}
data-testid="keyboard-focus-area"
>
Comment on lines +227 to +236
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The focusable div should include accessibility attributes for screen reader users. Consider adding role="region" and aria-label="Keyboard test input area" to improve accessibility. This helps screen reader users understand the purpose of the focusable element.

Example:

<div
  ref={focusAreaRef}
  role="region"
  aria-label="Keyboard test input area"
  tabIndex={isActive ? 0 : -1}
  // ... rest of props
>

Copilot uses AI. Check for mistakes.
{pressedKeys.size === 0 ? (
<div className="text-slate-500 dark:text-slate-400 italic">
No keys currently pressed
{isActive
? "Click here and start typing to test your keyboard..."
: "No keys currently pressed"}
</div>
) : (
Array.from(pressedKeys).map(code => {
Expand Down
22 changes: 22 additions & 0 deletions tests/e2e/tools/keyboard-test.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,26 @@ test.describe("Keyboard Test Tool", () => {
await expect(page.locator("main")).toBeVisible();
await expectNoErrors(page);
});

test("should auto-focus the keyboard input area on load", async ({
page,
}) => {
const focusArea = page.getByTestId("keyboard-focus-area");
await expect(focusArea).toBeVisible();
await expect(focusArea).toBeFocused();
});

test("should auto-focus when starting testing after stopping", async ({
page,
}) => {
const focusArea = page.getByTestId("keyboard-focus-area");

// Stop testing
await page.getByRole("button", { name: /stop testing/i }).click();
await expect(focusArea).not.toBeFocused();

// Start testing again
await page.getByRole("button", { name: /start testing/i }).click();
await expect(focusArea).toBeFocused();
});
});