Skip to content

Instantly share code, notes, and snippets.

@ljos
Last active January 6, 2024 07:36
Show Gist options
  • Star 68 You must be signed in to star a gist
  • Fork 11 You must be signed in to fork a gist
  • Save ljos/3019549 to your computer and use it in GitHub Desktop.
Save ljos/3019549 to your computer and use it in GitHub Desktop.
Showing how to listen to all keypresses in OS X through the Cocoa API using Python and PyObjC
#!/usr/bin/env python
#
# cocoa_keypress_monitor.py
# Copyright © 2016 Bjarte Johansen <Bjarte.Johansen@gmail.com>
#
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# “Software”), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Usage:
#
# Goto System Preferences > Security & Privacy > Accessibility and add
# Python to apps allowed to control your computer. If it is not in the
# list, the easiest is to run this file first and it should appear.
from AppKit import NSApplication, NSApp
from Foundation import NSObject, NSLog
from Cocoa import NSEvent, NSKeyDownMask
from PyObjCTools import AppHelper
class AppDelegate(NSObject):
def applicationDidFinishLaunching_(self, notification):
mask = NSKeyDownMask
NSEvent.addGlobalMonitorForEventsMatchingMask_handler_(mask, handler)
def handler(event):
try:
NSLog(u"%@", event)
except KeyboardInterrupt:
AppHelper.stopEventLoop()
def main():
app = NSApplication.sharedApplication()
delegate = AppDelegate.alloc().init()
NSApp().setDelegate_(delegate)
AppHelper.runEventLoop()
if __name__ == '__main__':
main()
@gourneau
Copy link

You are awesome @ljos! This is working for me with OS X 10.7 on a 64 bit machine!

@gourneau
Copy link

wait, your first version did:

https://gist.github.com/3019988

This one is giving me this error:

Traceback (most recent call last):
File "selfspy.py", line 4, in
from Foundation import NSApplication, NSObject, NSLog
ImportError: cannot import name NSApplication

@ljos
Copy link
Author

ljos commented Jun 29, 2012

It works for me, what version of PyObjC are you using?

And python version?

@bdash
Copy link

bdash commented Jun 29, 2012

NSApplication should be imported from AppKit (or Cocoa) rather than Foundation since that's where it is defined.

@mlsimpson
Copy link

Same issue here.

I don't know what version of PyObjC i'm using; how do I tell?

@ljos
Copy link
Author

ljos commented Jun 29, 2012

How did all these people suddenly see my gist?

Anyway, can you guys see if things work after the latest update (on advice from @bdash) ?

I am not sure how to see what version of PyObjC you are using. I am using Python2.7 and head from https://bitbucket.org/ronaldoussoren/pyobjc/

@gourneau
Copy link

Thanks @bdash importing from AppKit works with PyObjC 2.3. Which is the version on pipy

@ljos I posted this on hacker news and tweeted about it :)

@cuilkid
Copy link

cuilkid commented Jun 29, 2012

I get the following error:

type 'exceptions.TypeError' : Argument 3 is a block, but no signature available

I also cleaned up the code since it had some typos, did I introduce errors.... ? Thanks in advanced
https://gist.github.com/3020934

Also I'm on OS X 10.6.8

@ljos
Copy link
Author

ljos commented Jun 29, 2012

Does it say where it gives that? If you could paste the whole error that would be helpful(, unless that is the whole error; some of the PyObjC errors are really bad).

It might be that you have to enable access for assistive devices in 'System Preferences>Universal Access'.

@cuilkid
Copy link

cuilkid commented Jun 29, 2012

I updated the gist with some "debugging output"

$ python osx_keylogger.py
E
A
2012-06-29 15:10:12.626 Python[4333:d07] <type 'exceptions.TypeError'>: Argument 3 is a block, but no signature available

@cuilkid
Copy link

cuilkid commented Jun 29, 2012

I clicked on "enable access for assistive devices" under the keyboard tab in System Preferences>Universal Access. I still get the same error.

@ljos
Copy link
Author

ljos commented Jun 29, 2012

See your gist. I have commented what is wrong there.

@cuilkid
Copy link

cuilkid commented Jun 29, 2012

Can you check out my gist again, I made the fixes but I still get the same error. Thanks btw, really appreciate your help.

@hrbrmstr
Copy link

