Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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

This comment has been minimized.

Copy link

gourneau commented Jun 29, 2012

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

@gourneau

This comment has been minimized.

Copy link

gourneau commented Jun 29, 2012

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

This comment has been minimized.

Copy link
Owner Author

ljos commented Jun 29, 2012

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

And python version?

@bdash

This comment has been minimized.

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

This comment has been minimized.

Copy link

mlsimpson commented Jun 29, 2012

Same issue here.

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

@ljos

This comment has been minimized.

Copy link
Owner 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

This comment has been minimized.

Copy link

gourneau commented Jun 29, 2012

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

This comment has been minimized.

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

This comment has been minimized.

Copy link
Owner 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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

Copy link
Owner Author

ljos commented Jun 29, 2012

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

@cuilkid

This comment has been minimized.

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

This comment has been minimized.

Copy link

hrbrmstr commented Jun 29, 2012

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

This comment has been minimized.

Copy link

meierjan commented Nov 13, 2013

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

@ljos

This comment has been minimized.

Copy link
Owner Author

ljos commented Dec 4, 2013

@Jan1337z , have you installed the dependencies?

@ljos

This comment has been minimized.

Copy link
Owner 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

This comment has been minimized.

Copy link

Ali-Razmjoo commented May 25, 2014

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

This comment has been minimized.

Copy link
Owner 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

This comment has been minimized.

Copy link

Quentin-M commented Jan 5, 2015

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-

This comment has been minimized.

Copy link

kismet- commented Jan 21, 2015

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

@ljos

This comment has been minimized.

Copy link
Owner 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

This comment has been minimized.

Copy link

JacyNewbs commented Nov 14, 2015

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

This comment has been minimized.

Copy link
Owner 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

This comment has been minimized.

Copy link

jsrini78 commented Aug 10, 2016

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
@CrazyAddictionz

This comment has been minimized.

Copy link

CrazyAddictionz 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

This comment has been minimized.

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
You can’t perform that action at this time.