Skip to content

Commit 14fc704

Browse files
committed
Create a baseclass for device and uinput, to hold the shared functions that read and write events
1 parent 27b9ec0 commit 14fc704

3 files changed

Lines changed: 137 additions & 171 deletions

File tree

evdev/device.py

Lines changed: 4 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
import select
77
import collections
88

9-
from evdev import _input, _uinput, ecodes, util
9+
from evdev import _input, ecodes, util
1010
from evdev.events import InputEvent
11+
from evdev.eventio import EventIO
1112

1213

1314
#--------------------------------------------------------------------------
@@ -100,7 +101,7 @@ def __str__(self):
100101
return msg.format(*self)
101102

102103

103-
class InputDevice(object):
104+
class InputDevice(EventIO):
104105
'''
105106
A linux input device from which input events can be read.
106107
'''
@@ -219,20 +220,6 @@ def capabilities(self, verbose=False, absinfo=True):
219220
else:
220221
return self._capabilities(absinfo)
221222

222-
def need_write(func):
223-
'''
224-
Decorator that raises :class:`EvdevError` if there is no write access to the
225-
input device.
226-
'''
227-
@functools.wraps(func)
228-
def wrapper(*args):
229-
fd = args[0].fd
230-
if fcntl.fcntl(fd, fcntl.F_GETFL) & os.O_RDWR:
231-
return func(*args)
232-
msg = 'no write access to device "%s"' % args[0].fn
233-
raise EvdevError(msg)
234-
return wrapper
235-
236223
def leds(self, verbose=False):
237224
'''
238225
Return currently set LED keys.
@@ -254,7 +241,6 @@ def leds(self, verbose=False):
254241

255242
return leds
256243

257-
@need_write
258244
def set_led(self, led_num, value):
259245
'''
260246
Set the state of the selected LED.
@@ -263,18 +249,7 @@ def set_led(self, led_num, value):
263249
-------
264250
>>> device.set_led(ecodes.LED_NUML, 1)
265251
'''
266-
self.set(ecodes.EV_LED, led_num, value)
267-
268-
@need_write
269-
def set(self, etype, code, value):
270-
'''
271-
Set the state of the selected component.
272-
273-
Example
274-
-------
275-
>>> device.set(ecodes.EV_LED, ecodes.LED_NUML, 1)
276-
'''
277-
_uinput.write(self.fd, etype, code, value)
252+
self.write(ecodes.EV_LED, led_num, value)
278253

279254
def __eq__(self, other):
280255
'''
@@ -297,52 +272,6 @@ def close(self):
297272
finally:
298273
self.fd = -1
299274