Works perfectly in Mountain Lion DP4u2, tho needs to be executed with 'sudo' (which I suspect won't be necessary with the actual release of ML).

@meierjan
Copy link

Doesn't work for me on Mavericks... Just pasted it to textmate and executed .. whats wrong?

@ljos
Copy link
Author

ljos commented Dec 4, 2013

@Jan1337z , have you installed the dependencies?

@ljos
Copy link
Author

ljos commented Dec 4, 2013

@Jan1337z, you have to add the terminal application you run python from to application that are allowed to control your computer. This can be done in System Preferences > Privacy > Accessability.

@Ali-Razmjoo
Copy link

Hi huys , i enable access for assistive devices , but how can work
without it ? i have a ruby code , it can use without enable this
i need python version please

check this

https://github.com/rapid7/metasploit-framework/blob/master/modules/post/osx/capture/keylog_recorder.rb

@ljos
Copy link
Author

ljos commented Jul 19, 2014

@G3n3Rall This codes metasploit to do the heavy lifting. My code uses the Cocoa library calls directly and requires that you enable the access to assistive devices because of that. If you need it to work without the assistive devices enabled you will need to figure out how to work with python and metasploit (or figure out how metasploit does that).

@Quentin-M
Copy link

Hey.

Kinda strange because it generates the following exception when using ^C

An uncaught exception was raised <type 'exceptions.KeyboardInterrupt'>: 
(
    0   CoreFoundation                      0x00007fff8f87564c __exceptionPreprocess + 172
    1   libobjc.A.dylib                     0x00007fff88e916de objc_exception_throw + 43
    2   CoreFoundation                      0x00007fff8f8751e9 -[NSException raise] + 9
    3   _objc.so                            0x00000001012e1a8b PyObjCErr_ToObjCWithGILState + 46
    4   _objc.so                            0x00000001012ce52d PyObjCFFI_MakeClosure + 5097
    5   libffi.dylib                        0x00007fff8ed73a07 ffi_closure_unix64_inner + 511
    6   libffi.dylib                        0x00007fff8ed730c6 ffi_closure_unix64 + 70
    7   HIToolbox                           0x00007fff8c54232c _ZL23DispatchEventToHandlersP14EventTargetRecP14OpaqueEventRefP14HandlerCallRec + 1260
    8   HIToolbox                           0x00007fff8c54176e _ZL30SendEventToEventTargetInternalP14OpaqueEventRefP20OpaqueEventTargetRefP14HandlerCallRec + 386
    9   HIToolbox                           0x00007fff8c5415e2 SendEventToEventTargetWithOptions + 43
    10  HIToolbox                           0x00007fff8c5771fe _ZL29ToolboxEventDispatcherHandlerP25OpaqueEventHandlerCallRefP14OpaqueEventRefPv + 1762
    11  HIToolbox                           0x00007fff8c542a55 _ZL23DispatchEventToHandlersP14EventTargetRecP14OpaqueEventRefP14HandlerCallRec + 3093
    12  HIToolbox                           0x00007fff8c54176e _ZL30SendEventToEventTargetInternalP14OpaqueEventRefP20OpaqueEventTargetRefP14HandlerCallRec + 386
    13  HIToolbox                           0x00007fff8c556286 SendEventToEventTarget + 40
    14  AppKit                              0x00007fff94c0debb _DPSNextEvent + 2990
    15  AppKit                              0x00007fff94c0ce80 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 194
    16  AppKit                              0x00007fff94c00e23 -[NSApplication run] + 594
    17  libffi.dylib                        0x00007fff8ed72f44 ffi_call_unix64 + 76
    18  ???                                 0x00007fba864c94a0 0x0 + 140439093810336
)

@kismet-
Copy link

kismet- commented Jan 21, 2015

What if I want to write the output to a file?

@ljos
Copy link
Author

ljos commented Apr 1, 2015

@Quentin-M I think pyObjC returned a python KeyboardInterrupt before, but it seems it is not doing that anymore. It should be easy to fix, but I think that should be an exercise for the reader.

@kismet- You should be able to use standard python commands to output to a file, or you can use gurgeh/selfspy.

@JacyNewbs
Copy link

What is it supposed to print? I run and get no errors but also get no output, is this normal? It doesn't seem like it is, how do i prevent this?

@ljos
Copy link
Author

ljos commented Mar 8, 2016

@JacyNewbs It should print the event that contains the keyboard press. You probably have to turn on assistive devices and add python to the programs allowed to control your computer.

@jsrini78
Copy link

its working for me. thank you.
However, I have the following issue

  1. unable to stop the code ctl+C
  2. I want to create a log file in addition to display
    could you let me know the step. I tried , since it did not come out of loop I was not able to write in a file

@CrzPhil
Copy link

CrzPhil commented Aug 13, 2016

I get this error :
Traceback (most recent call last):
File "keylogger.py", line 1, in
from AppKit import NSApplication, NSApp
ImportError: No module named AppKit

And before you say somethin bout you gotta install appkit, I have I did all this pip install appkit thingy and it installed I think.
Please HELP!!!!

@skabbit
Copy link

skabbit commented Sep 3, 2016

Unable to stop the code control + C.
And can't get into handler. :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment