import argparse import keyboard import logging import mouse import pickle import threading import time LOGGER = logging.getLogger("playback") def main() -> None: parser = argparse.ArgumentParser() parser.add_argument( "-d", "--delay", default=5, type=int, help="Seconds to wait before replay." ) parser.add_argument( "-i", "--input", default="dump.capture", help="Name of the file to replay from." ) parser.add_argument( "--verbose", action="store_true", help="Show verbose messages." ) args = parser.parse_args() logging.basicConfig( level = logging.DEBUG if args.verbose else logging.INFO ) _do_delay(args.delay) events = _load_events(args.input) _play_events(events) def _play_events(events) -> None: LOGGER.info("Playback started.") key_state = keyboard.stash_state() last_time = None for event in events: if last_time is not None: to_sleep = event.time - last_time if to_sleep > 0: time.sleep(to_sleep) last_time = event.time if isinstance(event, keyboard.KeyboardEvent): _play_event_keyboard(event) elif any([ isinstance(event, mouse.ButtonEvent), isinstance(event, mouse.MoveEvent), isinstance(event, mouse.WheelEvent), ]): _play_event_mouse(event) else: raise ValueError(f"Not a recognized event {event}") keyboard.restore_modifiers(key_state) LOGGER.info("Done.") def _play_event_keyboard(event) -> None: LOGGER.debug("Key %s", event) key = event.scan_code or event.name keyboard.press(key) if event.event_type == keyboard.KEY_DOWN else keyboard.release(key) def _play_event_mouse(event) -> None: LOGGER.debug("Mouse %s", event) if isinstance(event, mouse.ButtonEvent): if event.event_type == mouse.UP: mouse.release(event.button) else: mouse.press(event.button) elif isinstance(event, mouse.MoveEvent): mouse.move(event.x, event.y, absolute=True) elif isinstance(event, mouse.WheelEvent): mouse.wheel(event.delta) def _do_delay(delay: int) -> None: if not delay: return print("\n") for i in range(delay): print(f"\rStarting in {delay-i} seconds") time.sleep(1) def _load_events(filename: str): with open(filename, "rb") as input_: events = pickle.load(input_) LOGGER.debug("Loaded %s", filename) return events if __name__ == "__main__": main()