300-
def fileno(self):
301-
'''
302-
Return the file descriptor to the open event device. This makes
303-
it possible to pass :class:`InputDevice` instances directly to
304-
:func:`select.select()` and :class:`asyncore.file_dispatcher`.
305-
'''
306-
307-
return self.fd
308-
309-
def read_one(self):
310-
'''
311-
Read and return a single input event as an instance of
312-
:class:`InputEvent <evdev.events.InputEvent>`.
313-
314-
Return ``None`` if there are no pending input events.
315-
'''
316-
317-
# event -> (sec, usec, type, code, val)
318-
event = _input.device_read(self.fd)
319-
320-
if event:
321-
return InputEvent(*event)
322-
323-
def read_loop(self):
324-
'''
325-
Enter an endless :func:`select.select()` loop that yields input events.
326-
'''
327-
328-
while True:
329-
r, w, x = select.select([self.fd], [], [])
330-
for event in self.read():
331-
yield event
332-
333-
def read(self):
334-
'''
335-
Read multiple input events from device. Return a generator object that
336-
yields :class:`InputEvent <evdev.events.InputEvent>` instances. Raises
337-
`BlockingIOError` if there are no available events at the moment.
338-
'''
339-
340-
# events -> [(sec, usec, type, code, val), ...]
341-
events = _input.device_read_many(self.fd)
342-
343-
for i in events:
344-
yield InputEvent(*i)
345-
346275
def grab(self):
347276
'''
348277
Grab input device using ``EVIOCGRAB`` - other applications will

evdev/eventio.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# encoding: utf-8
2+
3+
import os
4+
import fcntl
5+
import functools
6+
import select
7+
import collections
8+
9+
from evdev import _input, _uinput, ecodes, util
10+
from evdev.events import InputEvent
11+
12+
class EventIO(object):
13+
'''
14+
Class capable of read and write input events.
15+
16+
This is used as as a base class for both device and uinput:
17+
18+
- On ``device``, you read user-generated events (keys pressed, mouse moved, etc) and write feedback events (leds, beeps)
19+
20+
- On ``uinput``, you write user-generated events (keys pressed, mouse moved, etc) and read feedback events (leds, beeps)
21+
'''
22+
23+
def fileno(self):
24+
'''
25+
Return the file descriptor to the open event device. This makes
26+
it possible to pass instances directly to :func:`select.select()` and
27+
:class:`asyncore.file_dispatcher`.
28+
'''
29+
return self.fd
30+
31+
def read_loop(self):
32+
'''
33+
Enter an endless loop that yields input events.
34+
'''
35+
while True:
36+
r, w, x = select.select([self.fd], [], [])
37+
for event in self.read():
38+
yield event
39+
40+
41+
def read_one(self):
42+
'''
43+
Read and return a single input event as an instance of
44+
:class:`InputEvent <evdev.events.InputEvent>`.
45+
46+
Return ``None`` if there are no pending input events.
47+
'''
48+
49+
# event -> (sec, usec, type, code, val)
50+
event = _input.device_read(self.fd)
51+
52+
if event:
53+
return InputEvent(*event)
54+
55+
def read(self):
56+
'''
57+
Read multiple input events from device. Return a generator object that
58+
yields :class:`InputEvent <evdev.events.InputEvent>` instances. Raises
59+
`BlockingIOError` if there are no available events at the moment.
60+
'''
61+
62+
# events -> [(sec, usec, type, code, val), ...]
63+
events = _input.device_read_many(self.fd)
64+
65+
for i in events:
66+
yield InputEvent(*i)
67+
68+
69+
70+
def _need_write(func):
71+
'''
72+
Decorator that raises :class:`EvdevError` if there is no write access to the
73+
input device.
74+
'''
75+
@functools.wraps(func)
76+
def wrapper(*args):
77+
fd = args[0].fd
78+
if fcntl.fcntl(fd, fcntl.F_GETFL) & os.O_RDWR:
79+
return func(*args)
80+
msg = 'no write access to device "%s"' % args[0].fn
81+
raise EvdevError(msg)
82+
return wrapper
83+
84+
def write_event(self, event):
85+
'''
86+
Inject an input event into the input subsystem. Events are
87+
queued until a synchronization event is received.
88+
89+
Arguments
90+
---------
91+
event: InputEvent
92+
InputEvent instance or an object with an ``event`` attribute
93+
(:class:`KeyEvent <evdev.events.KeyEvent>`, :class:`RelEvent
94+
<evdev.events.RelEvent>` etc).
95+
96+
Example
97+
-------
98+
>>> ev = InputEvent(1334414993, 274296, ecodes.EV_KEY, ecodes.KEY_A, 1)
99+
>>> ui.write_event(ev)
100+
'''
101+
102+
if hasattr(event, 'event'):
103+
event = event.event
104+
105+
self.write(event.type, event.code, event.value)
106+
107+
@_need_write
108+
def write(self, etype, code, value):
109+
'''
110+
Inject an input event into the input subsystem. Events are
111+
queued until a synchronization event is received.
112+
113+
Arguments
114+
---------
115+
etype
116+
event type (e.g. ``EV_KEY``).
117+
118+
code
119+
event code (e.g. ``KEY_A``).
120+
121+
value
122+
event value (e.g. 0 1 2 - depends on event type).
123+
124+
Example
125+
---------
126+
>>> ui.write(e.EV_KEY, e.KEY_A, 1) # key A - down
127+
>>> ui.write(e.EV_KEY, e.KEY_A, 0) # key A - up
128+
'''
129+
130+
_uinput.write(self.fd, etype, code, value)

evdev/uinput.py

Lines changed: 3 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@
33
import os
44
import stat
55
import time
6-
import select
76

8-
from evdev import _input, _uinput
7+
from evdev import _uinput
98
from evdev import ecodes, util, device
109
from evdev.events import InputEvent
10+
from evdev.eventio import EventIO
1111

1212
class UInputError(Exception):
1313
pass
1414

1515

16-
class UInput(object):
16+
class UInput(EventIO):
1717
'''
1818
A userland input device and that can inject input events into the
1919
linux input subsystem.
@@ -132,99 +132,6 @@ def close(self):
132132
_uinput.close(self.fd)
133133
self.fd = -1
134134

