def __init__(self, ioloop, cb, types = ["kbd", "mouse", "js"]): self.ioloop = ioloop self.cb = cb self.streams = [] self.handler = EventHandler() self.types = types devs = list(find_devices(types)) for index, type in devs: self.add_stream(index, type) self.udevCtx = pyudev.Context() self.udevMon = pyudev.Monitor.from_netlink(self.udevCtx) self.udevMon.filter_by(subsystem = 'input') self.udevMon.start() ioloop.add_handler(self.udevMon.fileno(), self.udev_handler, ioloop.READ)
def __init__(self, ioloop, cb, types='kbd mouse js'.split(), log=None): self.ioloop = ioloop self.cb = cb self.streams = [] self.handler = EventHandler() self.types = types self.log = log if log else logging.getLogger('inevent') 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)
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"]): self.ioloop = ioloop self.cb = cb self.streams = [] self.handler = EventHandler() self.types = types devs = list(find_devices(types)) for index, type in devs: self.add_stream(index, type) self.udevCtx = pyudev.Context() self.udevMon = pyudev.Monitor.from_netlink(self.udevCtx) self.udevMon.filter_by(subsystem = 'input') self.udevMon.start() ioloop.add_handler(self.udevMon.fileno(), self.udev_handler, ioloop.READ) 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 in find_devices(self.types): if index == devIndex: self.add_stream(devIndex, devType) 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) else: break def udev_handler(self, fd, events): self.process_udev_event() def add_stream(self, devIndex, devType): try: stream = EventStream(devIndex, devType) self.streams.append(stream) self.ioloop.add_handler(stream.filehandle, self.stream_handler, self.ioloop.READ) log.info('Added %s[%d]', devType, devIndex) 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() 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()