Keyboard Event Tester

Press any key to see every property your browser puts on the KeyboardEvent — key, code, location, modifier state, the deprecated numeric codes and both timestamps — plus a running event log you can filter and export.

Live event inspector

Capturing keyboard events. Focus this page and press any key.

Press any key. Every keydown, keypress and keyup on this page is inspected below.

Identity

type
key
code
location
repeat
isTrusted
isComposing
target

Modifier state

ctrlKey
shiftKey
altKey
metaKey
getModifierState('AltGraph')
getModifierState('CapsLock')
getModifierState('NumLock')
getModifierState('ScrollLock')

Timing

timeStamp (raw)
normalized to performance timeline
performance.now() in handler
handler delay (now − timeStamp)
since previous event

Browser-side values only. Measure browser input event latency properly with the main latency test.

Legacy numeric properties Deprecated

keyCode
which
charCode

Do not use these in new code. Use event.key for the character the user typed and event.code for the physical key. Browsers still populate these three for backward compatibility only; their values are inconsistent across browsers and keyboard layouts.

Matching code for the last key pressed

A ready-to-paste handler that matches exactly what you just pressed. It follows the most recent keydown, so releasing the key does not overwrite it.

// Press a key to generate a matching handler.

Dead key & IME scratch field

Dead keys and input method editors do not produce one key event per character. Watch the timeline below to see what your browser actually emits.

Event timeline

Events logged0
keydown0
keyup0
keypress0Deprecated event
Auto-repeat0

No events logged yet.

The most recent 500 events; older rows are discarded so the page stays responsive. t is milliseconds since the first logged event and Δ prev is the gap from the previous logged event, both taken from event.timeStamp normalised onto the performance.now() timeline. * composition covers compositionstart, compositionupdate and compositionend from the scratch field above.
# Type key code Modifiers t (ms) Δ prev
Press a key to start logging.
Advanced: last event as JSON

Every property this page reads, serialised. Handy for pasting into a bug report.

{}
Measurement environment

Timer resolution: High-resolution timing: Browser: Platform:

These conditions affect your result. A browser that rounds its clock to 1 ms cannot resolve sub-millisecond differences, so jitter will look artificially quantised. How we measure.

What this test cannot tell you

This inspector shows you the KeyboardEvent objects your browser hands to JavaScript, and nothing earlier. It cannot see switch actuation, keyboard firmware, matrix scanning, USB or Bluetooth transmission, driver behaviour, or how your operating system remapped a key before the browser saw it. Timestamps here describe browser-side timing, not keyboard hardware latency.

It also cannot show you a key event that never arrives. Combinations claimed by the OS or the browser are absent from the log entirely, and their absence is not evidence that your keyboard failed to send them.

Read the full methodology and limitations

key, code and keyCode: what each one actually means

event.key is the value the active keyboard layout produces — a character like "q", or a named value like "Enter", "ArrowLeft" or "Shift". It changes when the user switches layout, and it changes when a modifier is held: the same key gives "a" and "A".

event.code is the physical key position, named after where that key sits on a US QWERTY board. It does not change with the layout, the modifiers or the language. If you want WASD movement to work for a French user without remapping, code is the property you want.

One physical key, four layouts, one code.

The same physical key reported under four layouts. event.code is identical in every column.
event.code QWERTY key AZERTY key QWERTZ key Dvorak key
KeyQ"q""a""q""'"
KeyA"a""q""a""a"
KeyW"w""z""w"","
KeyZ"z""w""y"";"
KeyY"y""y""z""f"
Digit1"1""&""1""1"

Values shown are the unshifted event.key for a standard variant of each layout. Regional variants exist and can differ — press the key on your own machine and read the inspector above rather than trusting any table, including this one.

The third property, event.keyCode, is a legacy number. It predates both of the others, never behaved the same way in every browser, and is derived differently depending on the layout and the browser's compatibility rules. It is marked deprecated in the UI Events specification. Browsers still populate it for old code, but there is no reason to write new code against it.

Event order, and why keypress is deprecated

A single press of a character key normally produces keydown, then keypress, then keyup. Holding the key produces a stream of extra keydown events with repeat === true, at the interval your operating system's key-repeat setting defines — that is an OS setting, not a hardware property of the keyboard.

keypress is deprecated: it only fired for keys that produced a character, it never had consistent behaviour for modifier and function keys, and it does not handle text produced by input methods at all. For text input, listen to the input event on the field instead; for key handling, use keydown.

Modifier state is more than four booleans

ctrlKey, shiftKey, altKey and metaKey cover the common cases, but event.getModifierState(name) answers questions the booleans cannot. getModifierState('CapsLock') is how you detect the classic "your password looks wrong because Caps Lock is on" case. 'NumLock' and 'ScrollLock' report lock state the same way.

getModifierState('AltGraph') matters on European layouts, where AltGr produces characters such as @, and #. On Windows, AltGr is commonly reported as Ctrl and Alt held together, so a shortcut bound to Ctrl+Alt+E can steal a character a German or Polish user was simply trying to type. Checking getModifierState('AltGraph') and bailing out is the fix.