135-
def fileno(self):
136-
'''
137-
Return the file descriptor to the open event device. This
138-
makes it possible to pass pass ``InputDevice`` instances
139-
directly to :func:`select.select()` and
140-
:class:`asyncore.file_dispatcher`.'''
141-
142-
return self.fd
143-
144-
def read_one(self):
145-
'''
146-
Read and return a single input event as an instance of
147-
:class:`InputEvent <evdev.events.InputEvent>`.
148-
149-
Return ``None`` if there are no pending input events.
150-
'''
151-
152-
# event -> (sec, usec, type, code, val)
153-
event = _input.device_read(self.fd)
154-
155-
if event:
156-
return InputEvent(*event)
157-
158-
def read_loop(self):
159-
'''
160-
Enter an endless :func:`select.select()` loop that yields input events.
161-
'''
162-
163-
while True:
164-
r, w, x = select.select([self.fd], [], [])
165-
for event in self.read():
166-
yield event
167-
168-
def read(self):
169-
'''
170-
Read multiple input events from device. Return a generator object that
171-
yields :class:`InputEvent <evdev.events.InputEvent>` instances. Raises
172-
`BlockingIOError` if there are no available events at the moment.
173-
'''
174-
175-
# events -> [(sec, usec, type, code, val), ...]
176-
events = _input.device_read_many(self.fd)
177-
178-
for event in events:
179-
yield InputEvent(*event)
180-
181-
def write_event(self, event):
182-
'''
183-
Inject an input event into the input subsystem. Events are
184-
queued until a synchronization event is received.
185-
186-
Arguments
187-
---------
188-
event: InputEvent
189-
InputEvent instance or an object with an ``event`` attribute
190-
(:class:`KeyEvent <evdev.events.KeyEvent>`, :class:`RelEvent
191-
<evdev.events.RelEvent>` etc).
192-
193-
Example
194-
-------
195-
>>> ev = InputEvent(1334414993, 274296, ecodes.EV_KEY, ecodes.KEY_A, 1)
196-
>>> ui.write_event(ev)
197-
'''
198-
199-
if hasattr(event, 'event'):
200-
event = event.event
201-
202-
self.write(event.type, event.code, event.value)
203-
204-
def write(self, etype, code, value):
205-
'''
206-
Inject an input event into the input subsystem. Events are
207-
queued until a synchronization event is received.
208-
209-
Arguments
210-
---------
211-
etype
212-
event type (e.g. ``EV_KEY``).
213-
214-
code
215-
event code (e.g. ``KEY_A``).
216-
217-
value
218-
event value (e.g. 0 1 2 - depends on event type).
219-
220-
Example
221-
---------
222-
>>> ui.write(e.EV_KEY, e.KEY_A, 1) # key A - down
223-
>>> ui.write(e.EV_KEY, e.KEY_A, 0) # key A - up
224-
'''
225-
226-
_uinput.write(self.fd, etype, code, value)
227-
228135
def syn(self):
229136
'''
230137
Inject a ``SYN_REPORT`` event into the input subsystem. Events

0 commit comments

Comments
 (0)