The simplest solution is to use the HotKey API functions of Carbon. Unfortunately there doesn't exist a comparably simple and efficient Cocoa API solution. Most Cocoa examples simply wrap the Carbon API functions. Therefore I have done the same in the following example which I tested successfully on Mac 10.6.8 (Snow Leopard) and 10.8.2 (Mountain Lion) with Cocoa x86 and x64 and subsystem Carbon in both ASCII and Unicode mode.spacebuddy wrote:Is it possible to create a global keyboard hook for a mac application?
The example code starts an invisible window and waits for the hot key combination Shift+Control+Space. When detected it makes the window visible. You may define several different hot keys which are handled in the HotKeyHandler() callback. The 4 byte signature of a hot key is user-defined and may be changed at will.
Code: Select all
EnableExplicit
#kEventClassKeyboard = $6B657962 ; 'keyb'
#kEventHotKeyPressed = 5
#kEventParamDirectObject = $2D2D2D2D ; '----'
#typeEventHotKeyID = $686B6964 ; 'hkid'
#controlKeyBit = 12
#controlKey = 1 << #controlKeyBit
#shiftKeyBit = 9
#shiftKey = 1 << #shiftKeyBit
ImportC ""
GetApplicationEventTarget()
RegisterEventHotKey(HotKeyCode.L, HotKeyModifiers.L, HotKeyID.Q, EventTargetRef.I, OptionBits.L, *EventHotKeyRef)
UnregisterEventHotKey(EventHotKeyRef.I)
EndImport
Structure EventTypeSpec
EventClass.L
EventKind.L
EndStructure
Structure EventHotKeyID
Signature.L
ID.L
EndStructure
ProcedureC HotKeyHandler(NextHandlerRef.I, EventRef.I, *UserData)
Protected HotKey.Q
If GetEventParameter_(EventRef, #kEventParamDirectObject, #typeEventHotKeyID, 0, SizeOf(EventHotKeyID), 0, @HotKey) = 0
If PeekL(HotKey) = $68746B31 ; HotKey\Signature = 'htk1' ?
If PeekL(HotKey + 4) = 1 ; HotKey\ID = 1 ?
HideWindow(0, #False)
EndIf
EndIf
EndIf
EndProcedure
Define HotKey.EventHotKeyID
Define HotKeyRef.I
Dim EventTypes.EventTypeSpec(0)
EventTypes(0)\EventClass = #kEventClassKeyboard
EventTypes(0)\EventKind = #kEventHotKeyPressed
HotKey\Signature = $68746B31 ; 'htk1'
HotKey\ID = 1
OpenWindow(0, 270, 100, 220, 70, "Activated by HotKey", #PB_Window_SystemMenu | #PB_Window_Invisible)
; ----- Install EventHandler to react to pressing of hot key(s)
If InstallEventHandler_(GetApplicationEventTarget(), @HotKeyHandler(), 1, @EventTypes(), 0, 0) = 0
; ----- Register hot key (Control+Shift+Space)
RegisterEventHotKey(49, #controlKey | #shiftKey, @HotKey, GetApplicationEventTarget(), 0, @HotKeyRef)
EndIf
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
; ----- You do not need to unregister a hot key when your application
; terminates; the system takes care of that for you. You can use this
; function if the user changes a hot key for something in your
; application - you would unregister the previous key and register your
; new key.
UnregisterEventHotKey(HotKeyRef)