Skip to content
LinuxDeep Dive Published Updated 6 min readViews unavailable

Linux evdev: Event Codes, SYN_REPORT Boundaries, and State Recovery

Consume Linux evdev streams by decoding event types, respecting SYN_REPORT frames, recovering after SYN_DROPPED, and identifying hotplugged devices.

Linux input devices expose events through the evdev interface, usually as /dev/input/eventN. The stream is a sequence of typed records, not a text log and not a direct copy of physical switch transitions. A keyboard driver, touch controller, mouse, game controller, or userspace virtual device can produce the same event codes through different hardware paths. Correct consumers interpret event type and code, honor synchronization boundaries, and recover when their per-client event queue overflows.

The event number is an enumeration detail that can change after reboot or hotplug. Robust software identifies devices by stable metadata such as name, physical path, bus/vendor/product IDs, and udev properties instead of hard-coding event0.

Discover the device before reading events

List input devices and their identity:

ls -l /dev/input/
cat /proc/bus/input/devices
udevadm info --query=property --name=/dev/input/eventN

Use the event node identified through the device’s attributes; do not assume the same N after restart. The input core can create multiple event nodes for one physical device, and one composite device can expose keyboard, touch, sensor, or consumer-control interfaces separately. Device permissions and access policy are separate from event semantics.

Tools such as evtest or libinput list-devices can show capabilities and decoded events where installed. Their output depends on the tool version and device access. A kernel event stream is low-level; desktop input frameworks may apply acceleration, gesture recognition, key mapping, or device classification after evdev.

Inspect device capabilities before interpreting events. The kernel reports supported event types and codes through ioctl queries. A device that supports EV_ABS can expose absolute axes with ranges and fuzz/flat values; one that supports EV_REL reports relative movement. The same numeric code is meaningful only in its event-type namespace. Do not interpret an EV_ABS code as a key code because their integer values overlap.

Event records and synchronization frames

Each evdev record includes a timestamp, event type, event code, and value. The timestamp reflects the kernel input event timing model selected by the device/client path; it is not automatically the instant a physical sensor sampled the signal. Userspace scheduling and buffering can delay when a client reads the record. Use monotonic time semantics where configured and preserve the clock source with captured data.

Events are often grouped into logical frames terminated by EV_SYN with SYN_REPORT. A touch device may report several absolute-axis updates and contact state changes, then issue one synchronization event to indicate that the current packet of state updates is complete. A consumer that reacts to every individual axis update as a complete gesture can observe partial states and produce inconsistent behavior.

SYN_REPORT is a framing boundary, not a guarantee that all hardware sensors sampled simultaneously. Applications should accumulate changes until the synchronization event and then process the resulting state transition. Some devices may produce additional synchronization codes for specialized behavior; consult the current input-event documentation and device protocol.

Key values are conventionally press, release, and repeat. A repeat event is not a new physical key-down transition. Relative motion values are signed deltas; absolute values are positions that require the reported range and calibration. Switch and tool-type codes carry state rather than movement. Decode each code using the kernel’s event-code tables and device capabilities.

Handle queue overflow with SYN_DROPPED

Each evdev client has a finite event queue. If the client does not read fast enough, records can be lost. The kernel reports SYN_DROPPED to signal that the stream’s state history is no longer complete. A consumer must not continue applying subsequent deltas as if nothing happened.

On SYN_DROPPED, ignore events through the next SYN_REPORT as described by the kernel interface, then query current state using the appropriate EVIOCG* ioctls for that device. For example, a keyboard consumer can request key state, while a touch device may require querying absolute values and multitouch slot state. The exact set of queries depends on the device and event types. If a reliable state query is unavailable, reset application state and wait for a known synchronization point rather than fabricating missed transitions.

A robust consumer records overflow count, event rate, processing latency, and whether state resynchronization succeeded. It should size its own processing pipeline and read promptly, but increasing a buffer does not fix sustained overload. If the producer’s long-term event rate exceeds the consumer’s capacity, backlog will recur.

Device identity and hotplug

eventN names are allocated dynamically. A daemon should discover devices through udev or the appropriate desktop input framework and match stable properties. A phys path can help distinguish identical USB peripherals on different ports; product name alone may not be unique. Device firmware updates can change identifiers, so keep matching rules explicit and test them against all supported revisions.

Handle removal as a lifecycle event. A read may return an error or hangup after unplug; close the file descriptor, discard stale per-device state, and wait for rediscovery. Do not assume reconnecting hardware receives the same event number. For USB devices, correlate bus topology and interface identity; for built-in devices, use the firmware node or platform path where available.

If a desktop does not react to input, first verify the kernel event node receives correct records. Then trace whether the user session is allowed to open it and whether the compositor or input service recognizes the capabilities. A desktop policy bug should not be debugged by changing the kernel device mapping blindly.

Common failure patterns

No event data. Confirm the correct node, supported event codes, device state, and permissions. Check whether another program has grabbed the device exclusively, where that behavior is supported.

Coordinates or axes are wrong. Check EV_ABS ranges, calibration, multitouch slots, and device orientation. Raw values may need transformation by a higher input layer.

Keys repeat unexpectedly. Distinguish repeat value from press/release and inspect input repeat configuration. Do not count repeats as physical key-downs.

Gestures jump or stick. Check whether the application honors SYN_REPORT, processes multitouch slots correctly, and resets after SYN_DROPPED.

Works after reboot only sometimes. The event number can change. Replace hard-coded node paths with stable discovery and validate udev matching.

Timestamps disagree with wall time. The event clock may be monotonic and may have a different origin. Configure or interpret the selected clock explicitly; do not compare raw timestamps directly with local wall-clock strings.

Build a trustworthy event consumer

At initialization, query device identity, supported event types/codes, axis ranges, and timestamp clock. Allocate a reader that handles partial reads, interruptions, removal, and queue overflow. Parse records according to event type, accumulate state within a frame, and publish only after synchronization. Keep event processing bounded so a slow downstream consumer cannot stop draining the kernel queue.

Test with a representative device and known sequence: press, release, repeat, motion, contact begin/end, unplug, and reconnect. Exercise SYN_DROPPED with a controlled test harness or artificially slow reader on a development system. Verify the application re-queries state and does not leave keys logically held or pointers stuck after an overflow.

For a production incident, preserve the kernel version, device identity, evdev node, capability query, raw event capture, event clock, overflow count, and userspace framework version. Event data can reveal user actions or input patterns, so handle captures according to privacy policy.

The safe model is a framed event stream with bounded queues and dynamic device identities. SYN_REPORT closes a state update frame; SYN_DROPPED invalidates the history; and eventN is temporary. Honor those properties and your input consumer can recover from both normal hotplug and overload without inventing state.

Related:

Sources:

Comments