A single HTML file implements a full-size 108-key keyboard testing tool that monitors key presses in real time and provides APM (Actions Per Minute) statistics and visualization.
-
Keyboard Layout Rendering Builds a standard full-size keyboard (main cluster, navigation cluster, numpad) with 108 physical keys (including function keys, editing keys, arrow keys, and numpad). Each key is dynamically generated with CSS Grid and Flex layouts, with responsive sizing (
clampunits). -
Real-time Key Monitoring Listens to
keydown/keyupevents, accurately maps them to the corresponding DOM element based onevent.codeandevent.location, and synchronizes visual feedback:- On press → black background, white text (
activeclass) - After release → gray background (
hitclass), indicating the key has been triggered - Not triggered → white background
- On press → black background, white text (
-
Statistics The top bar shows five metrics:
- Instant APM: number of key presses within the last 1 second converted to a per-minute rate
- Peak APM: highest instant value recorded
- Total Triggers: cumulative key press count (including repeats)
- Keys Tested: number of distinct keys triggered / total mappable keys
- Last Key: shows the last triggered key name, raw
code, andlocationvalue (useful for diagnosis)
-
Lock State Indicators Automatically reads
CapsLock,NumLock,ScrollLockstates and displays them via LED dots and the small dots at the top-right corner of the corresponding keys. -
APM Curve Drawn on Canvas, samples the instant APM every 500ms, keeping the most recent 120 points (a 60-second window). The curve scrolls and updates, showing the current instant value.
-
Reset Function One-click clears all statistics, curve data, and key highlight states, restoring the initial state.
- Uses a hybrid Flex and CSS Grid layout. The top
topbarcontains the curve chart and statistic cards; the middle keyboard body is divided intomain(main key column),nav(navigation column), andnumpad-col(numpad column). - Key sizes are controlled by the CSS variable
--u(clamp(24px, 4.3vw, 50px)), adapting to different screen sizes. - Keys spanning rows/columns (e.g., numpad
+,Enter,0) are implemented viagrid-row: span 2orgrid-column: span 2.
- All keys are defined in a JavaScript array. Each key object contains
label(display text),code(correspondingevent.code),w(width multiplier, supporting 1.25, 1.5, 2.25, etc.), andcls(extra class, such astall/wide). - The navigation area includes
spacerplaceholder elements to keep rows and columns aligned. - During rendering, the data is traversed to generate the DOM, and a mapping table from
codeto DOM element (codeMap) is built for fast lookup in event callbacks.
- Modifier Key Left/Right Distinction
For
Shift,Control,Alt,Meta,event.location(LEFT=1/RIGHT=2) is used first to determine left/right, avoiding reliance solely onevent.code(some systems or IMEs may misreport). Whenlocationis0(cannot be determined) andcodeis empty, it is judged as an abnormal injected event (e.g., right Shift hijacked), and handled as the right key. - Prevent Default Behavior
Calls
preventDefault()for Space, arrow keys, Tab, Backspace, function keys, etc., to prevent page scrolling or focus switching, ensuring the test is not disturbed. - Blur Handling
When the page loses focus (e.g., pressing the Win key pops up a menu), clears all keys'
activestate to avoid a "stuck key" illusion.
- Instant APM: maintains a timestamp array
hitsrecording theperformance.now()timestamp of each key press. When calculating, take the count within the last 1 second and multiply by 60 to convert to a per-minute rate. - Peak APM: compares the instant value after each update and keeps the maximum.
- Curve Chart:
- Samples the instant APM every 500ms, stored in the ring buffer
apmBuf(max 120 points). - When drawing, the Y-axis uses integer multiples of 60 as the tick upper limit (dynamically rounded), and the X-axis scrolls from right to left (newest point fixed at the far right).
- Includes grid lines, fill area, and polyline, highlighting the current value.
- Samples the instant APM every 500ms, stored in the ring buffer
- In
keydownandkeyup, callse.getModifierState()to get the three lock key states and update the LED indicators and small dots on the keys.
| Action | Visual Feedback | Statistics Update |
|---|---|---|
| Press any key | The corresponding key turns black background, white text (active), and is immediately marked as "triggered" (add hit class, gray background retained after release) |
Record timestamp, total count +1, update instant APM, peak, last key, keys tested |
| Release key | Black background removed, gray background retained | No new statistics (but lock state may change) |
| Toggle lock key | LED and key dots sync on/off | None |
| Page loses focus | All black backgrounds cleared | None |
| Reset button | All keys cleared of black and gray backgrounds | Clear all statistics, curve cache, APM reset to zero |
Key Design:
- Adding the
hitclass inkeydownensures the "triggered" mark is retained even if thekeyupevent is lost (e.g., Win key pops up the Start menu). - The last key display includes
codeandlocationfor debugging key mapping correctness.
-
Accuracy and Compatibility
- Compatible with key differences across operating systems and browsers (e.g., Mac's Meta key).
- Double-checks modifier key left/right position (location + code) to adapt to IME hijacking scenarios.
-
Intuitive Visual Feedback
- Three-state colors (white/black/gray) clearly distinguish "not triggered / pressed / triggered".
- Lock key dots sync with system state with no delay.
-
Performance Optimization
- Uses
performance.now()instead ofDate.now()for higher precision. - Timer intervals (250ms for stats update, 500ms for curve sampling) balance smoothness and performance.
- Uses
-
Responsive Design
- Key sizes change with the viewport, displaying well on phones, tablets, and desktops.
- Canvas adjusts resolution based on devicePixelRatio to ensure clarity on high-DPI screens.
-
User Guidance
- Bottom hint explains the color meanings and functions, lowering the usage threshold.