Shortcuts a web page can never capture

Some key combinations are consumed before any web page sees them. When that happens there is no event to inspect and no event to cancel — preventDefault() has nothing to act on, because your handler was never called. Which combinations are reserved depends on the operating system, the browser and the user's own settings, so treat the table below as typical behaviour rather than a guarantee.

Typical reservations. Behaviour varies by platform, browser and configuration.
CombinationUsually taken byReaches the page?
Ctrl+Alt+DelWindows secure attention sequenceNever
Alt+Tab, Cmd+TabOS window switcherNever
Windows / Cmd key combinationsOS shell (Win+L, Cmd+Space, …)Rarely
Ctrl+W, Ctrl+N, Ctrl+T, Ctrl+Shift+TBrowser tab and window managementUsually not
F11, F12, Ctrl+Shift+IBrowser fullscreen and developer toolsUsually not
Ctrl+Shift+EscWindows Task ManagerNever
Print Screen, media keysOS or hardware layerOften not, or partially

Combinations that do reach the page, such as Ctrl+S or Ctrl+P, can be intercepted with preventDefault() — but do it sparingly. Screen reader users depend on key combinations that look unremarkable to everyone else. Turn on shortcut capture above and try a few: anything that appears in the inspector is yours to claim, and anything that does not never will be.

Dead keys, IME composition and the 229 problem

A dead key produces no character on its own — it waits for the next keystroke to combine into an accented letter. Browsers usually report the dead key itself as event.key === "Dead", then deliver the composed character afterwards. Code that assumes one keystroke equals one character will mis-handle it.

Input method editors, used for Japanese, Chinese, Korean and other scripts, go further: a whole sequence of keystrokes belongs to an in-progress composition. While that is happening, event.isComposing is true, and many browsers report event.key as "Process" with the legacy keyCode set to 229. If your shortcut handler ignores that, pressing Enter to confirm a candidate word will also fire your "submit" shortcut. Guard with if (event.isComposing) return; and prefer the compositionstart and compositionend events when you need the boundaries. The scratch field above logs all three so you can see the real sequence your browser emits.

What event.timeStamp is and is not

KeyboardEvent.timeStamp is a DOMHighResTimeStamp on the same monotonic timeline as performance.now(), stamped when the browser creates the event object. Subtracting it from a performance.now() reading taken at the top of your handler gives you the browser-side queueing and main-thread scheduling delay — the handler delay figure in the inspector above.

It is not the moment the switch closed. Everything before the browser — the keyboard's own scanning and firmware, the USB or Bluetooth link, the OS input stack — is already finished by the time that number exists, and none of it is visible from JavaScript. Some engines also hand back an epoch-scale value instead of a page-relative one, which is why this page normalises the timestamp before showing it. The browser input latency test uses the same normalised figure across many samples, and browser keyboard event timing explains the pipeline in full.

Related keyboard tests

Frequently asked questions

Should I use event.key or event.code for a keyboard shortcut?

Use event.code when the physical position of the key is what matters, such as WASD movement in a game, because it stays the same on every layout. Use event.key when the character the user actually typed is what matters, such as pressing the letter S to save. For a shortcut like Ctrl+S, event.key is usually the better choice, because a user on AZERTY expects the key labelled S to work.

Why does event.key change when I switch keyboard layouts?

event.key reports the character or named value the active layout produces, so the same physical key gives "q" on QWERTY and "a" on AZERTY. event.code reports the physical key position using US QWERTY names, so that same key stays KeyQ on every layout. Neither is wrong; they answer different questions.

Why is event.keyCode deprecated, and what should I use instead?

keyCode, charCode and which are legacy numeric properties that never had consistent cross-browser or cross-layout behaviour, which is why the UI Events specification marks them deprecated. Browsers still populate them for compatibility, so old code keeps working, but new code should use event.key for the character and event.code for the physical key.

Why can't this page capture Ctrl+W, Alt+Tab or the Windows key?

Some combinations are claimed by the operating system or the browser before any page sees them, so no keydown event is ever delivered to JavaScript. Alt+Tab and Ctrl+Alt+Del are handled by the OS, and tab and window management shortcuts are usually handled by the browser. Because the event never reaches the page, calling preventDefault() cannot override them. Exactly which combinations are reserved varies by browser, operating system and user configuration.

What is event.isComposing and why do my keydown handlers misfire with an IME?

When an input method editor is composing text, for example when typing Japanese or Chinese, keystrokes belong to the composition rather than to your shortcut. During composition, event.isComposing is true and many browsers report event.key as "Process" with a legacy keyCode of 229. Ignoring keydown events while event.isComposing is true prevents shortcuts firing in the middle of someone's word.

Is event.timeStamp the time the key was physically pressed?

No. event.timeStamp is stamped when the browser creates the event object, after the operating system has already delivered the input to the browser. It does not include switch actuation, keyboard firmware, USB or Bluetooth transmission, or OS scheduling. It is useful for measuring browser-side ordering and delay, and this page shows it on the same timeline as performance.now() so you can compare the two directly.