Reputation: 121
Ok so i'm trying to log on console output what keys are pressed. I just can't understand the cocoa structure, neither with Obj-c, nor swift. I'm not a master in these 2 languages but... Well here's my code:
import Cocoa
import Foundation
import AppKit
var loop = true
var idRegisterdEvent: AnyObject? = nil
func handlerEvent(myEvent: (NSEvent!)) -> Void {
print(myEvent.keyCode)
}
while loop {
idRegisterdEvent = NSEvent.addGlobalMonitorForEventsMatchingMask(NSEventMask.KeyDownMask, handler: handlerEvent)
}
i know everything is wrong, yeah.. But man, these events, i can't understand how they work.
Upvotes: 11
Views: 5511
Reputation:
After spending a couple of hours on google I eventually read a couple of github resources. It turns out that someone has already figured it out.
Basically you need to create a NSApplicationDelegate
, which enables your app to listen to system-events.
The following shows the bare minimum code needed(swift2
):
func acquirePrivileges() -> Bool {
let accessEnabled = AXIsProcessTrustedWithOptions(
[kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String: true])
if accessEnabled != true {
print("You need to enable the keylogger in the System Preferences")
}
return accessEnabled == true
}
class ApplicationDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(notification: NSNotification?) {
acquirePrivileges()
// keyboard listeners
NSEvent.addGlobalMonitorForEventsMatchingMask(
NSEventMask.KeyDownMask, handler: {(event: NSEvent) in
print(event)
})
}
}
// preparing main loop
let application = NSApplication.sharedApplication()
let applicationDelegate = MyObserver()
application.delegate = applicationDelegate
application.activateIgnoringOtherApps(true)
application.run()
If you are just interested in only catching non-accessibility events (e.g.: NSWorkspaceDidActivateApplicationNotification
) you can get away with much fewer lines of code as you only need NSRunLoop.mainRunLoop().run()
. I only added this example since I saw your while true
event-loop, which never will let you listen to any system-events, since its blocking the main-thread.
class MyObserver: NSObject
{
override init() {
super.init()
// app listeners
NSWorkspace.sharedWorkspace().notificationCenter.addObserver(self, selector: "SwitchedApp:", name: NSWorkspaceDidActivateApplicationNotification, object: nil)
}
func SwitchedApp(notification: NSNotification!)
{
print(notification)
}
}
let observer = MyObserver()
// simply to keep the command line tool alive - as a daemon process
NSRunLoop.mainRunLoop().run()
Upvotes: 14
Reputation: 198
As a first step towards the solution I suggest to make sure the local version of the monitor works:
NSEvent.addLocalMonitorForEventsMatchingMask(NSEventMask.KeyDownMask, handler: {(evt: NSEvent!) -> NSEvent in
NSLog("Local Keydown: " + evt.characters! + " (" + String(evt.keyCode) + ")");
return evt;
});
If it works, go onto the global version:
NSEvent.addGlobalMonitorForEventsMatchingMask(NSEventMask.KeyDownMask, handler: {(evt: NSEvent!) -> Void in
NSLog("Global Keydown: " + evt.characters! + " (" + String(evt.keyCode) + ")");
});
If the local works, but the global doesn't, this means you didn't enable your app (or while developing, XCode) in [System Preferences / Security & Privacy / Accessibility] to control your computer.
If none of them works, then maybe it doesn't work with console applications at all...
Upvotes: 4