def key_pressed(self, e) -> None: if not self.collecting or keyboard.is_modifier(e.scan_code): return hk = keyboard.get_hotkey_name() for m in MODIFIERS: if keyboard.is_pressed(m) and not keyboard.is_modifier(hk) and hk not in ALL_SHORTCUTS: self.count += 1 logging.debug(f"Shortcut: {hk}") return
def run(self, **kwargs): assert "log_time" in kwargs, "Missing keyword agument log_time!" assert "buffer" in kwargs, "Missing keyword argument buffer!" log_time = int(kwargs.get("log_time")) buffer = int(kwargs.get("buffer")) assert log_time > 0, "Log time must be greater than 0!" assert buffer > 0, "Buffer must be greater than 0!" from queue import Queue, Empty import datetime import keyboard start_time = datetime.datetime.now() time_delta = datetime.timedelta(minutes=log_time) que = Queue(maxsize=1) self.hook = keyboard.hook(que.put) self._run.set() self._logger.info("Started KeyLogger task!") while self._run.is_set(): try: event: keyboard.KeyboardEvent = que.get(timeout=1) except Empty: event = None if event and event.event_type == keyboard.KEY_DOWN: if keyboard.is_modifier(event.name) or event.name in ["enter", "space", "backspace", "delete", "tab"]: event.name = " <" + event.name.upper() + "> " if len(self.buffer) >= buffer: self.data.append(self.buffer) self.buffer = "" else: self.buffer = self.buffer + event.name if datetime.datetime.now() - start_time > time_delta: self.data.append(self.buffer) self.buffer = "" break return self.data
def key_press_handler(self, key): if keyboard.is_modifier(key.scan_code): self.modifier |= MODIFIER[key.scan_code] self.key_hold = SCAN_CODES_HID_USAGEID_MAPPING[key.scan_code] if self.key_hold != self.macro_key: self.bt.send_report( modifier=self.modifier, code=(self.key_hold, 0x00, 0x00, 0x00, 0x00, 0x00) ) # replaying, press macro again to stop if self.replaying: if self.key_hold == self.macro_key: self.replaying = False else: if self.recording: # macro: stop record if self.key_hold == self.macro_key: try: # the first 2 elements is F1 down, F1 up self.replay_buf = keyboard.stop_recording()[2:] except ValueError: # if not keyboard.start_recording() pass finally: self.recording = False else: # F6: assign macro key if self.pre_key == 0x3f: self.macro_key = self.key_hold # F7: start record, prevent nested recording elif self.key_hold == 0x40: keyboard.start_recording() self.recording = True # macro: play the record elif self.key_hold == self.macro_key: self.replaying = True self.pre_key = self.key_hold
def test_is_modifier_scan_code(self): for i in range(10): self.assertEqual(keyboard.is_modifier(i), i in [4, 5, 6, 7])
def test_is_modifier_name(self): for name in keyboard.all_modifiers: self.assertTrue(keyboard.is_modifier(name))
def key_release_handler(self, key): if keyboard.is_modifier(key.scan_code): self.modifier &= ~MODIFIER[key.scan_code] if self.key_hold != self.macro_key: self.bt.send_report(self.modifier) # send empty data packet
def custom_direct_callback(self, event): print("Custom") """ This function is called for every OS keyboard event and decides if the event should be blocked or not, and passes a copy of the event to other, non-blocking, listeners. There are two ways to block events: remapped keys, which translate events by suppressing and re-emitting; and blocked hotkeys, which suppress specific hotkeys. """ # Pass through all fake key events, don't even report to other handlers. if self.is_replaying: return True """ MODIFIED PART captures keyboard events even if a hook is suppressing if the hook is not suppressing some issues happen because of hotkey recursion """ event_type = event.event_type scan_code = event.scan_code # Update tables of currently pressed keys and modifiers. with _pressed_events_lock: if event_type == KEY_DOWN: if is_modifier(scan_code): self.active_modifiers.add(scan_code) _pressed_events[scan_code] = event hotkey = tuple(sorted(_pressed_events)) if event_type == KEY_UP: self.active_modifiers.discard(scan_code) if scan_code in _pressed_events: del _pressed_events[scan_code] if not all(hook(event) for hook in self.blocking_hooks): return False # Mappings based on individual keys instead of hotkeys. for key_hook in self.blocking_keys[scan_code]: if not key_hook(event): return False # Default accept. accept = True if self.blocking_hotkeys: if self.filtered_modifiers[scan_code]: origin = 'modifier' modifiers_to_update = set([scan_code]) else: modifiers_to_update = self.active_modifiers if is_modifier(scan_code): modifiers_to_update = modifiers_to_update | {scan_code} callback_results = [ callback(event) for callback in self.blocking_hotkeys[hotkey] ] if callback_results: accept = all(callback_results) origin = 'hotkey' else: origin = 'other' for key in sorted(modifiers_to_update): transition_tuple = (self.modifier_states.get(key, 'free'), event_type, origin) should_press, new_accept, new_state = self.transition_table[ transition_tuple] if should_press: press(key) if new_accept is not None: accept = new_accept self.modifier_states[key] = new_state if accept: if event_type == KEY_DOWN: _logically_pressed_keys[scan_code] = event elif event_type == KEY_UP and scan_code in _logically_pressed_keys: del _logically_pressed_keys[scan_code] # Queue for handlers that won't block the event. self.queue.put(event) return accept
def print_pressed_keys(e): global script global lastevent global actualLine global dontprint if e.scan_code in scan_codes: e.name = scan_codes[e.scan_code] if e.name in rev_canonical_names: e.name = rev_canonical_names[e.name] if output_log_file is not None: with open(output_log_file, "a") as af: af.write(_getjson(e) + ",") e.name = (e.name.upper(), e.name)[len(e.name) == 1] if lastevent is not None: if lastevent.event_type == "up" and e.event_type == "down": delay = round((e.time-lastevent.time)*1000) if delay >= delay_threshold: if actualLine is not None and actualLine.startswith("STRING"): script.append(actualLine) actualLine = None script.append("DELAY %s" % delay) if e.event_type == "down": dontprint = False if len(e.name) == 1 and not e.modifiers and not keyboard.is_modifier(e.scan_code): if actualLine is None: actualLine = "STRING " elif e.name in actualLine and not actualLine.startswith("STRING"): pass actualLine = actualLine + e.name else: if actualLine is not None: if e.name in actualLine: pass if actualLine.startswith("STRING"): if actualLine is not None: script.append(actualLine) actualLine = e.name else: if e.name not in actualLine: actualLine = actualLine + " " + e.name else: actualLine = e.name else: #up if actualLine is not None: if not actualLine.startswith("STRING"): if e.name in actualLine: if not dontprint: script.append(actualLine) actualLine = actualLine.replace(e.name, "").replace(" "," ").strip() actualLine = (actualLine, None)[actualLine == ""] if actualLine is not None: dontprint = True lastevent = e i = actualLine