0
# Device Operations
1
2
Core functionality for discovering, opening, and interacting with Linux input devices. This includes device enumeration, capability querying, event reading, and device control operations.
3
4
## Capabilities
5
6
### Device Discovery
7
8
Functions for finding and identifying available input devices on the system.
9
10
```python { .api }
11
def list_devices(input_device_dir: Union[str, bytes, os.PathLike] = "/dev/input") -> List[str]:
12
"""
13
List readable character devices in input_device_dir.
14
15
Parameters:
16
- input_device_dir: Directory to search for input devices (default: "/dev/input")
17
18
Returns:
19
List of device paths (e.g., ["/dev/input/event0", "/dev/input/event1"])
20
"""
21
```
22
23
### Device Initialization
24
25
Opening and initializing input device connections.
26
27
```python { .api }
28
class InputDevice:
29
def __init__(self, dev: Union[str, bytes, os.PathLike]) -> None:
30
"""
31
Initialize InputDevice with device path.
32
33
Parameters:
34
- dev: Path to input device (e.g., "/dev/input/event0")
35
36
Raises:
37
- EvdevError: If device cannot be opened or accessed
38
"""
39
40
def close(self) -> None:
41
"""Close the device file descriptor and release resources."""
42
43
def fileno(self) -> int:
44
"""
45
Return file descriptor for the device.
46
Enables use with select.select() and asyncore.file_dispatcher.
47
"""
48
```
49
50
### Device Information
51
52
Methods for querying device properties, capabilities, and status information.
53
54
```python { .api }
55
class InputDevice:
56
@property
57
def path(self) -> str:
58
"""Path to the input device."""
59
60
@property
61
def fd(self) -> int:
62
"""File descriptor to the device."""
63
64
@property
65
def info(self) -> DeviceInfo:
66
"""Device identification information (vendor, product, etc.)."""
67
68
@property
69
def name(self) -> str:
70
"""Device name as reported by the kernel."""
71
72
@property
73
def phys(self) -> str:
74
"""Physical topology of the device."""
75
76
@property
77
def uniq(self) -> str:
78
"""Unique identifier for the device."""
79
80
@property
81
def version(self) -> int:
82
"""Evdev protocol version supported by the device."""
83
84
@property
85
def ff_effects_count(self) -> int:
86
"""Number of force feedback effects the device can store."""
87
88
def capabilities(self, verbose: bool = False, absinfo: bool = True) -> Dict:
89
"""
90
Get device capabilities and supported event types.
91
92
Parameters:
93
- verbose: Return human-readable names instead of numeric codes
94
- absinfo: Include AbsInfo for absolute axes
95
96
Returns:
97
Dictionary mapping event types to lists of supported event codes.
98
For absolute axes, includes (code, AbsInfo) tuples when absinfo=True.
99
"""
100
101
def input_props(self, verbose: bool = False) -> List:
102
"""
103
Get device input properties and quirks.
104
105
Parameters:
106
- verbose: Return human-readable names instead of numeric codes
107
108
Returns:
109
List of input property flags
110
"""
111
```
112
113
### Event Reading
114
115
Methods for reading input events from devices.
116
117
```python { .api }
118
class InputDevice:
119
def read_loop(self) -> Iterator[InputEvent]:
120
"""
121
Enter endless select() loop yielding input events.
122
Blocks until events are available.
123
"""
124
125
def read_one(self) -> Union[InputEvent, None]:
126
"""
127
Read single input event from device.
128
129
Returns:
130
InputEvent if available, None if no events pending
131
"""
132
133
def read(self) -> List[InputEvent]:
134
"""
135
Read multiple input events from device.
136
137
Returns:
138
List of available InputEvent objects
139
"""
140
```
141
142
### Device Control
143
144
Operations for controlling device behavior and state.
145
146
```python { .api }
147
class InputDevice:
148
def grab(self) -> None:
149
"""
150
Grant exclusive access to device using EVIOCGRAB ioctl.
151
Prevents other processes from receiving events from this device.
152
153
Raises:
154
- EvdevError: If grab fails (device already grabbed, insufficient permissions)
155
"""
156
157
def ungrab(self) -> None:
158
"""
159
Release exclusive access to device.
160
Allows other processes to receive events again.
161
"""
162
163
def grab_context(self):
164
"""
165
Context manager for device grabbing.
166
Automatically releases grab when exiting context.
167
168
Usage:
169
with device.grab_context():
170
# Device is exclusively grabbed
171
for event in device.read_loop():
172
process_event(event)
173
# Device is automatically ungrabbed
174
"""
175
```
176
177
### LED and Output Control
178
179
Methods for controlling device LEDs and output features.
180
181
```python { .api }
182
class InputDevice:
183
def leds(self, verbose: bool = False) -> List:
184
"""
185
Return currently active LED keys.
186
187
Parameters:
188
- verbose: Return human-readable names instead of numeric codes
189
190
Returns:
191
List of active LED codes/names
192
"""
193
194
def set_led(self, led_num: int, value: int) -> None:
195
"""
196
Set LED state on device.
197
198
Parameters:
199
- led_num: LED code (from ecodes.LED_*)
200
- value: LED state (0=off, 1=on)
201
"""
202
203
def active_keys(self, verbose: bool = False) -> List:
204
"""
205
Return currently pressed/active keys.
206
207
Parameters:
208
- verbose: Return human-readable names instead of numeric codes
209
210
Returns:
211
List of active key codes/names
212
"""
213
```
214
215
### Absolute Axis Control
216
217
Methods for working with absolute positioning devices (touchscreens, joysticks).
218
219
```python { .api }
220
class InputDevice:
221
def absinfo(self, axis_num: int) -> AbsInfo:
222
"""
223
Return AbsInfo for specified absolute axis.
224
225
Parameters:
226
- axis_num: Absolute axis code (from ecodes.ABS_*)
227
228
Returns:
229
AbsInfo namedtuple with axis information
230
"""
231
232
def set_absinfo(self, axis_num: int, value=None, min=None, max=None, fuzz=None, flat=None, resolution=None) -> None:
233
"""
234
Update AbsInfo values for absolute axis.
235
236
Parameters:
237
- axis_num: Absolute axis code (from ecodes.ABS_*)
238
- value: Current value (optional)
239
- min: Minimum value (optional)
240
- max: Maximum value (optional)
241
- fuzz: Fuzz value for noise filtering (optional)
242
- flat: Flat value for center deadband (optional)
243
- resolution: Resolution in units per mm/radian (optional)
244
"""
245
```
246
247
### Keyboard Repeat Control
248
249
Methods for controlling keyboard repeat rate settings.
250
251
```python { .api }
252
class InputDevice:
253
@property
254
def repeat(self) -> KbdInfo:
255
"""
256
Get keyboard repeat rate information.
257
258
Returns:
259
KbdInfo namedtuple with delay and repeat rate
260
"""
261
262
@repeat.setter
263
def repeat(self, value: KbdInfo) -> None:
264
"""
265
Set keyboard repeat rate.
266
267
Parameters:
268
- value: KbdInfo with new delay and repeat values
269
"""
270
```
271
272
### Event Writing
273
274
Methods for injecting events into devices (feedback events).
275
276
```python { .api }
277
class InputDevice:
278
def write_event(self, event: InputEvent) -> None:
279
"""
280
Inject InputEvent into device.
281
282
Parameters:
283
- event: InputEvent to write to device
284
"""
285
286
def write(self, etype: int, code: int, value: int) -> None:
287
"""
288
Inject input event into device.
289
290
Parameters:
291
- etype: Event type (from ecodes.EV_*)
292
- code: Event code
293
- value: Event value
294
"""
295
296
def syn(self) -> None:
297
"""Inject SYN_REPORT event to synchronize event stream."""
298
```
299
300
### Force Feedback Control
301
302
Methods for managing force feedback effects on compatible devices.
303
304
```python { .api }
305
class InputDevice:
306
def upload_effect(self, effect: "ff.Effect") -> int:
307
"""
308
Upload force feedback effect to device.
309
310
Parameters:
311
- effect: Force feedback Effect structure
312
313
Returns:
314
Effect ID for managing the uploaded effect
315
"""
316
317
def erase_effect(self, ff_id: int) -> None:
318
"""
319
Remove force feedback effect from device.
320
321
Parameters:
322
- ff_id: Effect ID returned from upload_effect()
323
"""
324
```
325
326
## Usage Examples
327
328
### Basic Device Reading
329
330
```python
331
from evdev import InputDevice, list_devices
332
333
# Find all input devices
334
devices = list_devices()
335
print("Available devices:")
336
for device_path in devices:
337
device = InputDevice(device_path)
338
print(f" {device.path}: {device.name}")
339
device.close()
340
341
# Monitor specific device
342
device = InputDevice('/dev/input/event0')
343
print(f"Monitoring {device.name}")
344
345
try:
346
for event in device.read_loop():
347
print(f"Event: type={event.type}, code={event.code}, value={event.value}")
348
finally:
349
device.close()
350
```
351
352
### Device Capabilities
353
354
```python
355
from evdev import InputDevice, ecodes
356
357
device = InputDevice('/dev/input/event0')
358
359
# Get raw capabilities
360
caps = device.capabilities()
361
print("Device capabilities:", caps)
362
363
# Get human-readable capabilities
364
caps_verbose = device.capabilities(verbose=True)
365
print("Human-readable capabilities:", caps_verbose)
366
367
# Check for specific capabilities
368
if ecodes.EV_KEY in caps:
369
print("Device supports key events")
370
key_codes = caps[ecodes.EV_KEY]
371
print(f"Supported keys: {len(key_codes)} keys")
372
373
device.close()
374
```
375
376
### Exclusive Device Access
377
378
```python
379
from evdev import InputDevice
380
381
device = InputDevice('/dev/input/event0')
382
383
# Method 1: Manual grab/ungrab
384
device.grab()
385
try:
386
# Process events exclusively
387
for event in device.read():
388
process_event(event)
389
finally:
390
device.ungrab()
391
device.close()
392
393
# Method 2: Context manager (recommended)
394
with device.grab_context():
395
for event in device.read_loop():
396
process_event(event)
397
if should_stop():
398
break
399
```