Skip to content

Instantly share code, notes, and snippets.

@EmanH
Last active August 2, 2023 11:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save EmanH/84d61a772c0c5110b8d240fdf2a15426 to your computer and use it in GitHub Desktop.
Save EmanH/84d61a772c0c5110b8d240fdf2a15426 to your computer and use it in GitHub Desktop.
⌨ Keeps track of usage and frequency of keyboard shortcuts
from pynput import keyboard
import json
import ctypes
import os
# Load the required libraries
user32 = ctypes.windll.user32
kernel32 = ctypes.windll.kernel32
psapi = ctypes.windll.psapi
# Define dictionaries to hold the counts and modifiers
shortcut_count = {}
active_modifiers = {
"ctrl": False,
"shift": False,
"alt": False
}
# write to console
print("Shortcut logger started")
# Load the counts from a JSON file if it exists
try:
with open('shortcuts.json', 'r') as file:
shortcut_count = json.load(file)
except FileNotFoundError:
pass
def get_underlying_char(control_char):
# check if first characterr is like \u
if len(repr(control_char)) == 3:
return control_char
return chr(ord(control_char) + 64)
def get_program_name():
hWnd = user32.GetForegroundWindow()
pid = ctypes.wintypes.DWORD()
user32.GetWindowThreadProcessId(hWnd, ctypes.byref(pid))
# Obtain a handle to the process
handle = kernel32.OpenProcess(0x1000, False, pid)
# Create a buffer and get the process image file name
buf = (ctypes.c_char * 1024)()
psapi.GetModuleFileNameExA(handle, None, ctypes.byref(buf), 1024)
# Clean up
kernel32.CloseHandle(handle)
return os.path.basename(buf.value.decode('utf-8'))
def on_press(key):
if isinstance(key, keyboard.Key):
# check if key.name starts with ctrl
if key.name.startswith("ctrl"):
active_modifiers["ctrl"] = True
elif key.name.startswith("shift"):
active_modifiers["shift"] = True
elif key.name.startswith("alt"):
active_modifiers["alt"] = True
elif active_modifiers["ctrl"] or active_modifiers["alt"] or active_modifiers["shift"]:
add_to_shortcut_count(key.name.upper())
elif isinstance(key, keyboard.KeyCode):
if active_modifiers["ctrl"] or active_modifiers["alt"]:
try:
add_to_shortcut_count(get_underlying_char(key.char).upper())
except:
pass
def add_to_shortcut_count(key):
program_name = get_program_name()
if program_name not in shortcut_count:
shortcut_count[program_name] = {}
modifiers = []
if active_modifiers["ctrl"]:
modifiers.append("CTRL")
if active_modifiers["shift"]:
modifiers.append("SHIFT")
if active_modifiers["alt"]:
modifiers.append("ALT")
key_combination = "+".join(modifiers) + "+" + key
if key_combination in shortcut_count[program_name]:
shortcut_count[program_name][key_combination] += 1
else:
shortcut_count[program_name][key_combination] = 1
# Write the counts to a JSON file
with open('shortcuts.json', 'w') as file:
json.dump(shortcut_count, file, indent=4)
def on_release(key):
if isinstance(key, keyboard.Key):
if key.name.startswith("ctrl"):
active_modifiers["ctrl"] = False
if key.name.startswith("shift"):
active_modifiers["shift"] = False
if key.name.startswith("alt"):
active_modifiers["alt"] = False
# Listen for key press and release events
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment