Input
Irregular • File:
InputCapture.csv• Writer:KeyCodeDataWriter.cs
At a glance
Input captures key input events for keys configured on the KeyCodeDataCapture asset. Emits on key-down, key-up, and optionally key-held (every N samples while held). Each row records the key code and the event type. Stamped at the frame the input was polled.
Use Input for:
- Reaction-time analyses (stimulus → key press).
- Response logging (which key did they press?).
- Keyboard / controller event timelines.
When it writes
KeyCodeInputObserver detects configured key events and fires OnInputEvent. The writer picks that up via RecordEntry. Timing is stamped at the frame of detection — so FrameNumber is the frame on which Unity reported the input state change.
File & location
- Default:
InputCapture.csvin the run directory. - Writer:
KeyCodeDataWriter.csinRuntime/DataCapture/InputLogging/. - Observer:
KeyCodeInputObserver.cs(same directory). - Observation:
Runtime/DataCapture/DataModels/KeyCodeObservation.cs. - Config SO:
KeyCodeDataCapture.cs.
Configuration
KeyCodeDataCapture SO fields:
| Field | What it does |
|---|---|
enabledLogging | Master enable/disable. |
fileName | Override the default name. |
flushEveryNRows | Batched flush cadence. Default 30. |
writeHeader | Write the header row on first emission. Default true. |
samplingLoop | Update / FixedUpdate / Both. |
keyCodes | List<KeyCode> of keys to observe. Only these keys are logged. |
holdMode | Off (no held rows) / SampleWhileHeld (periodic rows while held) / StateTransitionsOnly (down + up only). |
emitHeldEveryNSamples | When holdMode = SampleWhileHeld, emit a held row every Nth poll. Min 1, default 1. |
Note: KeyCodeDataCapture is its own ScriptableObject — not a subclass of DataCaptureConfig. Same field names but separate inheritance.
Columns
Shared prefix
See Column conventions — The shared prefix.
Domain columns
| Column | Type | Description |
|---|---|---|
timeSeconds | double | Time at which the input was polled. Typically matches ObservationTime from the shared prefix. |
frame | int | The frame the input was polled. Typically matches FrameNumber from the shared prefix. |
isFixedTimeStep | int | 1 if the poll happened during FixedUpdate, 0 for Update. |
keyCode | string | Name of the KeyCode (e.g. Space, Return, A, Mouse0). |
eventType | string | KeyDown, KeyUp, or KeyHeld. |
Sample rows
...shared...,timeSeconds,frame,isFixedTimeStep,keyCode,eventType
...,12.345,745,0,Space,KeyDown
...,12.387,748,0,Space,KeyUp
...,12.390,749,0,Return,KeyDown
Join with other streams
Classic reaction-time pattern — pair a stimulus-onset event with the next key-down:
import pandas as pd
events = pd.read_csv("EventPoints.csv")
inputs = pd.read_csv("InputCapture.csv")
stim = events[events["Event_Description"] == "Stimulus flash"].sort_values("MonotonicExecutionTime")
keys = inputs[inputs["eventType"] == "KeyDown"].sort_values("MonotonicExecutionTime")
# For each stimulus, find the first KeyDown after it:
pairs = pd.merge_asof(
stim,
keys,
on="MonotonicExecutionTime",
direction="forward",
suffixes=("_stim", "_key"),
)
pairs["reaction_time_s"] = pairs["MonotonicExecutionTime_key"] - pairs["MonotonicExecutionTime_stim"]
See Reaction time recipe for the full pattern.
Gotchas
- Only configured keys are logged. If a key isn't in the SO's
keyCodeslist, its presses are invisible to the CSV. Easy mistake if you added a key to the experience but forgot to add it to the capture config. SampleWhileHeldcan be chatty. WithholdMode = SampleWhileHeldandemitHeldEveryNSamples = 1, a held key emits a row every poll — expect potentially very large files. Either raiseemitHeldEveryNSamplesor useStateTransitionsOnlyfor dwell analysis (compute duration from KeyDown / KeyUp pairs).timeSeconds/frameduplicate shared columns. They mostly equalObservationTimeandFrameNumberfrom the shared prefix. Treat shared-prefix values as authoritative.isFixedTimeStepis rarely1. Input polling is typically inUpdate, notFixedUpdate. If you seeisFixedTimeStep = 1, that's an unusual config — double-check.- Stamped at the frame of polling, not the hardware moment. If Unity missed an input on a slow frame, the reported time is the frame Unity observed it — which may be a frame or two late vs. actual finger-down. For sub-frame accuracy, couple this with display-offset correction — see Timing.
Analysis recipes
- Reaction time — the canonical Input use case.
- Stimulus-locked averaging — use key presses as trial markers to segment regular-stream data.