Skip to content

Instantly share code, notes, and snippets.

@ajpinedam
Created August 26, 2025 03:37
Show Gist options
  • Save ajpinedam/60c848133ddc9ed0bb180fa60b21b6e9 to your computer and use it in GitHub Desktop.
Save ajpinedam/60c848133ddc9ed0bb180fa60b21b6e9 to your computer and use it in GitHub Desktop.
monitor cocoa trackpad events
import Foundation
import ApplicationServices
let mask = (
(1 << CGEventType.leftMouseDown.rawValue) |
(1 << CGEventType.leftMouseUp.rawValue) |
(1 << CGEventType.mouseMoved.rawValue) |
(1 << CGEventType.otherMouseDown.rawValue) |
(1 << CGEventType.otherMouseUp.rawValue)
)
func describe(_ event: CGEvent) -> String {
let type = event.type
let loc = event.location
let clickState = event.getIntegerValueField(.mouseEventClickState) // 1=single, 2=double
let flags = event.flags.rawValue
return "type=\(type) click=\(clickState) x=\(Int(loc.x)) y=\(Int(loc.y)) flags=0x\(String(flags, radix: 16))"
}
let tapCallback: CGEventTapCallBack = { _, type, event, _ in
// Only print mouse down/up; add others if you like
switch type {
case .leftMouseDown, .leftMouseUp, .otherMouseDown, .otherMouseUp:
print(describe(event))
default:
// print("Unhandled event type: \(type)")
break
}
return Unmanaged.passRetained(event)
}
guard let tap = CGEvent.tapCreate(
tap: .cgSessionEventTap,
place: .headInsertEventTap,
options: .defaultTap,
eventsOfInterest: CGEventMask(mask),
callback: tapCallback,
userInfo: nil
) else {
fputs("ERROR: Could not create event tap (add Input Monitoring permission?)\n", stderr)
exit(1)
}
let runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0)
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes)
CGEvent.tapEnable(tap: tap, enable: true)
print("Listening… (grant Terminal ‘Input Monitoring’ in System Settings > Privacy & Security)")
CFRunLoopRun()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment