def rattle(d, effnr=0, effgain=0xC000): print("rattle", effnr, effgain) gain = evdev.InputEvent(0, 0, evdev.ecodes.EV_FF, evdev.ecodes.FF_GAIN, effgain) # [0x5000 .. 0xFFFF] play = evdev.InputEvent(0,0,evdev.ecodes.EV_FF, effnr, 1) stop = evdev.InputEvent(0,0,evdev.ecodes.EV_FF, effnr, 0) d.write_event(gain) d.write_event(play)
def flush_state_change(self, sync_event): noisy = self._state == VirtualModifierState.PRESSED_NOISY previous_noisy = self._previous_state == VirtualModifierState.PRESSED_NOISY if noisy and not previous_noisy: self._keyboard.write_event( evdev.InputEvent(sync_event.sec, sync_event.usec, evdev.ecodes.EV_KEY, self.code, 1)) elif not noisy and previous_noisy: self._keyboard.write_event( evdev.InputEvent(sync_event.sec, sync_event.usec, evdev.ecodes.EV_KEY, self.code, 0)) self._previous_state = self._state
async def _event_consumer(self, source, forward_to): """Reads input events to inject keycodes or talk to the event_producer. Can be stopped by stopping the asyncio loop. This loop reads events from a single device only. Other devnodes may be present for the hardware device, in which case this needs to be started multiple times. Parameters ---------- source : evdev.InputDevice where to read keycodes from forward_to : evdev.UInput where to write keycodes to that were not mapped to anything. Should be an UInput with capabilities that work for all forwarded events, so ideally they should be copied from source. """ logger.debug( 'Started consumer to inject to %s, fd %s', source.path, source.fd ) gamepad = classify(source) == GAMEPAD keycode_handler = KeycodeMapper(self.context, source, forward_to) async for event in source.async_read_loop(): if self._event_producer.is_handled(event): # the event_producer will take care of it self._event_producer.notify(event) continue # for mapped stuff if utils.should_map_as_btn(event, self.context.mapping, gamepad): will_report_key_up = utils.will_report_key_up(event) keycode_handler.handle_keycode(event) if not will_report_key_up: # simulate a key-up event if no down event arrives anymore. # this may release macros, combinations or keycodes. release = evdev.InputEvent(0, 0, event.type, event.code, 0) self._event_producer.debounce( debounce_id=(event.type, event.code, event.value), func=keycode_handler.handle_keycode, args=(release, False), ticks=3, ) continue # forward the rest forward_to.write(event.type, event.code, event.value) # this already includes SYN events, so need to syn here again # This happens all the time in tests because the async_read_loop # stops when there is nothing to read anymore. Otherwise tests # would block. logger.error('The consumer for "%s" stopped early', source.path)
def flush_state_change(self, sync_event): if self._state == OnReleaseState.PRESSED_SILENT and \ self._previous_state != OnReleaseState.PRESSED_SILENT: event = evdev.InputEvent(sync_event.sec, sync_event.usec, evdev.ecodes.EV_KEY, self._second_code, 1) self._keyboard.write_event(event) if not self._repeating: event.value = 0 self._keyboard.write_event(event) if self._state != OnReleaseState.PRESSED_SILENT and \ self._previous_state == OnReleaseState.PRESSED_SILENT and \ self._repeating: event = evdev.InputEvent(sync_event.sec, sync_event.usec, evdev.ecodes.EV_KEY, self._second_code, 0) self._keyboard.write_event(event) self._repeating = False super().flush_state_change(sync_event)
def new_event(type, code, value, timestamp=None, offset=0): """Create a new input_event.""" if timestamp is None: timestamp = time.time() + offset sec = int(timestamp) usec = timestamp % 1 * 1000000 event = evdev.InputEvent(sec, usec, type, code, value) return event
def flush_state_change(self, sync_event): if self._previous_state == OnReleaseState.PRESSED_SINGLE and \ self._state == OnReleaseState.RELEASED: event = evdev.InputEvent(sync_event.sec, sync_event.usec, evdev.ecodes.EV_KEY, self._extra_code, 1) self._keyboard.write_event(event) event.value = 0 self._keyboard.write_event(event) self._previous_state = self._state
def js_read_loop(dev, timeout): """ same as /usr/local/lib/python3.5/dist-packages/evdev/eventio.py:read_loop, but with a timeout... """ while True: r, w, x = select.select([dev.fd], [], [], timeout) if len(r): for event in dev.read(): yield event else: yield evdev.InputEvent(0,0,evdev.ecodes.EV_SYN, evdev.ecodes.KEY_UNKNOWN,0) # dummy when timout
def franken_event( original_event, franken_uinput, franken_event_code, original_absinfo=None, franken_absinfo=None): event = evdev.InputEvent( original_event.sec, original_event.usec, original_event.type, franken_event_code, franken_value(original_event.value, original_absinfo, franken_absinfo), ) franken_uinput.write_event(event) logger.debug(f"generated event {franken_uinput.device.path} {evdev.categorize(event)} {event.code}")
def button(uinput, code, value=1, syn=True): """ Send a button event. :param uinput: the uinput device to generate the button event :type uinput: evdev.UInput :param code: the event code, e.g. evdev.ecodes.BTN_A :type code: int :param value: 1 (button down), 0 (button up) :type code: int :param syn: whether or not to follow up the event with a syn event :type syn: bool """ # sec and usec are thrown out anyway, see # https://github.com/gvalkov/python-evdev/blob/master/evdev/eventio.py#L111 uinput.write_event(evdev.InputEvent(0, 0, evdev.ecodes.EV_KEY, code, value)) if(syn): uinput.syn()
def _get_event(self, message): """Return an InputEvent if the message contains one. None otherwise.""" message_type = message['type'] message_body = message['message'] if message_type == 'groups': if message_body != groups.dumps(): groups.loads(message_body) logger.debug('Received %d devices', len(groups)) self._devices_updated = True return None if message_type == 'event': return evdev.InputEvent(*message_body) logger.error('Received unknown message "%s"', message) return None
def _get_event(self, message): """Return an InputEvent if the message contains one. None otherwise.""" message_type = message['type'] message_body = message['message'] if message_type == 'devices': # result of get_devices in the helper if message_body != get_devices(): logger.debug('Received %d devices', len(message_body)) set_devices(message_body) self._devices_updated = True return None if message_type == 'event': return evdev.InputEvent(*message_body) logger.error('Received unknown message "%s"', message) return None
def set_led_pulse(self, brightness=255, speed=255, pulse_table=0, pulse_while_asleep=False, pulse_while_awake=True): """ Encode the pulse parameters: brightness: 0 to 255 speed: 0 to 510, slower to faster, log scale, sortof. 255 = 2s ("normal") So basically: 251=8s, 252=6s, 253=4s, 254=2.5s, 255=2s /ish/. I timed those values with a stopwatch, so... pulse_table: 0, 1, 2 (dunno) pulse_while_asleep: boolean pulse_while_awake: boolean """ if brightness < 0 or brightness > 255: raise ValueError("brightness (%s) must be 0 through 255" % (brightness,)) if speed < 0 or speed > 510: raise ValueError("speed (%s) must be 0 through 510" % (speed,)) if pulse_table < 0 or pulse_table > 2: raise ValueError("pulse table (%s) must be 0, 1, or 2" % (pulse_table,)) pulse_while_awake = int(bool(pulse_while_awake)) pulse_while_asleep = int(bool(pulse_while_asleep)) value = (pulse_while_awake << 20) \ | (pulse_while_asleep << 19) \ | (pulse_table << 17) \ | (speed << 8) \ | brightness mod, sec = math.modf(time.time()) sec = int(sec) usec = int(mod * 1000000) event = evdev.InputEvent(sec=sec, usec=usec, type=evdev.ecodes.EV_MSC, code=evdev.ecodes.MSC_PULSELED, value=value) self.device.write_event(event)
async def action(device, fake_device): global keycodes_to_bind try: is_on_pause = False # no remapping if script is on pause is_leftctrl_down = False is_rightctrl_down = False is_ctrl_down = False is_leftalt_down = False is_rightalt_down = False is_alt_down = False is_leftshift_down = False is_rightshift_down = False is_shift_down = False is_leftwin_down = False is_rightwin_down = False is_win_down = False is_space_down = False list_of_keydowns_while_space_down = [] # const from evdev key_is_hold = 2 # key is holding key_is_down = 1 # key is pressed key_is_up = 0 # key is released # for catching space hotkey hotkey_with_space_pressed = False device.grab( ) # https://python-evdev.readthedocs.io/en/latest/tutorial.html#getting-exclusive-access-to-a-device async for event in device.async_read_loop( ): # https://python-evdev.readthedocs.io/en/latest/tutorial.html#reading-events-using-asyncio if event.code == 2: continue if event.type == evdev.ecodes.EV_SYN: continue # event.type == evdev.ecodes.EV_... # https://www.kernel.org/doc/Documentation/input/event-codes.txt skip_send = False # for not to send current key if event.type != evdev.ecodes.EV_KEY: if event.type == evdev.ecodes.EV_MSC: logging.debug('') logging.debug('event.type=%s, event=%s, sending as is', event.type, evdev.categorize(event)) fake_device.write_event(event) fake_device.syn() else: logging.debug( 'event.type=EV_KEY event.code=%s event.value=%s %s %s', event.code, event.value, 'isDown' if event.value == key_is_down else '', 'isUp' if event.value == key_is_up else '') if event.code == evdev.ecodes.KEY_LEFTCTRL: is_leftctrl_down = event.value elif event.code == evdev.ecodes.KEY_RIGHTCTRL: is_rightctrl_down = event.value elif event.code == evdev.ecodes.KEY_LEFTALT: is_leftalt_down = event.value elif event.code == evdev.ecodes.KEY_RIGHTALT: is_rightalt_down = event.value elif event.code == evdev.ecodes.KEY_LEFTSHIFT: is_leftshift_down = event.value elif event.code == evdev.ecodes.KEY_RIGHTSHIFT: is_rightshift_down = event.value elif event.code == evdev.ecodes.KEY_LEFTMETA: is_leftwin_down = event.value elif event.code == evdev.ecodes.KEY_RIGHTMETA: is_rightwin_down = event.value elif event.code == evdev.ecodes.KEY_SPACE: is_space_down = event.value if event.value == key_is_down: list_of_keydowns_while_space_down = [] skip_send = True hotkey_with_space_pressed = False if event.value == key_is_up: if hotkey_with_space_pressed: skip_send = True else: # send `space` key if no hotkey with `space` was pressed # send `space` down before sending current event (`space` up) logging.debug( '---> send space event-down before sending event-up' ) fake_device.write_event( evdev.InputEvent(event.sec, event.usec, event.type, evdev.ecodes.KEY_SPACE, key_is_down)) fake_device.syn() # print('leftctrl=', is_leftctrl_down, 'leftalt=', is_leftalt_down, 'leftshift=', is_leftshift_down, 'leftmeta=', is_leftmeta_down, 'space=', is_space_down) is_ctrl_down = is_leftctrl_down or is_rightctrl_down is_alt_down = is_leftalt_down or is_rightalt_down is_shift_down = is_leftshift_down or is_rightshift_down is_win_down = is_leftwin_down or is_rightwin_down if event.value == key_is_down: # handle special hotkeys on key-down only! if event.code == evdev.ecodes.KEY_Q and is_win_down and is_ctrl_down and is_alt_down: print('win+ctrl+alt+q, quit!') device.ungrab() sys.exit() break if event.code == evdev.ecodes.KEY_Z and is_win_down and is_ctrl_down and is_alt_down: if is_on_pause: print('win+ctrl+alt+z, unpause script') is_on_pause = False else: print('win+ctrl+alt+z, pause script') is_on_pause = True # main logic begins if not skip_send: if event.value == key_is_down or event.value == key_is_hold: if not is_on_pause and is_space_down and event.code in keycodes_to_bind: # that is our key, modify it # save keys to modify on key-up if event.code not in list_of_keydowns_while_space_down: list_of_keydowns_while_space_down.append( event.code) # modify key code event.code = keycodes_to_bind[event.code] # save flag that hotkey was pressed for not to send space-key hotkey_with_space_pressed = True elif event.value == key_is_up: # we must modify key-up event even when space-key was # just released and not pressed anymore if event.code in list_of_keydowns_while_space_down: # that is our key, modify it # remove that key from list list_of_keydowns_while_space_down.remove( event.code) # modify key code event.code = keycodes_to_bind[event.code] logging.debug('---> sending event: %s', evdev.categorize(event)) fake_device.write_event(event) fake_device.syn() except Exception as e: logging.error(e) device.ungrab() print('device ungrabbed')