You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
2.7 KiB
99 lines
2.7 KiB
# coding=utf-8
|
|
# pynput
|
|
# Copyright (C) 2015-2022 Moses Palmér
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify it under
|
|
# the terms of the GNU Lesser General Public License as published by the Free
|
|
# Software Foundation, either version 3 of the License, or (at your option) any
|
|
# later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
"""
|
|
Utility functions and classes for the *uinput* backend.
|
|
"""
|
|
|
|
# pylint: disable=R0903
|
|
# We implement stubs
|
|
|
|
import evdev
|
|
|
|
|
|
# Check that we have permissions to continue
|
|
def _check():
|
|
# TODO: Implement!
|
|
pass
|
|
_check()
|
|
del _check
|
|
|
|
|
|
class ListenerMixin(object):
|
|
"""A mixin for *uinput* event listeners.
|
|
|
|
Subclasses should set a value for :attr:`_EVENTS` and implement
|
|
:meth:`_handle`.
|
|
"""
|
|
#: The events for which to listen
|
|
_EVENTS = tuple()
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(ListenerMixin, self).__init__(*args, **kwargs)
|
|
self._dev = self._device(self._options.get(
|
|
'device_paths',
|
|
evdev.list_devices()))
|
|
if self.suppress:
|
|
self._dev.grab()
|
|
|
|
def _run(self):
|
|
for event in self._dev.read_loop():
|
|
if event.type in self._EVENTS:
|
|
self._handle(event)
|
|
|
|
def _stop_platform(self):
|
|
self._dev.close()
|
|
|
|
def _device(self, paths):
|
|
"""Attempts to load a readable keyboard device.
|
|
|
|
:param paths: A list of paths.
|
|
|
|
:return: a compatible device
|
|
"""
|
|
dev, count = None, 0
|
|
for path in paths:
|
|
# Open the device
|
|
try:
|
|
next_dev = evdev.InputDevice(path)
|
|
except OSError:
|
|
continue
|
|
|
|
# Does this device provide more handled event codes?
|
|
capabilities = next_dev.capabilities()
|
|
next_count = sum(
|
|
len(codes)
|
|
for event, codes in capabilities.items()
|
|
if event in self._EVENTS)
|
|
if next_count > count:
|
|
dev = next_dev
|
|
count = next_count
|
|
else:
|
|
next_dev.close()
|
|
|
|
if dev is None:
|
|
raise OSError('no keyboard device available')
|
|
else:
|
|
return dev
|
|
|
|
def _handle(self, event):
|
|
"""Handles a single event.
|
|
|
|
This method should call one of the registered event callbacks.
|
|
|
|
:param event: The event.
|
|
"""
|
|
raise NotImplementedError()
|
|
|