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.
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()
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...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With