diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 3d185e2..be2d47e 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -9,7 +9,7 @@ RUN apt update \
&& apt install -y \
build-essential git wget binfmt-support qemu gcc-9 \
parted gcc-avr avr-libc avrdude python3 python3-pip python3-tornado \
- curl unzip python3-setuptools gcc-arm-linux-gnueabihf bc vim sudo \
+ curl unzip python3-setuptools gcc-arm-linux-gnueabihf bc vim locate sudo \
&& update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 9 \
&& curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
&& apt install -y nodejs
diff --git a/package-lock.json b/package-lock.json
index a4779f0..e757821 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "bbctrl",
- "version": "1.0.10b10",
+ "version": "1.0.10b11",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "bbctrl",
- "version": "1.0.10b10",
+ "version": "1.0.10b11",
"hasInstallScript": true,
"license": "GPL-3.0+",
"dependencies": {
diff --git a/package.json b/package.json
index edc4d21..f433a40 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "bbctrl",
- "version": "1.0.10b10",
+ "version": "1.0.10b11",
"homepage": "https://onefinitycnc.com/",
"repository": "https://github.com/OneFinityCNC/onefinity",
"license": "GPL-3.0+",
@@ -16,4 +16,4 @@
"lodash.merge": "4.6.2",
"pug-cli": "^1.0.0-alpha6"
}
-}
+}
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 7b3b375..5005f9b 100755
--- a/setup.py
+++ b/setup.py
@@ -18,7 +18,6 @@ setup(
package_dir={'': 'src/py'},
packages=[
'bbctrl',
- 'inevent',
'camotics',
'iw_parse'
],
diff --git a/src/py/bbctrl/Jog.py b/src/py/bbctrl/Jog.py
index 39c1537..28847dc 100644
--- a/src/py/bbctrl/Jog.py
+++ b/src/py/bbctrl/Jog.py
@@ -1,87 +1,492 @@
-################################################################################
-# #
-# This file is part of the Buildbotics firmware. #
-# #
-# Copyright (c) 2015 - 2018, Buildbotics LLC #
-# All rights reserved. #
-# #
-# This file ("the software") is free software: you can redistribute it #
-# and/or modify it under the terms of the GNU General Public License, #
-# version 2 as published by the Free Software Foundation. You should #
-# have received a copy of the GNU General Public License, version 2 #
-# along with the software. If not, see . #
-# #
-# The software 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 the software. If not, see #
-# . #
-# #
-# For information regarding this software email: #
-# "Joseph Coffland" #
-# #
-################################################################################
+from bbctrl.Ctrl import Ctrl
+from bbctrl.Log import Logger
+from evdev.ecodes import EV_ABS, EV_KEY
+import errno
+import evdev
+import functools
+import hashlib
+import json
+import os
+import pyudev
+import re
+import traceback
+import typing
-import inevent
-from inevent.Constants import *
+userGamepadConfigs = {}
+
+gamepadConfigs = {
+ "default": {
+ "sign-x": 1,
+ "sign-y": -1,
+ "sign-z": -1,
+ "deadband": 0.15
+ },
+ "5C936FF2": {
+ "description": "Logitech 710, X mode",
+ "EV_KEY:308": "speed-4",
+ "EV_KEY:305": "speed-3",
+ "EV_KEY:304": "speed-2",
+ "EV_KEY:307": "speed-1",
+ "EV_ABS:0": "axis-x",
+ "EV_ABS:16": "axis-x",
+ "EV_ABS:1": "axis-y",
+ "EV_ABS:17": "axis-y",
+ "EV_ABS:4": "axis-z",
+ "EV_KEY:310": "lock-y",
+ "EV_KEY:311": "lock-x",
+ },
+ "10E159EC": {
+ "description": "Logitech 710, D mode",
+ "EV_KEY:307": "speed-4",
+ "EV_KEY:306": "speed-3",
+ "EV_KEY:305": "speed-2",
+ "EV_KEY:304": "speed-1",
+ "EV_ABS:0": "axis-x",
+ "EV_ABS:16": "axis-x",
+ "EV_ABS:1": "axis-y",
+ "EV_ABS:17": "axis-y",
+ "EV_ABS:5": "axis-z",
+ "EV_KEY:308": "lock-y",
+ "EV_KEY:309": "lock-x",
+ },
+ "5443E73C": {
+ "description": "EasySMX ESM-9013, top lights mode",
+ "EV_KEY:308": "speed-4",
+ "EV_KEY:305": "speed-3",
+ "EV_KEY:304": "speed-2",
+ "EV_KEY:307": "speed-1",
+ "EV_ABS:0": "axis-x",
+ "EV_ABS:16": "axis-x",
+ "EV_ABS:1": "axis-y",
+ "EV_ABS:17": "axis-y",
+ "EV_ABS:4": "axis-z",
+ "EV_KEY:310": "lock-y",
+ "EV_KEY:311": "lock-x",
+ },
+ "951CA031": {
+ "description": "EasySMX ESM-9013, left lights mode",
+ "EV_KEY:304": "speed-4",
+ "EV_KEY:305": "speed-3",
+ "EV_KEY:306": "speed-2",
+ "EV_KEY:307": "speed-1",
+ "EV_ABS:0": "axis-x",
+ "EV_ABS:16": "axis-x",
+ "EV_ABS:1": "axis-y",
+ "EV_ABS:17": "axis-y",
+ "EV_ABS:5": "axis-z",
+ "EV_KEY:308": "lock-y",
+ "EV_KEY:309": "lock-x",
+ },
+ "0BF75ED2": {
+ "description": "EasySMX ESM-9013, bottom lights mode",
+ "EV_KEY:308": "speed-4",
+ "EV_KEY:305": "speed-3",
+ "EV_KEY:304": "speed-2",
+ "EV_KEY:307": "speed-1",
+ "EV_ABS:0": "axis-x",
+ "EV_ABS:16": "axis-x",
+ "EV_ABS:1": "axis-y",
+ "EV_ABS:17": "axis-y",
+ "EV_ABS:5": "axis-z",
+ "EV_KEY:310": "lock-y",
+ "EV_KEY:311": "lock-x",
+ },
+ "B3907139": {
+ "description": "Sony Playstation 4 Dual-Shock Controller",
+ "EV_KEY:307": "speed-4",
+ "EV_KEY:306": "speed-3",
+ "EV_KEY:305": "speed-2",
+ "EV_KEY:304": "speed-1",
+ "EV_ABS:0": "axis-x",
+ "EV_ABS:16": "axis-x",
+ "EV_ABS:1": "axis-y",
+ "EV_ABS:17": "axis-y",
+ "EV_ABS:5": "axis-z",
+ "EV_KEY:308": "lock-y",
+ "EV_KEY:309": "lock-x",
+ }
+}
+
+udevPropertiesToLog = ["ID_MODEL", "ID_SERIAL", "ID_SERIAL_SHORT", "ID_VENDOR"]
+
+udevPropertiesToIgnore = [
+ ".INPUT_CLASS", "ACTION", "DEVLINKS", "DEVNAME", "DEVPATH", "ID_BUS",
+ "ID_FOR_SEAT", "ID_INPUT", "ID_INPUT_JOYSTICK", "ID_MODEL_ID",
+ "ID_MODEL_ENC", "ID_PATH", "ID_PATH_TAG", "ID_REVISION", "ID_TYPE",
+ "ID_USB_DRIVER", "ID_USB_INTERFACES", "ID_USB_INTERFACE_NUM",
+ "ID_VENDOR_ENC", "ID_VENDOR_ID", "LIBINPUT_DEVICE_GROUP", "MAJOR", "MINOR",
+ "SEQNUM", "SUBSYSTEM", "TAGS", "USEC_INITIALIZED"
+]
-# Listen for input events
-class Jog(inevent.JogHandler):
- def __init__(self, ctrl):
- self.ctrl = ctrl
- self.log = ctrl.log.get('Jog')
+def safe_int(s, base=10, val=None):
+ try:
+ return int(s, base)
+ except ValueError:
+ return val
- config = {
- "Logitech Logitech RumblePad 2 USB": {
- "deadband": 0.15,
- "axes": [ABS_X, ABS_Y, ABS_RZ, ABS_Z],
- "dir": [1, -1, -1, 1],
- "arrows": [ABS_HAT0X, ABS_HAT0Y],
- "speed": [0x120, 0x121, 0x122, 0x123],
- "lock": [0x124, 0x125],
- },
- "default": {
- "deadband": 0.15,
- "axes": [ABS_X, ABS_Y, ABS_RY, ABS_RX],
- "dir": [1, -1, -1, 1],
- "arrows": [ABS_HAT0X, ABS_HAT0Y],
- "speed": [0x133, 0x130, 0x131, 0x134],
- "lock": [0x136, 0x137],
+def get_udev_prop(device: pyudev.Device, propertyName: str):
+ try:
+ return device.properties[propertyName]
+ except:
+ return None
+
+
+def to_sorted_json(value):
+ return json.dumps(value, sort_keys=True)
+
+
+AbsMinMax = typing.NamedTuple('AbsMinMax', [('min', float), ('max', float)])
+
+
+def processCapabilities(capabilities):
+ result = {}
+
+ for (type, details) in capabilities.items():
+ if type == EV_KEY:
+ result[type] = details
+
+ if type == EV_ABS:
+ result[type] = {
+ code: AbsMinMax(float(info.min), float(info.max))
+ for (code, info) in details
}
+
+ return result
+
+
+class Gamepad(object):
+ _logRecord = set()
+
+ def __init__(self, log: Logger, _evdev: evdev.InputDevice,
+ _udev: pyudev.Device):
+ self._log = log
+ self._evdev = _evdev
+ self._udev = _udev
+
+ self._capabilities = processCapabilities(_evdev.capabilities())
+
+ self._details = {
+ "evdev": {
+ "name": _evdev.name,
+ "vendor": _evdev.info.vendor,
+ "product": _evdev.info.product,
+ "version": _evdev.info.version,
+ "capabilities": self._capabilities,
+ },
+ "udev":
+ {key: get_udev_prop(_udev, key)
+ for key in udevPropertiesToLog}
}
- super().__init__(config)
+ json = to_sorted_json(self._details)
+ self.hash = hashlib.sha256(json.encode()).hexdigest()[-8:].upper()
- self.v = [0.0] * 4
- self.lastV = self.v
- self.callback()
+ self.config = {
+ **gamepadConfigs.get("default"),
+ **userGamepadConfigs.get("default", {}),
+ **gamepadConfigs.get(self.hash, {}),
+ **userGamepadConfigs.get(self.hash, {})
+ }
- self.processor = inevent.InEvent(ctrl.ioloop, self, types = ['js'])
+ def read(self):
+ return self._evdev.read()
+
+ @property
+ def fd(self):
+ return self._evdev.fd
+
+ @property
+ def devicePath(self):
+ return self._evdev.path
+
+ def scaleAndClampValue(self, event: evdev.InputEvent):
+ if event.type != EV_ABS:
+ return event.value
+
+ info = self._capabilities[EV_ABS].get(event.code) # type: AbsMinMax
+ if not info:
+ return 0
+
+ # Clamp the value to the device's min/max range
+ value = float(max(info.min, min(info.max, event.value)))
+
+ # Remap the value from the device range to -1..1
+ value = ((value - info.min) / (info.max - info.min)) * 2.0 - 1.0
+
+ sign = -1 if value < 0 else 1
+ value = abs(value)
+
+ deadband = self.config.get("deadband", 0.15)
+ if value < deadband:
+ return 0
+
+ # Remap the value to use the full range, with the "deadband" range removed
+ # e.g. if value == deadband, the new value will be zero
+ delta = value - deadband
+ range = 1 - deadband
+ return (delta * sign) / range
+
+ def log(self, msg):
+ self._log.info("{}: {}".format(self.hash, msg))
+
+ def logOnce(self, msg):
+ if self.config.get("debug") or msg not in self._logRecord:
+ self._logRecord.add(msg)
+ self.log(msg)
+
+ def logDebug(self, msg):
+ if self.config.get("debug"):
+ self.log(msg)
+
+ def __str__(self) -> str:
+ return to_sorted_json({
+ "devicePath": self.devicePath,
+ "bustype": self._evdev.info.bustype,
+ "details": self._details,
+ "hash": self.hash
+ })
- def callback(self):
- if self.v != self.lastV:
- self.lastV = self.v
+class Command(object):
+
+ def __init__(self, id: str, value: int, gamepad: Gamepad):
+ self.id = id
+ self.value = value
+ self.gamepad = gamepad
+
+ def __str__(self):
+ return "Command(id='{}', value={}, gamepad='{}')".format(
+ self.id, self.value, self.gamepad.hash)
+
+
+class Jog(object):
+ gamepads = {} # type: dict[typing.Union[int, str], Gamepad]
+ lock = {"x": False, "y": False}
+ axes = {"x": 0, "y": 0, "z": 0}
+ speed = 3 # a resonable default speed, not too fast, not too slow
+ changed = False
+
+ def __init__(self, ctrl: Ctrl):
+ self.ctrl = ctrl
+ self.ioloop = ctrl.ioloop
+ self.log = ctrl.log.get('Jog')
+
+ self._loadUserGamepadConfigs()
+ self._startMonitoring()
+ self._discoverGamepads()
+ self._updateJogging()
+
+ def _loadUserGamepadConfigs(self):
+ path = self.ctrl.get_path('gamepads.json')
+ if os.path.exists(path):
+ with open(path, 'r') as f:
+ global userGamepadConfigs
+ userGamepadConfigs = json.load(f)
+
+ def _startMonitoring(self):
+ self.udev_context = pyudev.Context()
+ self.monitor = pyudev.Monitor.from_netlink(self.udev_context)
+ self.monitor.filter_by(subsystem='input')
+ self.ctrl.ioloop.add_handler(self.monitor, self._udevHandler,
+ self.ctrl.ioloop.READ)
+ self.monitor.start()
+
+ def _udevHandler(self, fd, events):
+ for udev in iter(functools.partial(self.monitor.poll, 0), None):
+ isEventDevice = re.search(r"/event\d+$", udev.device_node or "")
+ if not isEventDevice:
+ continue
+
+ inputJoystick = safe_int(udev.properties["ID_INPUT_JOYSTICK"])
+
+ if inputJoystick != 1:
+ self.log.info("Ignoring non-gamepad device: {}".format(
+ to_sorted_json(
+ {key: udev.properties[key]
+ for key in udev.properties})))
+ continue
+
+ uniqueProperties = set(udev.properties).difference(
+ udevPropertiesToIgnore).difference(udevPropertiesToLog)
+ if len(uniqueProperties) > 0:
+ self.log.info("Unique properties: {}".format(
+ to_sorted_json({
+ key: udev.properties[key]
+ for key in uniqueProperties
+ })))
+
+ if udev.action == 'add':
+ self._listen(udev.device_node)
+ elif udev.action == 'remove':
+ self._forget(udev.device_node)
+
+ def _discoverGamepads(self):
+ with open("/proc/bus/input/devices", "r") as file:
+ for line in file:
+ # Matches lines from '/proc/bus/input/devices' that look like:
+ # H: Handlers=js1 event0
+ if not re.match(r"H:\s*Handlers\s*=.*\bjs\d+\b", line):
+ continue
+
+ match = re.search(r"\bevent\d+\b", line)
+ if not match:
+ continue
+
+ self._listen("/dev/input/{}".format(match.group()))
+
+ def _listen(self, devicePath: str):
+ gamepad = Gamepad(
+ self.log, evdev.InputDevice(devicePath),
+ pyudev.Devices.from_device_file(self.udev_context, devicePath))
+
+ self.log.info("Found gamepad: {}".format(str(gamepad)))
+
+ self.gamepads[gamepad.fd] = self.gamepads[devicePath] = gamepad
+
+ self.ioloop.add_handler(gamepad.fd, self._gamepadHandler,
+ self.ioloop.READ)
+
+ def _forget(self, devicePath: str):
+ gamepad = self.gamepads.get(devicePath)
+ if not gamepad:
+ return
+
+ self.log.info("Device removed: {}, {}".format(gamepad.hash,
+ devicePath))
+
+ self.ioloop.remove_handler(gamepad.fd)
+ del self.gamepads[gamepad.devicePath]
+ del self.gamepads[gamepad.fd]
+
+ def _gamepadHandler(self, fd, events):
+ gamepad = self.gamepads.get(fd)
+ if not gamepad:
+ self.log.info("_gamepad_handler: Unknown gamepad? {}".format(fd))
+ return
+
+ try:
+ for event in gamepad.read():
+ command = self._getCommandFromEvent(gamepad, event)
+ if command:
+ self._processCommand(command)
+ except BlockingIOError:
+ pass
+ except OSError as error:
+ if error.errno == errno.ENODEV:
+ self._forget(gamepad.devicePath)
+ else:
+ gamepad.log(traceback.format_exc())
+ except Exception as error:
+ gamepad.log(traceback.format_exc())
+
+ def _getCommandFromEvent(self, gamepad: Gamepad,
+ event: evdev.InputEvent) -> Command:
+ if event.type not in [EV_ABS, EV_KEY]:
+ return
+
+ eventSignature = "{}:{}".format(evdev.ecodes.EV[event.type],
+ event.code)
+ commandId = gamepad.config.get(eventSignature)
+
+ if not commandId:
+ gamepad.logOnce("Unmapped event: {}:{}".format(
+ gamepad.hash, eventSignature))
+ return
+
+ gamepad.logDebug("Got event: {}".format(str(event)))
+
+ return Command(commandId, gamepad.scaleAndClampValue(event), gamepad)
+
+ def _processCommand(self, command: Command):
+ processor = self.commandProcessors.get(command.id)
+ if not processor:
+ command.gamepad.log("Unrecognized command: {}".format(command.id))
+ return
+
+ command.gamepad.logDebug("Processing command: {}".format(str(command)))
+
+ processor(self, command)
+
+ def _processSpeedCommand(self, command: Command):
+ match = re.match(r"^speed-(\d)$", command.id)
+ speed = int(match.group(1)) if match else 0
+ if speed not in [1, 2, 3, 4]:
+ command.gamepad.log("Unrecognized speed command: {}".format(
+ str(command)))
+
+ self.changed = self.changed or self.speed != speed
+ self.speed = speed
+
+ def _processAxisCommand(self, command: Command):
+ match = re.match(r"^axis-(.)$", command.id)
+ axis = match.group(1) if match else ""
+ if axis not in ["x", "y", "z"]:
+ command.gamepad.log("Unrecognized axis command: {}".format(
+ str(command)))
+
+ sign = command.gamepad.config.get("sign-{}".format(axis), 1)
+ oldValue = self.axes[axis]
+ locked = self.lock.get(axis, False)
+
+ self.axes[axis] = 0 if locked else command.value * sign
+ self.changed = self.changed or oldValue != self.axes[axis]
+
+ command.gamepad.logDebug("_processAxisCommand: {}".format(
+ json.dumps({
+ "command.value": command.value,
+ "axis": axis,
+ "oldValue": oldValue,
+ "value": self.axes[axis],
+ "sign": sign,
+ "locked": locked,
+ "changed": self.changed
+ })))
+
+ def _processLockCommand(self, command: Command):
+ match = re.match(r"^lock-(.)$", command.id)
+ axis = match.group(1) if match else ""
+ if axis not in ["x", "y"]:
+ command.gamepad.log("Unrecognized lock command: {}".format(
+ str(command)))
+
+ self.lock[axis] = bool(command.value)
+
+ def _processDisabled(self, command: Command):
+ pass
+
+ def _updateJogging(self):
+ try:
+ if not self.changed:
+ return
+
+ self.changed = False
+
+ if self.speed == 1: scale = 1.0 / 128.0
+ if self.speed == 2: scale = 1.0 / 32.0
+ if self.speed == 3: scale = 1.0 / 4.0
+ if self.speed == 4: scale = 1.0
+
+ axes = {axis: value * scale for (axis, value) in self.axes.items()}
try:
- axes = {}
- for i in range(len(self.v)): axes["xyzabc"[i]] = self.v[i]
self.ctrl.mach.jog(axes)
+ except:
+ self.log.info(traceback.format_exc())
+ finally:
+ # We only update 4 times a second, to keep from overwhelming the system
+ # EV_ABS events can happen hundreds of times a second.
+ self.ctrl.ioloop.call_later(0.25, self._updateJogging)
- except Exception as e:
- self.log.warning('Jog: %s', e)
-
- self.ctrl.ioloop.call_later(0.25, self.callback)
-
-
- def changed(self):
- scale = 1.0
- if self.speed == 1: scale = 1.0 / 128.0
- if self.speed == 2: scale = 1.0 / 32.0
- if self.speed == 3: scale = 1.0 / 4.0
-
- self.v = [x * scale for x in self.axes]
+ commandProcessors = {
+ "speed-1": _processSpeedCommand,
+ "speed-2": _processSpeedCommand,
+ "speed-3": _processSpeedCommand,
+ "speed-4": _processSpeedCommand,
+ "axis-x": _processAxisCommand,
+ "axis-y": _processAxisCommand,
+ "axis-z": _processAxisCommand,
+ "lock-x": _processLockCommand,
+ "lock-y": _processLockCommand,
+ "disabled": _processDisabled
+ } # type: dict[str, typing.Callable[[Command], None]]
diff --git a/src/py/bbctrl/Log.py b/src/py/bbctrl/Log.py
index 87f694f..d333d37 100644
--- a/src/py/bbctrl/Log.py
+++ b/src/py/bbctrl/Log.py
@@ -128,7 +128,7 @@ class Log(object):
def remove_listener(self, listener): self.listeners.remove(listener)
- def get(self, name, level = None):
+ def get(self, name, level = None) -> Logger:
if not name in self.loggers:
self.loggers[name] = Logger(self, name, self.level)
return self.loggers[name]
diff --git a/src/py/inevent/AbsAxisScaling.py b/src/py/inevent/AbsAxisScaling.py
deleted file mode 100644
index 4b00721..0000000
--- a/src/py/inevent/AbsAxisScaling.py
+++ /dev/null
@@ -1,106 +0,0 @@
-################################################################################
-# #
-# This file is part of the Buildbotics firmware. #
-# #
-# Copyright (c) 2015 - 2018, Buildbotics LLC #
-# All rights reserved. #
-# #
-# This file ("the software") is free software: you can redistribute it #
-# and/or modify it under the terms of the GNU General Public License, #
-# version 2 as published by the Free Software Foundation. You should #
-# have received a copy of the GNU General Public License, version 2 #
-# along with the software. If not, see . #
-# #
-# The software 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 the software. If not, see #
-# . #
-# #
-# For information regarding this software email: #
-# "Joseph Coffland" #
-# #
-################################################################################
-
-# The inevent Python module was adapted from pi3d.event from the pi3d
-# project.
-#
-# Copyright (c) 2016, Joseph Coffland, Cauldron Development LLC.
-# Copyright (c) 2015, Tim Skillman.
-# Copyright (c) 2015, Paddy Gaunt.
-# Copyright (c) 2015, Tom Ritchford.
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-import array
-import fcntl
-import struct
-from inevent import ioctl
-
-
-def EVIOCGABS(axis):
- return ioctl._IOR(ord('E'), 0x40 + axis, "ffffff") # get abs value/limits
-
-
-
-class AbsAxisScaling(object):
- """
- Fetches and implements the EV_ABS axis scaling.
-
- The constructor fetches the scaling values from the given stream for the
- given axis using an ioctl.
-
- There is a scale method, which scales a given value to the range -1..+1.
- """
-
- def __init__(self, stream, axis):
- """
- Fetch the scale values for this stream and fill in the instance
- variables accordingly.
- """
- s = array.array("i", [1, 2, 3, 4, 5, 6])
- try:
- fcntl.ioctl(stream.filehandle, EVIOCGABS(axis), s)
-
- except IOError:
- self.value = self.minimum = self.maximum = self.fuzz = self.flat = \
- self.resolution = 1
-
- else:
- self.value, self.minimum, self.maximum, self.fuzz, self.flat, \
- self.resolution = struct.unpack("iiiiii", s)
-
-
- def __str__(self):
- return "Value {0} Min {1}, Max {2}, Fuzz {3}, Flat {4}, Res {5}".format(
- self.value, self.minimum, self.maximum, self.fuzz, self.flat,
- self.resolution)
-
-
- def scale(self, value):
- """
- scales the given value into the range -1..+1
- """
- return (float(value) - float(self.minimum)) / \
- float(self.maximum - self.minimum) * 2.0 - 1.0
diff --git a/src/py/inevent/Constants.py b/src/py/inevent/Constants.py
deleted file mode 100644
index 0f3a2ed..0000000
--- a/src/py/inevent/Constants.py
+++ /dev/null
@@ -1,124 +0,0 @@
-################################################################################
-# #
-# This file is part of the Buildbotics firmware. #
-# #
-# Copyright (c) 2015 - 2018, Buildbotics LLC #
-# All rights reserved. #
-# #
-# This file ("the software") is free software: you can redistribute it #
-# and/or modify it under the terms of the GNU General Public License, #
-# version 2 as published by the Free Software Foundation. You should #
-# have received a copy of the GNU General Public License, version 2 #
-# along with the software. If not, see . #
-# #
-# The software 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 the software. If not, see #
-# . #
-# #
-# For information regarding this software email: #
-# "Joseph Coffland" #
-# #
-################################################################################
-
-# The inevent Python module was adapted from pi3d.event from the pi3d
-# project.
-#
-# Copyright (c) 2016, Joseph Coffland, Cauldron Development LLC.
-# Copyright (c) 2015, Tim Skillman.
-# Copyright (c) 2015, Paddy Gaunt.
-# Copyright (c) 2015, Tom Ritchford.
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-EV_SYN = 0x00
-EV_KEY = 0x01
-EV_REL = 0x02
-EV_ABS = 0x03
-EV_MSC = 0x04
-EV_SW = 0x05
-EV_LED = 0x11
-EV_SND = 0x12
-EV_REP = 0x14
-EV_FF = 0x15
-EV_PWR = 0x16
-EV_FF_STATUS = 0x17
-
-ev_type_name = {}
-ev_type_name[EV_SYN] = "SYN"
-ev_type_name[EV_KEY] = "KEY"
-ev_type_name[EV_REL] = "REL"
-ev_type_name[EV_ABS] = "ABS"
-ev_type_name[EV_MSC] = "MSC"
-ev_type_name[EV_SW] = "SW"
-ev_type_name[EV_LED] = "LED"
-ev_type_name[EV_SND] = "SND"
-ev_type_name[EV_REP] = "REP"
-ev_type_name[EV_FF] = "FF"
-ev_type_name[EV_PWR] = "PWR"
-ev_type_name[EV_FF_STATUS] = "FF_STATUS"
-
-SYN_REPORT = 0
-SYN_CONFIG = 1
-
-REL_X = 0x00
-REL_Y = 0x01
-REL_Z = 0x02
-REL_RX = 0x03
-REL_RY = 0x04
-REL_RZ = 0x05
-REL_HWHEEL = 0x06
-REL_DIAL = 0x07
-REL_WHEEL = 0x08
-REL_MISC = 0x09
-REL_MAX = 0x0f
-
-ABS_X = 0x00
-ABS_Y = 0x01
-ABS_Z = 0x02
-ABS_RX = 0x03
-ABS_RY = 0x04
-ABS_RZ = 0x05
-ABS_THROTTLE = 0x06
-ABS_RUDDER = 0x07
-ABS_WHEEL = 0x08
-ABS_GAS = 0x09
-ABS_BRAKE = 0x0a
-ABS_HAT0X = 0x10
-ABS_HAT0Y = 0x11
-ABS_HAT1X = 0x12
-ABS_HAT1Y = 0x13
-ABS_HAT2X = 0x14
-ABS_HAT2Y = 0x15
-ABS_HAT3X = 0x16
-ABS_HAT3Y = 0x17
-ABS_PRESSURE = 0x18
-ABS_DISTANCE = 0x19
-ABS_TILT_X = 0x1a
-ABS_TILT_Y = 0x1b
-ABS_TOOL_WIDTH = 0x1c
-ABS_VOLUME = 0x20
-ABS_MISC = 0x28
-ABS_MAX = 0x3f
diff --git a/src/py/inevent/Event.py b/src/py/inevent/Event.py
deleted file mode 100644
index bf8f2e1..0000000
--- a/src/py/inevent/Event.py
+++ /dev/null
@@ -1,142 +0,0 @@
-################################################################################
-# #
-# This file is part of the Buildbotics firmware. #
-# #
-# Copyright (c) 2015 - 2018, Buildbotics LLC #
-# All rights reserved. #
-# #
-# This file ("the software") is free software: you can redistribute it #
-# and/or modify it under the terms of the GNU General Public License, #
-# version 2 as published by the Free Software Foundation. You should #
-# have received a copy of the GNU General Public License, version 2 #
-# along with the software. If not, see . #
-# #
-# The software 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 the software. If not, see #
-# . #
-# #
-# For information regarding this software email: #
-# "Joseph Coffland" #
-# #
-################################################################################
-
-# The inevent Python module was adapted from pi3d.event from the pi3d
-# project.
-#
-# Copyright (c) 2016, Joseph Coffland, Cauldron Development LLC.
-# Copyright (c) 2015, Tim Skillman.
-# Copyright (c) 2015, Paddy Gaunt.
-# Copyright (c) 2015, Tom Ritchford.
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-import struct
-
-from inevent.Constants import *
-
-
-_format = 'llHHi'
-size = struct.calcsize(_format)
-
-
-class Event(object):
- """
- A single event from the linux input event system.
-
- Events are tuples: (Time, Type, Code, Value)
- In addition we remember the stream it came from.
-
- Externally, only the unhandled event handler gets passed the whole event,
- but the SYN handler gets the code and value. (Also the keyboard handler, but
- those are renamed to key and value.)
-
- This class is responsible for converting the Linux input event structure into
- one of these objects and back again.
- """
- def __init__(self, stream, time = None, type = None, code = None,
- value = None):
- """
- Create a new event.
-
- Generally all but the stream parameter are left out; we will want to
- populate the object from a Linux input event using decode.
- """
- self.stream = stream
- self.time = time
- self.type = type
- self.code = code
- self.value = value
-
-
- def get_type_name(self):
- if self.type not in ev_type_name: return '0x%x' % self.type
- return ev_type_name[self.type]
-
-
- def get_source(self):
- return "%s[%d]" % (self.stream.devType, self.stream.devIndex)
-
-
- def __str__(self):
- """
- Uses the stream to give the device type and whether it is currently grabbed.
- """
- grabbed = "grabbed" if self.stream.grabbed else "ungrabbed"
-
- return "Event %s %s @%f: %s 0x%x=0x%x" % (
- self.get_source(), grabbed, self.time, self.get_type_name(), self.code,
- self.value)
-
-
- def __repr__(self):
- return "Event(%s, %f, 0x%x, 0x%x, 0x%x)" % (
- repr(self.stream), self.time, self.type, self.code, self.value)
-
-
- def encode(self):
- """
- Encode this event into a Linux input event structure.
-
- The output is packed into a string. It is unlikely that this function
- will be required, but it might as well be here.
- """
- tsec = int(self.time)
- tfrac = int((self.time - tsec) * 1000000)
-
- return struct.pack(_format, tsec, tfrac, self.type, self.code, self.value)
-
-
- def decode(self, s):
- """
- Decode a Linux input event into the fields of this object.
-
- Arguments:
- *s*
- A binary structure packed into a string.
- """
- tsec, tfrac, self.type, self.code, self.value = struct.unpack(_format, s)
-
- self.time = tsec + tfrac / 1000000.0
diff --git a/src/py/inevent/EventHandler.py b/src/py/inevent/EventHandler.py
deleted file mode 100644
index ccc9d7c..0000000
--- a/src/py/inevent/EventHandler.py
+++ /dev/null
@@ -1,146 +0,0 @@
-################################################################################
-# #
-# This file is part of the Buildbotics firmware. #
-# #
-# Copyright (c) 2015 - 2018, Buildbotics LLC #
-# All rights reserved. #
-# #
-# This file ("the software") is free software: you can redistribute it #
-# and/or modify it under the terms of the GNU General Public License, #
-# version 2 as published by the Free Software Foundation. You should #
-# have received a copy of the GNU General Public License, version 2 #
-# along with the software. If not, see . #
-# #
-# The software 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 the software. If not, see #
-# . #
-# #
-# For information regarding this software email: #
-# "Joseph Coffland" #
-# #
-################################################################################
-
-# The inevent Python module was adapted from pi3d.event from the pi3d
-# project.
-#
-# Copyright (c) 2016, Joseph Coffland, Cauldron Development LLC.
-# Copyright (c) 2015, Tim Skillman.
-# Copyright (c) 2015, Paddy Gaunt.
-# Copyright (c) 2015, Tom Ritchford.
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-from inevent.Constants import *
-from inevent.EventStream import EventStream
-
-
-class EventHandler(object):
- """
- A class to handle events.
-
- Four types of events are handled: REL (mouse movement), KEY (keybaord keys and
- other device buttons), ABS (joysticks and gamepad analogue sticks) and SYN
- (delimits simultaneous events such as mouse movements)
- """
- def __init__(self):
- self.buttons = dict()
-
-
- def event(self, event, handler, name):
- """
- Handles the given event.
-
- If the event is passed to a handler or otherwise handled then returns None,
- else returns the event. All handlers are optional.
-
- All key events are handled by putting them in the self.buttons dict, and
- optionally by calling the supplied handler.
-
- REL X, Y and wheel V and H events are all accumulated internally and
- also optionally passed to the supplied handler. All these events are
- handled.
-
- ABS X, Y, Z, RX, RY, RZ, Hat0X, Hat0Y are all accumulated internally and
- also optionally passed to the supplied handler. Other ABS events are not
- handled.
-
- All SYN events are passed to the supplied handler.
-
- There are several ABS events that we do not handle. In particular:
- THROTTLE, RUDDER, WHEEL, GAS, BRAKE, HAT1, HAT2, HAT3, PRESSURE,
- DISTANCE, TILT, TOOL_WIDTH. Implementing these is left as an exercise
- for the interested reader.
-
- Likewise, since one handler is handling all events for all devices, we
- may get the situation where two devices return the same button. The only
- way to handle that would seem to be to have a key dict for every device,
- which seems needlessly profligate for a situation that may never arise.
- """
-
- state = event.stream.state
-
- if event.type == EV_KEY: self.buttons[event.code] = event.value
- elif event.type == EV_REL: state.rel[event.code] += event.value
- elif event.type == EV_ABS:
- state.abs[event.code] = event.stream.scale(event.code, event.value)
-
- if handler: handler.event(event, state, name)
-
-
- def key_state(self, code):
- """
- Returns the last event value for the given key code.
-
- Key names can be converted to key codes using codeOf[str].
- If the key is pressed the returned value will be 1 (pressed) or 2 (held).
- If the key is not pressed, the returned value will be 0.
- """
- return self.buttons.get(code, 0)
-
-
- def clear_key(self, code):
- """
- Clears the event value for the given key code.
-
- Key names can be converted to key codes using codeOf[str].
- This emulates a key-up but does not generate any events.
- """
- self.buttons[code] = 0
-
-
- def get_keys(self):
- """
- Returns the first of whichever keys have been pressed.
-
- Key names can be converted to key codes using codeOf[str].
- This emulates a key-up but does not generate any events.
- """
- k_list = []
-
- for k in self.buttons:
- if self.buttons[k] != 0: k_list.append(k)
-
- return k_list
diff --git a/src/py/inevent/EventState.py b/src/py/inevent/EventState.py
deleted file mode 100644
index d1443bf..0000000
--- a/src/py/inevent/EventState.py
+++ /dev/null
@@ -1,145 +0,0 @@
-################################################################################
-# #
-# This file is part of the Buildbotics firmware. #
-# #
-# Copyright (c) 2015 - 2018, Buildbotics LLC #
-# All rights reserved. #
-# #
-# This file ("the software") is free software: you can redistribute it #
-# and/or modify it under the terms of the GNU General Public License, #
-# version 2 as published by the Free Software Foundation. You should #
-# have received a copy of the GNU General Public License, version 2 #
-# along with the software. If not, see . #
-# #
-# The software 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 the software. If not, see #
-# . #
-# #
-# For information regarding this software email: #
-# "Joseph Coffland" #
-# #
-################################################################################
-
-# The inevent Python module was adapted from pi3d.event from the pi3d
-# project.
-#
-# Copyright (c) 2016, Joseph Coffland, Cauldron Development LLC.
-# Copyright (c) 2015, Tim Skillman.
-# Copyright (c) 2015, Paddy Gaunt.
-# Copyright (c) 2015, Tom Ritchford.
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-from inevent.Constants import *
-
-
-class EventState:
- def __init__(self):
- self.abs = [0.0] * ABS_MAX
- self.rel = [0.0] * REL_MAX
-
-
- def __str__(self):
- return ("({:6.3f}, {:6.3f}, {:6.3f}) ".format(*self.get_joystick3d()) +
- "({:6.3f}, {:6.3f}, {:6.3f}) ".format(*self.get_joystickR3d()) +
- "({:2.0f}, {:2.0f}) ".format(*self.get_hat()) +
- "({:0.2f}, {:0.2f}) ".format(*self.get_mouse()) +
- "({:0.2f}, {:0.2f})".format(*self.get_wheel()))
-
-
- def get_joystick(self):
- """
- Returns the x,y coordinates for a joystick or left gamepad analogue stick.
-
- The values are returned as a tuple. All values are -1.0 to +1.0 with
- 0.0 being centred.
- """
- return self.abs[ABS_X], self.abs[ABS_Y]
-
-
- def get_joystick3d(self):
- """
- Returns the x,y,z coordinates for a joystick or left gamepad analogue stick
-
- The values are returned as a tuple. All values are -1.0 to +1.0 with
- 0.0 being centred.
- """
- return self.abs[ABS_X], self.abs[ABS_Y], self.abs[ABS_Z]
-
-
- def get_joystickR(self):
- """
- Returns the x,y coordinates for a right gamepad analogue stick.
-
- The values are returned as a tuple. For some odd reason, the gamepad
- returns values in the Z axes of both joysticks, with y being the first.
-
- All values are -1.0 to +1.0 with 0.0 being centred.
- """
- return self.abs[ABS_RZ], self.abs[ABS_Z]
-
-
- def get_joystickR3d(self):
- """
- Returns the x,y,z coordinates for a 2nd joystick control
-
- The values are returned as a tuple. All values are -1.0 to +1.0 with
- 0.0 being centred.
- """
- return self.abs[ABS_RX], self.abs[ABS_RY], self.abs[ABS_RZ]
-
-
- def get_hat(self):
- """
- Returns the x,y coordinates for a joystick hat or gamepad direction pad
-
- The values are returned as a tuple. All values are -1.0 to +1.0 with
- 0.0 being centred.
- """
- return self.abs[ABS_HAT0X], self.abs[ABS_HAT0Y]
-
-
- def get_mouse(self):
- return self.rel[REL_X], self.rel[REL_Y]
-
-
- def get_wheel(self):
- return self.rel[REL_WHEEL], self.rel[REL_HWHEEL]
-
-
- def get_mouse_movement(self):
- """
- Returns the accumulated REL (mouse or other relative device) movements
- since the last call.
-
- The returned value is a tuple: (X, Y, WHEEL, H-WHEEL)
- """
- ret = self.get_mouse() + self.get_wheel()
-
- self.rel[REL_X] = self.rel[REL_Y] = 0
- self.rel[REL_WHEEL] = self.rel[REL_HWHEEL] = 0
-
- return ret
diff --git a/src/py/inevent/EventStream.py b/src/py/inevent/EventStream.py
deleted file mode 100644
index aac648d..0000000
--- a/src/py/inevent/EventStream.py
+++ /dev/null
@@ -1,218 +0,0 @@
-################################################################################
-# #
-# This file is part of the Buildbotics firmware. #
-# #
-# Copyright (c) 2015 - 2018, Buildbotics LLC #
-# All rights reserved. #
-# #
-# This file ("the software") is free software: you can redistribute it #
-# and/or modify it under the terms of the GNU General Public License, #
-# version 2 as published by the Free Software Foundation. You should #
-# have received a copy of the GNU General Public License, version 2 #
-# along with the software. If not, see . #
-# #
-# The software 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 the software. If not, see #
-# . #
-# #
-# For information regarding this software email: #
-# "Joseph Coffland" #
-# #
-################################################################################
-
-# The inevent Python module was adapted from pi3d.event from the pi3d
-# project.
-#
-# Copyright (c) 2016, Joseph Coffland, Cauldron Development LLC.
-# Copyright (c) 2015, Tim Skillman.
-# Copyright (c) 2015, Paddy Gaunt.
-# Copyright (c) 2015, Tom Ritchford.
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-import fcntl
-import os
-import select
-import logging
-
-from inevent.Constants import *
-from inevent import ioctl
-from inevent.AbsAxisScaling import AbsAxisScaling
-from inevent import Event
-from inevent.EventState import EventState
-
-
-log = logging.getLogger('inevent')
-
-EVIOCGRAB = ioctl._IOW(ord('E'), 0x90, "i") # Grab/Release device
-
-
-
-class EventStream(object):
- """
- encapsulates the event* file handling
-
- Each device is represented by a file in /dev/input called eventN, where N is
- a small number. (Actually, a keybaord can be represented by two such files.)
- Instances of this class open one of these files and provide means to read
- events from them.
-
- Class methods also exist to read from multiple files simultaneously, and
- also to grab and ungrab all instances of a given type.
- """
- axisX = 0
- axisY = 1
- axisZ = 2
- axisRX = 3
- axisRY = 4
- axisRZ = 5
- axisHat0X = 6
- axisHat0Y = 7
- axisHat1X = 8
- axisHat1Y = 9
- axisHat2X = 10
- axisHat2Y = 11
- axisHat3X = 12
- axisHat3Y = 13
- axisThrottle = 14
- axisRudder = 15
- axisWheel = 16
- axisGas = 17
- axisBrake = 18
- axisPressure = 19
- axisDistance = 20
- axisTiltX = 21
- axisTiltY = 22
- axisToolWidth = 23
- numAxes = 24
-
- axisToEvent = [
- ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ, ABS_HAT0X, ABS_HAT0Y,
- ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y, ABS_HAT3X, ABS_HAT3Y,
- ABS_THROTTLE, ABS_RUDDER, ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_PRESSURE,
- ABS_DISTANCE, ABS_TILT_X, ABS_TILT_Y, ABS_TOOL_WIDTH]
-
-
- def __init__(self, devIndex, devType, devName):
- """
- Opens the given /dev/input/event file and grabs it.
-
- Also adds it to a class-global list of all existing streams.
- """
- self.devIndex = devIndex
- self.devType = devType
- self.devName = devName
- self.filename = "/dev/input/event" + str(devIndex)
- self.filehandle = os.open(self.filename, os.O_RDWR)
- self.state = EventState()
- self.grab(True)
- self.absInfo = [None] * ABS_MAX
-
- if devType == "js":
- for axis in range(ABS_MAX):
- self.absInfo[axis] = AbsAxisScaling(self, axis)
-
-
- def scale(self, axis, value):
- """
- Scale the given value according to the given axis.
-
- acquire_abs_info must have been previously called to acquire the data to
- do the scaling.
- """
- assert axis < ABS_MAX, "Axis number out of range"
-
- if self.absInfo[axis]: return self.absInfo[axis].scale(value)
- else: return value
-
-
- def grab(self, grab = True):
- """
- Grab (or release) exclusive access to all devices of the given type.
-
- The devices are grabbed if grab is True and released if grab is False.
-
- All devices are grabbed to begin with. We might want to ungrab the
- keyboard for example to use it for text entry. While not grabbed, all
- key-down and key-hold events are filtered out.
- """
- fcntl.ioctl(self.filehandle, EVIOCGRAB, 1 if grab else 0)
- self.grabbed = grab
-
-
- def __iter__(self):
- """s
- Required to make this class an iterator
- """
- return self
-
-
- def next(self): return self.__next__()
-
-
- def __next__(self):
- """
- Returns the next waiting event.
-
- If no event is waiting, returns None.
- """
- ready = select.select([self.filehandle], [], [], 0)[0]
- if ready: return self.read()
-
-
- def read(self):
- """
- Read and return the next waiting event.
- """
- try:
- s = os.read(self.filehandle, Event.size)
- if s:
- event = Event.Event(self)
- event.decode(s)
- return event
-
- except Exception as e:
- log.info('Reading event: %s' % e)
-
-
- def __enter__(self): return self
-
-
- def release(self):
- "Ungrabs the file and closes it."
-
- try:
- self.grab(False)
- os.close(self.filehandle)
-
- except:
- pass
-
-
- def __exit__(self, type, value, traceback):
- "Ungrabs the file and closes it."
-
- self.release()
diff --git a/src/py/inevent/FindDevices.py b/src/py/inevent/FindDevices.py
deleted file mode 100644
index 2f3970a..0000000
--- a/src/py/inevent/FindDevices.py
+++ /dev/null
@@ -1,245 +0,0 @@
-################################################################################
-# #
-# This file is part of the Buildbotics firmware. #
-# #
-# Copyright (c) 2015 - 2018, Buildbotics LLC #
-# All rights reserved. #
-# #
-# This file ("the software") is free software: you can redistribute it #
-# and/or modify it under the terms of the GNU General Public License, #
-# version 2 as published by the Free Software Foundation. You should #
-# have received a copy of the GNU General Public License, version 2 #
-# along with the software. If not, see . #
-# #
-# The software 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 the software. If not, see #
-# . #
-# #
-# For information regarding this software email: #
-# "Joseph Coffland" #
-# #
-################################################################################
-
-# The inevent Python module was adapted from pi3d.event from the pi3d
-# project.
-#
-# Copyright (c) 2016, Joseph Coffland, Cauldron Development LLC.
-# Copyright (c) 2015, Tim Skillman.
-# Copyright (c) 2015, Paddy Gaunt.
-# Copyright (c) 2015, Tom Ritchford.
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-import re
-import logging
-from inevent.Constants import *
-
-log = logging.getLogger('inevent')
-
-
-def test_bit(nlst, b):
- index = b / 32
- bit = b % 32
- return index < len(nlst) and nlst[index] & (1 << bit)
-
-
-def EvToStr(events):
- s = []
-
- if test_bit(events, EV_SYN): s.append("EV_SYN")
- if test_bit(events, EV_KEY): s.append("EV_KEY")
- if test_bit(events, EV_REL): s.append("EV_REL")
- if test_bit(events, EV_ABS): s.append("EV_ABS")
- if test_bit(events, EV_MSC): s.append("EV_MSC")
- if test_bit(events, EV_LED): s.append("EV_LED")
- if test_bit(events, EV_SND): s.append("EV_SND")
- if test_bit(events, EV_REP): s.append("EV_REP")
- if test_bit(events, EV_FF): s.append("EV_FF" )
- if test_bit(events, EV_PWR): s.append("EV_PWR")
- if test_bit(events, EV_FF_STATUS): s.append("EV_FF_STATUS")
-
- return s
-
-
-class DeviceCapabilities(object):
- def __init__(self, firstLine, filehandle):
- self.EV_SYNevents = []
- self.EV_KEYevents = []
- self.EV_RELevents = []
- self.EV_ABSevents = []
- self.EV_MSCevents = []
- self.EV_LEDevents = []
- self.EV_SNDevents = []
- self.EV_REPevents = []
- self.EV_FFevents = []
- self.EV_PWRevents = []
- self.EV_FF_STATUSevents = []
- self.eventTypes = []
-
- match = re.search(".*Bus=([0-9A-Fa-f]+).*Vendor=([0-9A-Fa-f]+).*"
- "Product=([0-9A-Fa-f]+).*Version=([0-9A-Fa-f]+).*",
- firstLine)
-
- if not match:
- log.warning("Do not understand device ID: %s", firstLine)
- self.bus = 0
- self.vendor = 0
- self.product = 0
- self.version = 0
-
- else:
- self.bus = int(match.group(1), base = 16)
- self.vendor = int(match.group(2), base = 16)
- self.product = int(match.group(3), base = 16)
- self.version = int(match.group(4), base = 16)
-
- for line in filehandle:
- if not line.strip(): break
-
- if line[0] == "N":
- match = re.search('Name="([^"]+)"', line)
- if match: self.name = match.group(1)
- else: self.name = "UNKNOWN"
-
- elif line[0] == "P":
- match = re.search('Phys=(.+)', line)
- if match: self.phys = match.group(1)
- else: self.phys = "UNKNOWN"
-
- elif line[0] == "S":
- match = re.search('Sysfs=(.+)', line)
- if match: self.sysfs = match.group(1)
- else: self.sysfs = "UNKNOWN"
-
- elif line[0] == "U":
- match = re.search('Uniq=(.*)', line)
- if match: self.uniq = match.group(1)
- else: self.uniq = "UNKNOWN"
-
- elif line[0] == "H":
- match = re.search('Handlers=(.+)', line)
- if match: self.handlers = match.group(1).split()
- else: self.handlers = []
-
- elif line[:5] == "B: EV":
- eventsNums = [int(x, base = 16) for x in line[6:].split()]
- eventsNums.reverse()
- self.eventTypes = eventsNums
-
- elif line[:6] == "B: KEY":
- eventsNums = [int(x, base = 16) for x in line[7:].split()]
- eventsNums.reverse()
- self.EV_KEYevents = eventsNums
-
- elif line[:6] == "B: ABS":
- eventsNums = [int(x, base = 16) for x in line[7:].split()]
- eventsNums.reverse()
- self.EV_ABSevents = eventsNums
-
- elif line[:6] == "B: MSC":
- eventsNums = [int(x, base = 16) for x in line[7:].split()]
- eventsNums.reverse()
- self.EV_MSCevents = eventsNums
-
- elif line[:6] == "B: REL":
- eventsNums = [int(x, base = 16) for x in line[7:].split()]
- eventsNums.reverse()
- self.EV_RELevents = eventsNums
-
- elif line[:6] == "B: LED":
- eventsNums = [int(x, base = 16) for x in line[7:].split()]
- eventsNums.reverse()
- self.EV_LEDevents = eventsNums
-
- for handler in self.handlers:
- if handler[:5] == "event": self.eventIndex = int(handler[5:])
-
- self.isMouse = False
- self.isKeyboard = False
- self.isJoystick = False
-
-
- def doesProduce(self, eventType, eventCode):
- return test_bit(self.eventTypes, eventType) and (
- (eventType == EV_SYN and test_bit(self.EV_SYNevents, eventCode)) or
- (eventType == EV_KEY and test_bit(self.EV_KEYevents, eventCode)) or
- (eventType == EV_REL and test_bit(self.EV_RELevents, eventCode)) or
- (eventType == EV_ABS and test_bit(self.EV_ABSevents, eventCode)) or
- (eventType == EV_MSC and test_bit(self.EV_MSCevents, eventCode)) or
- (eventType == EV_LED and test_bit(self.EV_LEDevents, eventCode)) or
- (eventType == EV_SND and test_bit(self.EV_SNDevents, eventCode)) or
- (eventType == EV_REP and test_bit(self.EV_REPevents, eventCode)) or
- (eventType == EV_FF and test_bit(self.EV_FFevents, eventCode)) or
- (eventType == EV_PWR and test_bit(self.EV_PWRevents, eventCode)) or
- (eventType == EV_FF_STATUS and
- test_bit(self.EV_FF_STATUSevents, eventCode)))
-
-
- def __str__(self):
- return (
- ("%s\n"
- "Bus: %s Vendor: %s Product: %s Version: %s\n"
- "Phys: %s\n"
- "Sysfs: %s\n"
- "Uniq: %s\n"
- "Handlers: %s Event Index: %s\n"
- "Keyboard: %s Mouse: %s Joystick: %s\n"
- "Events: %s") % (
- self.name, self.bus, self.vendor, self.product, self.version, self.phys,
- self.sysfs, self.uniq, self.handlers, self.eventIndex, self.isKeyboard,
- self.isMouse, self.isJoystick, EvToStr(self.eventTypes)))
-
-
-deviceCapabilities = []
-
-
-def get_devices(filename = "/proc/bus/input/devices"):
- global deviceCapabilities
-
- with open("/proc/bus/input/devices", "r") as filehandle:
- for line in filehandle:
- if line[0] == "I":
- deviceCapabilities.append(DeviceCapabilities(line, filehandle))
-
- return deviceCapabilities
-
-
-def print_devices():
- devs = get_devices()
-
- for dev in devs:
- print(str(dev))
- print(" ABS: {}"
- .format([x for x in range(64) if test_bit(dev.EV_ABSevents, x)]))
- print(" REL: {}"
- .format([x for x in range(64) if test_bit(dev.EV_RELevents, x)]))
- print(" MSC: {}"
- .format([x for x in range(64) if test_bit(dev.EV_MSCevents, x)]))
- print(" KEY: {}"
- .format([x for x in range(512) if test_bit(dev.EV_KEYevents, x)]))
- print(" LED: {}"
- .format([x for x in range(64) if test_bit(dev.EV_LEDevents, x)]))
- print()
diff --git a/src/py/inevent/InEvent.py b/src/py/inevent/InEvent.py
deleted file mode 100644
index a85ea44..0000000
--- a/src/py/inevent/InEvent.py
+++ /dev/null
@@ -1,288 +0,0 @@
-################################################################################
-# #
-# This file is part of the Buildbotics firmware. #
-# #
-# Copyright (c) 2015 - 2018, Buildbotics LLC #
-# All rights reserved. #
-# #
-# This file ("the software") is free software: you can redistribute it #
-# and/or modify it under the terms of the GNU General Public License, #
-# version 2 as published by the Free Software Foundation. You should #
-# have received a copy of the GNU General Public License, version 2 #
-# along with the software. If not, see . #
-# #
-# The software 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 the software. If not, see #
-# . #
-# #
-# For information regarding this software email: #
-# "Joseph Coffland" #
-# #
-################################################################################
-
-# The inevent Python module was adapted from pi3d.event from the pi3d
-# project.
-#
-# Copyright (c) 2016, Joseph Coffland, Cauldron Development LLC.
-# Copyright (c) 2015, Tim Skillman.
-# Copyright (c) 2015, Paddy Gaunt.
-# Copyright (c) 2015, Tom Ritchford.
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-import pyudev
-import re
-import select
-import errno
-import functools
-import logging
-
-from inevent.EventHandler import EventHandler
-from inevent import Keys
-from inevent.Constants import *
-from inevent.EventStream import EventStream
-
-
-log = logging.getLogger('inevent')
-
-_KEYS = (k for k in vars(Keys) if not k.startswith('_'))
-KEY_CODE = dict((k, getattr(Keys, k)) for k in _KEYS)
-CODE_KEY = {}
-for v in KEY_CODE: CODE_KEY[KEY_CODE[v]] = v
-
-
-def key_to_code(key):
- return KEY_CODE.get(str(key), -1) \
- if isinstance(key, str) else key
-
-
-def code_to_key(code): return CODE_KEY.get(code, '')
-
-
-class InEvent(object):
- """Encapsulates the entire InEvent subsystem.
-
- This is generally all you need to import.
-
- On instantiation, we open all devices that are keyboards, mice or joysticks.
- That means we might have two of one sort of another, and that might be a
- problem, but it would be rather rare.
-
- There are several ABS (joystick, touch) events that we do not handle,
- specifically THROTTLE, RUDDER, WHEEL, GAS, BRAKE, HAT1, HAT2, HAT3, PRESSURE,
- DISTANCE, TILT, TOOL_WIDTH. Implementing these is left as an exercise
- for the interested reader. Similarly, we make no attempt to handle
- multi-touch.
-
- Handlers can be supplied, in which case they are called for each event, but
- it isn't necessary; API exists for all the events.
-
- The handler signature is:
-
- def handler_func(event, state)
-
- where:
- event:
- An Event object describing the event.
-
- state:
- An EventState object describing the current state.
-
- Use key_to_code() to convert from the name of a key to its code,
- and code_to_key() to convert a code to a name.
-
- The keys are listed in inevent.Constants.py or /usr/include/linux/input.h
- Note that the key names refer to a US keyboard.
- """
- def __init__(self, ioloop, cb, types = 'kbd mouse js'.split()):
- self.ioloop = ioloop
- self.cb = cb
- self.streams = []
- self.handler = EventHandler()
- self.types = types
-
- self.udevCtx = pyudev.Context()
- self.udevMon = pyudev.Monitor.from_netlink(self.udevCtx)
- self.udevMon.filter_by(subsystem = 'input')
-
- devs = list(self.find_devices(types))
- for index, type, name in devs:
- self.add_stream(index, type, name)
-
- self.udevMon.start()
- ioloop.add_handler(self.udevMon.fileno(), self.udev_handler, ioloop.READ)
-
-
- def get_dev(self, index):
- return pyudev.Device.from_name(self.udevCtx, 'input', 'event%s' % index)
-
-
- def get_dev_name(self, index):
- try:
- dev = self.get_dev(index)
- return dev.parent.attributes.asstring('name').decode('utf-8')
- except: pass
-
-
- def find_devices(self, types):
- """Finds the event indices of all devices of the specified types.
-
- A type is a string on the handlers line of /proc/bus/input/devices.
- Keyboards use "kbd", mice use "mouse" and joysticks (and gamepads) use "js".
-
- Returns a list of integer indexes N, where /dev/input/eventN is the event
- stream for each device.
-
- If butNot is given it holds a list of tuples which the returned values
- should not match.
-
- All devices of each type are returned; if you have two mice, they will both
- be used.
- """
- with open("/proc/bus/input/devices", "r") as filehandle:
- for line in filehandle:
- if line[0] == "H":
- for type in types:
- if type in line:
- match = re.search("event([0-9]+)", line)
- index = match and match.group(1)
- if index:
- yield int(index), type, self.get_dev_name(index)
- break
-
-
- def process_udev_event(self):
- action, device = self.udevMon.receive_device()
- if device is None: return
-
- match = re.search(r"/dev/input/event([0-9]+)", str(device.device_node))
- devIndex = match and match.group(1)
- if not devIndex: return
- devIndex = int(devIndex)
-
- if action == 'add':
- for index, devType, devName in self.find_devices(self.types):
- if index == devIndex:
- self.add_stream(devIndex, devType, devName)
- break
-
- if action == 'remove': self.remove_stream(devIndex)
-
-
- def stream_handler(self, fd, events):
- for stream in self.streams:
- if stream.filehandle == fd:
- while True:
- event = stream.next()
- if event: self.handler.event(event, self.cb, stream.devName)
- else: break
-
-
- def udev_handler(self, fd, events):
- self.process_udev_event()
-
-
- def add_stream(self, devIndex, devType, devName):
- try:
- stream = EventStream(devIndex, devType, devName)
- self.streams.append(stream)
-
- self.ioloop.add_handler(stream.filehandle, self.stream_handler,
- self.ioloop.READ)
-
- log.info('Added %s[%d] %s', devType, devIndex, devName)
-
- except OSError as e:
- log.warning('Failed to add %s[%d]: %s', devType, devIndex, e)
-
-
- def remove_stream(self, devIndex):
- for stream in self.streams:
- if stream.devIndex == devIndex:
- self.streams.remove(stream)
- self.ioloop.remove_handler(stream.filehandle)
- stream.release()
- self.cb.clear()
-
- log.info('Removed %s[%d]', stream.devType, devIndex)
-
-
- def key_state(self, key):
- """
- Returns the state of the given key.
-
- The returned value will be 0 for key-up, or 1 for key-down. This method
- returns a key-held(2) as 1 to aid in using the returned value as a
- movement distance.
-
- This function accepts either the key code or the string name of the key.
- It would be more efficient to look-up and store the code of
- the key with KEY_CODE[], rather than using the string every time. (Which
- involves a dict look-up keyed with a string for every key_state call, every
- time around the loop.)
-
- Gamepad keys are:
- Select = BTN_BASE3, Start = BTN_BASE4
- L1 = BTN_TOP R1 = BTN_BASE
- L2 = BTN_PINKIE R2 = BTN_BASE2
-
- The action buttons are:
- BTN_THUMB
- BTN_TRIGGER
- BTN_TOP
- BTN_THUMB2
-
- Analogue Left Button = BTN_BASE5
- Analogue Right Button = BTN_BASE6
-
- Some of those may clash with extended mouse buttons, so if you are using
- both at once, you'll see some overlap.
-
- The direction pad is hat0 (see get_hat)
- """
- return self.handler.key_state(key_to_code(key))
-
-
- def clear_key(self, key):
- """
- Clears the state of the given key.
-
- Emulates a key-up, but does not call any handlers.
- """
- return self.handler.clear_key(key_to_code(key))
-
-
- def get_keys(self):
- return [code_to_key(k) for k in self.handler.get_keys()]
-
-
- def release(self):
- """
- Ungrabs all streams and closes all files.
-
- Only do this when you're finished with this object. You can't use it again.
- """
- for s in self.streams: s.release()
diff --git a/src/py/inevent/JogHandler.py b/src/py/inevent/JogHandler.py
deleted file mode 100644
index 2deac48..0000000
--- a/src/py/inevent/JogHandler.py
+++ /dev/null
@@ -1,115 +0,0 @@
-import logging
-
-from inevent.Constants import *
-
-
-log = logging.getLogger('inevent')
-log.setLevel(logging.INFO)
-
-
-def axes_to_string(axes):
- s = ''
- for axis in axes:
- if s: s += ', '
- else: s = '('
- s += '{:6.3f}'.format(axis)
- return s + ')'
-
-
-def event_to_string(event, state):
- s = '{} {}: '.format(event.get_source(), event.get_type_name())
-
- if event.type == EV_ABS:
- s += axes_to_string(state.get_joystick3d()) + ' ' + \
- axes_to_string(state.get_joystickR3d()) + ' ' + \
- '({:2.0f}, {:2.0f}) '.format(*state.get_hat())
-
- if event.type == EV_REL:
- s += '({:d}, {:d}) '.format(*state.get_mouse()) + \
- '({:d}, {:d})'.format(*state.get_wheel())
-
- if event.type == EV_KEY:
- state = 'pressed' if event.value else 'released'
- s += '0x{:x} {}'.format(event.code, state)
-
- return s
-
-
-class JogHandler:
- def __init__(self, config):
- self.config = config
- self.reset()
-
-
- def changed(self):
- log.info(axes_to_string(self.axes) + ' x {:d}'.format(self.speed))
-
-
- def reset(self):
- self.axes = [0.0, 0.0, 0.0, 0.0]
- self.speed = 3
- self.vertical_lock = 0
- self.horizontal_lock = 0
-
-
- def clear(self):
- self.reset()
- self.changed()
-
-
- def get_config(self, name):
- if name in self.config: return self.config[name]
- return self.config['default']
-
-
- def event(self, event, state, dev_name):
- if event.type not in [EV_ABS, EV_REL, EV_KEY]: return
-
- config = self.get_config(dev_name)
- changed = False
-
- # Process event
- if event.type == EV_ABS and event.code in config['axes']:
- old_axes = list(self.axes)
- deadband = config['deadband']
- axis = config['axes'].index(event.code)
-
- self.axes[axis] = event.stream.state.abs[event.code]
- self.axes[axis] *= config['dir'][axis]
-
- value = abs(self.axes[axis])
- if value >= deadband:
- sign = -1 if self.axes[axis] < 0 else 1
- delta = value - deadband
- range = 1 - deadband
-
- # Scale the new value to the available range (full range, minus the deadband)
- self.axes[axis] = (delta * sign) / range
- else:
- self.axes[axis] = 0
-
- if self.horizontal_lock and axis not in [0, 3]:
- self.axes[axis] = 0
-
- if self.vertical_lock and axis not in [1, 2]:
- self.axes[axis] = 0
-
- if old_axes[axis] != self.axes[axis]: changed = True
-
- elif event.type == EV_KEY and event.code in config['speed']:
- old_speed = self.speed
- self.speed = config['speed'].index(event.code) + 1
- if self.speed != old_speed: changed = True
-
- elif event.type == EV_KEY and event.code in config['lock']:
- index = config['lock'].index(event.code)
-
- self.horizontal_lock, self.vertical_lock = False, False
-
- if event.value:
- if index == 0: self.horizontal_lock = True
- if index == 1: self.vertical_lock = True
-
- log.debug(event_to_string(event, state))
-
- if changed: self.changed()
diff --git a/src/py/inevent/Keys.py b/src/py/inevent/Keys.py
deleted file mode 100644
index 449aa97..0000000
--- a/src/py/inevent/Keys.py
+++ /dev/null
@@ -1,445 +0,0 @@
-################################################################################
-# #
-# This file is part of the Buildbotics firmware. #
-# #
-# Copyright (c) 2015 - 2018, Buildbotics LLC #
-# All rights reserved. #
-# #
-# This file ("the software") is free software: you can redistribute it #
-# and/or modify it under the terms of the GNU General Public License, #
-# version 2 as published by the Free Software Foundation. You should #
-# have received a copy of the GNU General Public License, version 2 #
-# along with the software. If not, see . #
-# #
-# The software 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 the software. If not, see #
-# . #
-# #
-# For information regarding this software email: #
-# "Joseph Coffland" #
-# #
-################################################################################
-
-# The inevent Python module was adapted from pi3d.event from the pi3d
-# project.
-#
-# Copyright (c) 2016, Joseph Coffland, Cauldron Development LLC.
-# Copyright (c) 2015, Tim Skillman.
-# Copyright (c) 2015, Paddy Gaunt.
-# Copyright (c) 2015, Tom Ritchford.
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-KEY_ESC = 1
-KEY_1 = 2
-KEY_2 = 3
-KEY_3 = 4
-KEY_4 = 5
-KEY_5 = 6
-KEY_6 = 7
-KEY_7 = 8
-KEY_8 = 9
-KEY_9 = 10
-KEY_0 = 11
-KEY_MINUS = 12
-KEY_EQUAL = 13
-KEY_BACKSPACE = 14
-KEY_TAB = 15
-KEY_Q = 16
-KEY_W = 17
-KEY_E = 18
-KEY_R = 19
-KEY_T = 20
-KEY_Y = 21
-KEY_U = 22
-KEY_I = 23
-KEY_O = 24
-KEY_P = 25
-KEY_LEFTBRACE = 26
-KEY_RIGHTBRACE = 27
-KEY_ENTER = 28
-KEY_LEFTCTRL = 29
-KEY_A = 30
-KEY_S = 31
-KEY_D = 32
-KEY_F = 33
-KEY_G = 34
-KEY_H = 35
-KEY_J = 36
-KEY_K = 37
-KEY_L = 38
-KEY_SEMICOLON = 39
-KEY_APOSTROPHE = 40
-KEY_GRAVE = 41
-KEY_LEFTSHIFT = 42
-KEY_BACKSLASH = 43
-KEY_Z = 44
-KEY_X = 45
-KEY_C = 46
-KEY_V = 47
-KEY_B = 48
-KEY_N = 49
-KEY_M = 50
-KEY_COMMA = 51
-KEY_DOT = 52
-KEY_SLASH = 53
-KEY_RIGHTSHIFT = 54
-KEY_KPASTERISK = 55
-KEY_LEFTALT = 56
-KEY_SPACE = 57
-KEY_CAPSLOCK = 58
-KEY_F1 = 59
-KEY_F2 = 60
-KEY_F3 = 61
-KEY_F4 = 62
-KEY_F5 = 63
-KEY_F6 = 64
-KEY_F7 = 65
-KEY_F8 = 66
-KEY_F9 = 67
-KEY_F10 = 68
-KEY_NUMLOCK = 69
-KEY_SCROLLLOCK = 70
-KEY_KP7 = 71
-KEY_KP8 = 72
-KEY_KP9 = 73
-KEY_KPMINUS = 74
-KEY_KP4 = 75
-KEY_KP5 = 76
-KEY_KP6 = 77
-KEY_KPPLUS = 78
-KEY_KP1 = 79
-KEY_KP2 = 80
-KEY_KP3 = 81
-KEY_KP0 = 82
-KEY_KPDOT = 83
-
-KEY_ZENKAKUHANKAKU = 85
-KEY_102ND = 86
-KEY_F11 = 87
-KEY_F12 = 88
-KEY_RO = 89
-KEY_KATAKANA = 90
-KEY_HIRAGANA = 91
-KEY_HENKAN = 92
-KEY_KATAKANAHIRAGANA = 93
-KEY_MUHENKAN = 94
-KEY_KPJPCOMMA = 95
-KEY_KPENTER = 96
-KEY_RIGHTCTRL = 97
-KEY_KPSLASH = 98
-KEY_SYSRQ = 99
-KEY_RIGHTALT = 100
-KEY_LINEFEED = 101
-KEY_HOME = 102
-KEY_UP = 103
-KEY_PAGEUP = 104
-KEY_LEFT = 105
-KEY_RIGHT = 106
-KEY_END = 107
-KEY_DOWN = 108
-KEY_PAGEDOWN = 109
-KEY_INSERT = 110
-KEY_DELETE = 111
-KEY_MACRO = 112
-KEY_MUTE = 113
-KEY_VOLUMEDOWN = 114
-KEY_VOLUMEUP = 115
-KEY_POWER = 116
-KEY_KPEQUAL = 117
-KEY_KPPLUSMINUS = 118
-KEY_PAUSE = 119
-
-KEY_KPCOMMA = 121
-KEY_HANGUEL = 122
-KEY_HANJA = 123
-KEY_YEN = 124
-KEY_LEFTMETA = 125
-KEY_RIGHTMETA = 126
-KEY_COMPOSE = 127
-
-KEY_STOP = 128
-KEY_AGAIN = 129
-KEY_PROPS = 130
-KEY_UNDO = 131
-KEY_FRONT = 132
-KEY_COPY = 133
-KEY_OPEN = 134
-KEY_PASTE = 135
-KEY_FIND = 136
-KEY_CUT = 137
-KEY_HELP = 138
-KEY_MENU = 139
-KEY_CALC = 140
-KEY_SETUP = 141
-KEY_SLEEP = 142
-KEY_WAKEUP = 143
-KEY_FILE = 144
-KEY_SENDFILE = 145
-KEY_DELETEFILE = 146
-KEY_XFER = 147
-KEY_PROG1 = 148
-KEY_PROG2 = 149
-KEY_WWW = 150
-KEY_MSDOS = 151
-KEY_COFFEE = 152
-KEY_DIRECTION = 153
-KEY_CYCLEWINDOWS = 154
-KEY_MAIL = 155
-KEY_BOOKMARKS = 156
-KEY_COMPUTER = 157
-KEY_BACK = 158
-KEY_FORWARD = 159
-KEY_CLOSECD = 160
-KEY_EJECTCD = 161
-KEY_EJECTCLOSECD = 162
-KEY_NEXTSONG = 163
-KEY_PLAYPAUSE = 164
-KEY_PREVIOUSSONG = 165
-KEY_STOPCD = 166
-KEY_RECORD = 167
-KEY_REWIND = 168
-KEY_PHONE = 169
-KEY_ISO = 170
-KEY_CONFIG = 171
-KEY_HOMEPAGE = 172
-KEY_REFRESH = 173
-KEY_EXIT = 174
-KEY_MOVE = 175
-KEY_EDIT = 176
-KEY_SCROLLUP = 177
-KEY_SCROLLDOWN = 178
-KEY_KPLEFTPAREN = 179
-KEY_KPRIGHTPAREN = 180
-
-KEY_F13 = 183
-KEY_F14 = 184
-KEY_F15 = 185
-KEY_F16 = 186
-KEY_F17 = 187
-KEY_F18 = 188
-KEY_F19 = 189
-KEY_F20 = 190
-KEY_F21 = 191
-KEY_F22 = 192
-KEY_F23 = 193
-KEY_F24 = 194
-
-KEY_PLAYCD = 200
-KEY_PAUSECD = 201
-KEY_PROG3 = 202
-KEY_PROG4 = 203
-KEY_SUSPEND = 205
-KEY_CLOSE = 206
-KEY_PLAY = 207
-KEY_FASTFORWARD = 208
-KEY_BASSBOOST = 209
-KEY_PRINT = 210
-KEY_HP = 211
-KEY_CAMERA = 212
-KEY_SOUND = 213
-KEY_QUESTION = 214
-KEY_EMAIL = 215
-KEY_CHAT = 216
-KEY_SEARCH = 217
-KEY_CONNECT = 218
-KEY_FINANCE = 219
-KEY_SPORT = 220
-KEY_SHOP = 221
-KEY_ALTERASE = 222
-KEY_CANCEL = 223
-KEY_BRIGHTNESSDOWN = 224
-KEY_BRIGHTNESSUP = 225
-KEY_MEDIA = 226
-
-KEY_UNKNOWN = 240
-
-BTN_MISC = 0x100
-BTN_0 = 0x100
-BTN_1 = 0x101
-BTN_2 = 0x102
-BTN_3 = 0x103
-BTN_4 = 0x104
-BTN_5 = 0x105
-BTN_6 = 0x106
-BTN_7 = 0x107
-BTN_8 = 0x108
-BTN_9 = 0x109
-
-BTN_MOUSE = 0x110
-BTN_LEFT = 0x110
-BTN_RIGHT = 0x111
-BTN_MIDDLE = 0x112
-BTN_SIDE = 0x113
-BTN_EXTRA = 0x114
-BTN_FORWARD = 0x115
-BTN_BACK = 0x116
-BTN_TASK = 0x117
-
-BTN_JOYSTICK = 0x120
-BTN_TRIGGER = 0x120
-BTN_THUMB = 0x121
-BTN_THUMB2 = 0x122
-BTN_TOP = 0x123
-BTN_TOP2 = 0x124
-BTN_PINKIE = 0x125
-BTN_BASE = 0x126
-BTN_BASE2 = 0x127
-BTN_BASE3 = 0x128
-BTN_BASE4 = 0x129
-BTN_BASE5 = 0x12a
-BTN_BASE6 = 0x12b
-BTN_DEAD = 0x12f
-
-BTN_GAMEPAD = 0x130
-BTN_A = 0x130
-BTN_B = 0x131
-BTN_C = 0x132
-BTN_X = 0x133
-BTN_Y = 0x134
-BTN_Z = 0x135
-BTN_TL = 0x136
-BTN_TR = 0x137
-BTN_TL2 = 0x138
-BTN_TR2 = 0x139
-BTN_SELECT = 0x13a
-BTN_START = 0x13b
-BTN_MODE = 0x13c
-BTN_THUMBL = 0x13d
-BTN_THUMBR = 0x13e
-
-BTN_DIGI = 0x140
-BTN_TOOL_PEN = 0x140
-BTN_TOOL_RUBBER = 0x141
-BTN_TOOL_BRUSH = 0x142
-BTN_TOOL_PENCIL = 0x143
-BTN_TOOL_AIRBRUSH = 0x144
-BTN_TOOL_FINGER = 0x145
-BTN_TOOL_MOUSE = 0x146
-BTN_TOOL_LENS = 0x147
-BTN_TOUCH = 0x14a
-BTN_STYLUS = 0x14b
-BTN_STYLUS2 = 0x14c
-BTN_TOOL_DOUBLETAP = 0x14d
-BTN_TOOL_TRIPLETAP = 0x14e
-
-BTN_WHEEL = 0x150
-BTN_GEAR_DOWN = 0x150
-BTN_GEAR_UP = 0x151
-
-KEY_OK = 0x160
-KEY_SELECT = 0x161
-KEY_GOTO = 0x162
-KEY_CLEAR = 0x163
-KEY_POWER2 = 0x164
-KEY_OPTION = 0x165
-KEY_INFO = 0x166
-KEY_TIME = 0x167
-KEY_VENDOR = 0x168
-KEY_ARCHIVE = 0x169
-KEY_PROGRAM = 0x16a
-KEY_CHANNEL = 0x16b
-KEY_FAVORITES = 0x16c
-KEY_EPG = 0x16d
-KEY_PVR = 0x16e
-KEY_MHP = 0x16f
-KEY_LANGUAGE = 0x170
-KEY_TITLE = 0x171
-KEY_SUBTITLE = 0x172
-KEY_ANGLE = 0x173
-KEY_ZOOM = 0x174
-KEY_MODE = 0x175
-KEY_KEYBOARD = 0x176
-KEY_SCREEN = 0x177
-KEY_PC = 0x178
-KEY_TV = 0x179
-KEY_TV2 = 0x17a
-KEY_VCR = 0x17b
-KEY_VCR2 = 0x17c
-KEY_SAT = 0x17d
-KEY_SAT2 = 0x17e
-KEY_CD = 0x17f
-KEY_TAPE = 0x180
-KEY_RADIO = 0x181
-KEY_TUNER = 0x182
-KEY_PLAYER = 0x183
-KEY_TEXT = 0x184
-KEY_DVD = 0x185
-KEY_AUX = 0x186
-KEY_MP3 = 0x187
-KEY_AUDIO = 0x188
-KEY_VIDEO = 0x189
-KEY_DIRECTORY = 0x18a
-KEY_LIST = 0x18b
-KEY_MEMO = 0x18c
-KEY_CALENDAR = 0x18d
-KEY_RED = 0x18e
-KEY_GREEN = 0x18f
-KEY_YELLOW = 0x190
-KEY_BLUE = 0x191
-KEY_CHANNELUP = 0x192
-KEY_CHANNELDOWN = 0x193
-KEY_FIRST = 0x194
-KEY_LAST = 0x195
-KEY_AB = 0x196
-KEY_NEXT = 0x197
-KEY_RESTART = 0x198
-KEY_SLOW = 0x199
-KEY_SHUFFLE = 0x19a
-KEY_BREAK = 0x19b
-KEY_PREVIOUS = 0x19c
-KEY_DIGITS = 0x19d
-KEY_TEEN = 0x19e
-KEY_TWEN = 0x19f
-
-KEY_DEL_EOL = 0x1c0
-KEY_DEL_EOS = 0x1c1
-KEY_INS_LINE = 0x1c2
-KEY_DEL_LINE = 0x1c3
-
-KEY_FN = 0x1d0
-KEY_FN_ESC = 0x1d1
-KEY_FN_F1 = 0x1d2
-KEY_FN_F2 = 0x1d3
-KEY_FN_F3 = 0x1d4
-KEY_FN_F4 = 0x1d5
-KEY_FN_F5 = 0x1d6
-KEY_FN_F6 = 0x1d7
-KEY_FN_F7 = 0x1d8
-KEY_FN_F8 = 0x1d9
-KEY_FN_F9 = 0x1da
-KEY_FN_F10 = 0x1db
-KEY_FN_F11 = 0x1dc
-KEY_FN_F12 = 0x1dd
-KEY_FN_1 = 0x1de
-KEY_FN_2 = 0x1df
-KEY_FN_D = 0x1e0
-KEY_FN_E = 0x1e1
-KEY_FN_F = 0x1e2
-KEY_FN_S = 0x1e3
-KEY_FN_B = 0x1e4
-
-KEY_MAX = 0x1ff
diff --git a/src/py/inevent/__init__.py b/src/py/inevent/__init__.py
deleted file mode 100644
index 5e6780d..0000000
--- a/src/py/inevent/__init__.py
+++ /dev/null
@@ -1,57 +0,0 @@
-################################################################################
-# #
-# This file is part of the Buildbotics firmware. #
-# #
-# Copyright (c) 2015 - 2018, Buildbotics LLC #
-# All rights reserved. #
-# #
-# This file ("the software") is free software: you can redistribute it #
-# and/or modify it under the terms of the GNU General Public License, #
-# version 2 as published by the Free Software Foundation. You should #
-# have received a copy of the GNU General Public License, version 2 #
-# along with the software. If not, see . #
-# #
-# The software 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 the software. If not, see #
-# . #
-# #
-# For information regarding this software email: #
-# "Joseph Coffland" #
-# #
-################################################################################
-
-# The inevent Python module was adapted from pi3d.event from the pi3d
-# project.
-#
-# Copyright (c) 2016, Joseph Coffland, Cauldron Development LLC.
-# Copyright (c) 2015, Tim Skillman.
-# Copyright (c) 2015, Paddy Gaunt.
-# Copyright (c) 2015, Tom Ritchford.
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-from .InEvent import InEvent
-from .JogHandler import JogHandler
diff --git a/src/py/inevent/ioctl.py b/src/py/inevent/ioctl.py
deleted file mode 100644
index 652ef68..0000000
--- a/src/py/inevent/ioctl.py
+++ /dev/null
@@ -1,128 +0,0 @@
-################################################################################
-# #
-# This file is part of the Buildbotics firmware. #
-# #
-# Copyright (c) 2015 - 2018, Buildbotics LLC #
-# All rights reserved. #
-# #
-# This file ("the software") is free software: you can redistribute it #
-# and/or modify it under the terms of the GNU General Public License, #
-# version 2 as published by the Free Software Foundation. You should #
-# have received a copy of the GNU General Public License, version 2 #
-# along with the software. If not, see . #
-# #
-# The software 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 the software. If not, see #
-# . #
-# #
-# For information regarding this software email: #
-# "Joseph Coffland" #
-# #
-################################################################################
-
-# The inevent Python module was adapted from pi3d.event from the pi3d
-# project.
-#
-# Copyright (c) 2016, Joseph Coffland, Cauldron Development LLC.
-# Copyright (c) 2015, Tim Skillman.
-# Copyright (c) 2015, Paddy Gaunt.
-# Copyright (c) 2015, Tom Ritchford.
-#
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-#
-# IOCTL macros
-#
-# ioctl command encoding: 32 bits total, command in lower 16 bits,
-# size of the parameter structure in the lower 14 bits of the
-# upper 16 bits.
-#
-# Encoding the size of the parameter structure in the ioctl request
-# is useful for catching programs compiled with old versions
-# and to avoid overwriting user space outside the user buffer area.
-# The highest 2 bits are reserved for indicating the ``access mode''.
-# NOTE: This limits the max parameter size to 16kB - 1
-#
-# The following is for compatibility across the various Linux
-# platforms. The generic ioctl numbering scheme doesn't really enforce
-# a type field. De facto, however, the top 8 bits of the lower 16
-# bits are indeed used as a type field, so we might just as well make
-# this explicit here.
-
-import struct
-
-
-sizeof = struct.calcsize
-
-_IOC_NRBITS = 8
-_IOC_TYPEBITS = 8
-_IOC_SIZEBITS = 14
-_IOC_DIRBITS = 2
-
-_IOC_NRMASK = (1 << _IOC_NRBITS) - 1
-_IOC_TYPEMASK = (1 << _IOC_TYPEBITS) - 1
-_IOC_SIZEMASK = (1 << _IOC_SIZEBITS) - 1
-_IOC_DIRMASK = (1 << _IOC_DIRBITS) - 1
-
-_IOC_NRSHIFT = 0
-_IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
-_IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
-_IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS
-
-_IOC_NONE = 0
-_IOC_WRITE = 1
-_IOC_READ = 2
-_IOC_RW = _IOC_READ | _IOC_WRITE
-
-
-def _IOC(dir, type, nr, size):
- return int(
- (dir << _IOC_DIRSHIFT) |
- (type << _IOC_TYPESHIFT) |
- (nr << _IOC_NRSHIFT) |
- (size << _IOC_SIZESHIFT))
-
-# encode ioctl numbers
-def _IO(type, nr): return _IOC(_IOC_NONE, type, nr, 0)
-def _IOR(type, nr, fmt): return _IOC(_IOC_READ, type, nr, sizeof(fmt))
-def _IOW(type, nr, fmt): return _IOC(_IOC_WRITE, type, nr, sizeof(fmt))
-def _IOWR(type, nr, fmt): return _IOC(_IOC_RW, type, nr, sizeof(fmt))
-def _IOR_BAD(type, nr, fmt): return _IOC(_IOC_READ, type, nr, sizeof(fmt))
-def _IOW_BAD(type, nr, fmt): return _IOC(_IOC_WRITE, type, nr, sizeof(fmt))
-def _IOWR_BAD(type, nr, fmt): return _IOC(_IOC_RW, type, nr, sizeof(fmt))
-
-# decode ioctl numbers
-def _IOC_DIR(nr): return (nr >> _IOC_DIRSHIFT) & _IOC_DIRMASK
-def _IOC_TYPE(nr): return (nr >> _IOC_TYPESHIFT) & _IOC_TYPEMASK
-def _IOC_NR(nr): return (nr >> _IOC_NRSHIFT) & _IOC_NRMASK
-def _IOC_SIZE(nr): return (nr >> _IOC_SIZESHIFT) & _IOC_SIZEMASK
-
-# for drivers/sound files
-IOC_IN = _IOC_WRITE << _IOC_DIRSHIFT
-IOC_OUT = _IOC_READ << _IOC_DIRSHIFT
-IOC_INOUT = _IOC_RW << _IOC_DIRSHIFT
-IOCSIZE_MASK = _IOC_SIZEMASK << _IOC_SIZESHIFT
-IOCSIZE_SHIFT = _IOC_SIZESHIFT
-