Skip to content

Commit 986ba0f

Browse files
committed
Add readonly parameter to InputDevice and writable parameter to list_devices/is_device
1 parent a47b5b5 commit 986ba0f

2 files changed

Lines changed: 33 additions & 7 deletions

File tree

src/evdev/device.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,19 +109,26 @@ class InputDevice(EventIO, Generic[_AnyStr]):
109109

110110
__slots__ = ("path", "fd", "info", "name", "phys", "uniq", "_rawcapabilities", "version", "ff_effects_count")
111111

112-
def __init__(self, dev: Union[_AnyStr, "os.PathLike[_AnyStr]"]):
112+
def __init__(self, dev: Union[_AnyStr, "os.PathLike[_AnyStr]"], readonly: bool = False):
113113
"""
114114
Arguments
115115
---------
116116
dev : str|bytes|PathLike
117117
Path to input device
118+
readonly : bool
119+
If True, the device is opened in read-only mode (``O_RDONLY``)
120+
without attempting ``O_RDWR`` first. This avoids triggering
121+
firmware side-effects (such as LED state re-assertion) on
122+
certain hardware. Default is False.
118123
"""
119124

120125
#: Path to input device.
121126
self.path: _AnyStr = dev if not hasattr(dev, "__fspath__") else dev.__fspath__()
122127

123128
# Certain operations are possible only when the device is opened in read-write mode.
124129
try:
130+
if readonly:
131+
raise OSError
125132
fd = os.open(dev, os.O_RDWR | os.O_NONBLOCK)
126133
except OSError:
127134
fd = os.open(dev, os.O_RDONLY | os.O_NONBLOCK)

src/evdev/util.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,33 @@
99
from .events import InputEvent, event_factory, KeyEvent, RelEvent, AbsEvent, SynEvent
1010

1111

12-
def list_devices(input_device_dir: Union[str, bytes, os.PathLike] = "/dev/input") -> List[str]:
13-
"""List readable character devices in ``input_device_dir``."""
12+
def list_devices(input_device_dir: Union[str, bytes, os.PathLike] = "/dev/input", writable: bool = True) -> List[str]:
13+
"""List readable (and optionally writable) character devices in ``input_device_dir``.
14+
15+
Arguments
16+
---------
17+
input_device_dir : str|bytes|PathLike
18+
Path to the input device directory. Default is ``/dev/input``.
19+
writable : bool
20+
If True (default), only list devices that are both readable and
21+
writable. If False, list all readable devices.
22+
"""
1423

1524
fns = glob.glob("{}/event*".format(input_device_dir))
16-
return list(filter(is_device, fns))
25+
return list(filter(lambda fn: is_device(fn, writable=writable), fns))
26+
1727

28+
def is_device(fn: Union[str, bytes, os.PathLike], writable: bool = True) -> bool:
29+
"""Check if ``fn`` is a readable (and optionally writable) character device.
1830
19-
def is_device(fn: Union[str, bytes, os.PathLike]) -> bool:
20-
"""Check if ``fn`` is a readable and writable character device."""
31+
Arguments
32+
---------
33+
fn : str|bytes|PathLike
34+
Path to the device file.
35+
writable : bool
36+
If True (default), also check for write access. If False, only
37+
check for read access.
38+
"""
2139

2240
if not os.path.exists(fn):
2341
return False
@@ -26,7 +44,8 @@ def is_device(fn: Union[str, bytes, os.PathLike]) -> bool:
2644
if not stat.S_ISCHR(m):
2745
return False
2846

29-
if not os.access(fn, os.R_OK | os.W_OK):
47+
access = os.R_OK | os.W_OK if writable else os.R_OK
48+
if not os.access(fn, access):
3049
return False
3150

3251
return True

0 commit comments

Comments
 (0)