Skip to content

Instantly share code, notes, and snippets.

@willwade
Last active April 28, 2024 17:10
Show Gist options
  • Save willwade/2ee856037aedd8974a9d9f7e7747e925 to your computer and use it in GitHub Desktop.
Save willwade/2ee856037aedd8974a9d9f7e7747e925 to your computer and use it in GitHub Desktop.
capture keys - mac and Win code
from Quartz import *
from PyObjCTools.AppHelper import runConsoleEventLoop
def key_callback(proxy, type_, event, refcon):
# Get the key code
key_code = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode)
print("Key pressed:", key_code)
return event
def main():
tap = CGEventTapCreate(
kCGSessionEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
CGEventMaskBit(kCGEventKeyDown), # Listening only to key down events
key_callback,
None
)
if tap:
runloop_source = CFMachPortCreateRunLoopSource(None, tap, 0)
CFRunLoopAddSource(CFRunLoopGetCurrent(), runloop_source, kCFRunLoopCommonModes)
CGEventTapEnable(tap, True)
runConsoleEventLoop()
else:
print("Failed to create event tap")
if __name__ == '__main__':
main()
# This uses the keyboard libarry. On a mac you need to run this as sudo
import sys
import keyboard
from PyQt5.QtWidgets import QApplication, QDialog
from PyQt5.QtCore import QThread, pyqtSignal
class KeyListenerThread(QThread):
keyPressed = pyqtSignal(str)
def run(self):
keyboard.hook(self.on_press)
self.exec_() # Start the Qt event loop
def on_press(self, event):
try:
# Emit the character pressed if it's a character key
if event.name and len(event.name) == 1:
self.keyPressed.emit(event.name)
else:
# Emit the key name if it's a special key (e.g., 'space')
self.keyPressed.emit(event.name)
except AttributeError:
# Fallback if event handling fails
self.keyPressed.emit('unknown key')
class MainWindow(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle("Key Listener Example")
self.resize(300, 200)
# Initialize and start the key listener thread
self.listenerThread = KeyListenerThread()
self.listenerThread.keyPressed.connect(self.handleKeyPress)
self.listenerThread.start()
def handleKeyPress(self, key):
print(f"Key pressed: {key}")
def closeEvent(self, event):
# Ensure all hooks are cleared when the window is closed
keyboard.unhook_all()
self.listenerThread.quit()
self.listenerThread.wait()
super().closeEvent(event)
if __name__ == "__main__":
app = QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())
import ctypes
from ctypes import wintypes
import win32con
user32 = ctypes.WinDLL('user32', use_last_error=True)
# Define necessary structures
class KBDLLHOOKSTRUCT(ctypes.Structure):
_fields_ = [("vkCode", wintypes.DWORD),
("scanCode", wintypes.DWORD),
("flags", wintypes.DWORD),
("time", wintypes.DWORD),
("dwExtraInfo", wintypes.ULONG_PTR)]
# Define the callback function
def low_level_keyboard_proc(nCode, wParam, lParam):
if nCode == win32con.HC_ACTION:
if wParam == win32con.WM_KEYDOWN:
kb = ctypes.cast(lParam, ctypes.POINTER(KBDLLHOOKSTRUCT)).contents
print(f"Key Pressed: {kb.vkCode}")
return user32.CallNextHookEx(None, nCode, wParam, lParam)
# Set hook
HOOKPROC = ctypes.WINFUNCTYPE(wintypes.LPARAM, ctypes.c_int, wintypes.WPARAM, wintypes.LPARAM)
pointer = HOOKPROC(low_level_keyboard_proc)
hook_id = user32.SetWindowsHookExA(win32con.WH_KEYBOARD_LL, pointer, 0, 0)
# Message loop to keep the hook active
msg = wintypes.MSG()
while user32.GetMessageW(ctypes.byref(msg), 0, 0, 0) != 0:
user32.TranslateMessage(ctypes.byref(msg))
user32.DispatchMessageW(ctypes.byref(msg))
# Unhook on exit
user32.UnhookWindowsHookEx(hook_id)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment