Skip to content

Instantly share code, notes, and snippets.

@p0deje
Last active November 13, 2018 03:06
Show Gist options
  • Save p0deje/da5e5cfda6be8cb87c2e7caad3a3df63 to your computer and use it in GitHub Desktop.
Save p0deje/da5e5cfda6be8cb87c2e7caad3a3df63 to your computer and use it in GitHub Desktop.
import AppKit
import Carbon
// Custom NSMenu implementation allowing to filter key inputs.
class Menu: NSMenu {
required init(coder decoder: NSCoder) {
super.init(coder: decoder)
}
init() {
super.init(title: "Test")
// We add header with custom view which will intercept Carbon events.
let headerItem = NSMenuItem(title: "filter", action: nil, keyEquivalent: "")
headerItem.view = FilterMenuItemView()
addItem(headerItem)
// Ignore, this is just to fill menu with items.
addItem(NSMenuItem(title: "test1", action: nil, keyEquivalent: ""))
addItem(NSMenuItem(title: "test2", action: nil, keyEquivalent: ""))
}
}
// Custom menu which listens to Carbon events allowing to filter input.
class FilterMenuItemView: NSView {
private var eventHandler: EventHandlerRef?
required init?(coder decoder: NSCoder) {
super.init(coder: decoder)
}
init() {
super.init(frame: NSRect(x: 0, y: 0, width: 20, height: 21))
}
// The most important part where event interception happens.
override func viewDidMoveToWindow() {
super.viewDidMoveToWindow()
if window != nil {
// 1/6: Window is loaded and we can attach our event listener
if let dispatcher = GetEventDispatcherTarget() {
// 2/6: Add handler callback
let eventHandlerCallback: EventHandlerUPP = { eventHandlerCallRef, eventRef, userData in
// 3/6: This callback simply propagates it downwards and prints response
let response = CallNextEventHandler(eventHandlerCallRef, eventRef!)
print("Response \(response)")
return response
}
// 4/6: We need to listen only for key down and repeat events.
let eventSpecs = [
EventTypeSpec(eventClass: OSType(kEventClassKeyboard), eventKind: UInt32(kEventRawKeyDown)),
EventTypeSpec(eventClass: OSType(kEventClassKeyboard), eventKind: UInt32(kEventRawKeyRepeat))
]
// 5/6: Finally, add our event handler
InstallEventHandler(dispatcher, eventHandlerCallback, 2, eventSpecs, nil, &eventHandler)
}
} else {
// 6/6: Window is unloaded, so we need to remove our handler.
RemoveEventHandler(eventHandler)
}
}
}
Menu().popUp(positioning: nil, at: NSEvent.mouseLocation, in: nil)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment