Python捕获OS X上的文本文件中的击键值

时间:2012-09-12 13:46:23

标签: python macos pyobjc

我正在尝试监控Macbook上的击键,以便构建统计分析器。但是我怎样才能将这些字符与“事件”隔离开来,这更像是:

  

NSEvent:type = KeyDown loc =(850,248)time = 66551.8 flags = 0x100 win = 0x0   winNum = 0 ctxt = 0x0 chars =“l”unmodchars =“l”repeat = 0 keyCode = 37

所以有人知道如何根据下面发布的脚本,使用chars(来自NSEvent)的值来实现一个.txt doc吗?我需要一个带有按键的文本文件,以便在其上运行我的其他脚本并分析频率等...

提前致谢;)

#!/usr/bin/python
# -*- coding: utf-8 -*-


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:
        print event
    except KeyboardInterrupt:
        AppHelper.stopEventLoop()

def main():
    app = NSApplication.sharedApplication()
    delegate = AppDelegate.alloc().init()
    NSApp().setDelegate_(delegate)
    AppHelper.runEventLoop()

if __name__ == '__main__':
    main()

2 个答案:

答案 0 :(得分:7)

#!/usr/bin/python2.6

#  You _must_ turn on assistive devices under Accessibility prefpane 
# for any of this code to work. Otherwise it won't do anything.

from Cocoa import *
from Foundation import *
from PyObjCTools import AppHelper
import keycode
import string
import sys

class AppDelegate(NSObject):
    def applicationDidFinishLaunching_(self, aNotification):
        NSEvent.addGlobalMonitorForEventsMatchingMask_handler_(NSKeyDownMask, handler)

def handler(event):
    if event.type() == NSKeyDown and keycode.tostring(event.keyCode()) in string.printable:
        print keycode.tostring(event.keyCode())

def main():
    app = NSApplication.sharedApplication()
    delegate = AppDelegate.alloc().init()
    NSApp().setDelegate_(delegate)
    AppHelper.runEventLoop()


if __name__ == '__main__':
   main()

我挖了一下,发现github用户'gurgeh的OSX修改为他的分支中的selfspy - https://github.com/gurgeh/selfspy/blob/new_activity/sniff_cocoa.py

我把一些自己的想法融入其中,这就是结果。感谢gurgeh如何捕获窗口更改事件 - 这使得关键记录器更加有趣,因为您基本上可以忽略不提供有趣事件的应用程序,或者对于具有统计意义的图表,您可以使用最多的应用程序和你正在做什么..

#!/usr/bin/python2.6

import exceptions
import sys
from Foundation import NSObject, NSLog
from AppKit import NSApplication, NSApp, NSWorkspace
from Cocoa import *
from Quartz import CGWindowListCopyWindowInfo, kCGWindowListOptionOnScreenOnly, kCGNullWindowID
from PyObjCTools import AppHelper
import keycode

evtypes = dict(
    NSLeftMouseDown     = 1,
    NSLeftMouseUp       = 2,
    NSRightMouseDown    = 3,
    NSRightMouseUp      = 4,
    NSMouseMoved        = 5,
    NSLeftMouseDragged  = 6,
    NSRightMouseDragged = 7,
    NSMouseEntered      = 8,
    NSMouseExited       = 9,
    NSKeyDown           = 10,
    NSKeyUp             = 11,
    NSFlagsChanged      = 12,
    NSAppKitDefined     = 13,
    NSSystemDefined     = 14,
    NSApplicationDefined = 15,
    NSPeriodic          = 16,
    NSCursorUpdate      = 17,
    NSScrollWheel       = 22,
    NSTabletPoint       = 23,
    NSTabletProximity   = 24,
    NSOtherMouseDown    = 25,
    NSOtherMouseUp      = 26,
    NSOtherMouseDragged = 27
)

evtypes_rev = dict([[v,k] for k,v in evtypes.items()])

class Hooker(object):
    def __call__(self, *args, **kwargs):
        try:
            evt = kwargs.get('event')
            del kwargs['event'] 
            items = ' '.join( [ x[0]+"="+unicode(x[1]) for x in kwargs.iteritems()] )
            print "%20s | %22s | %s" % ( self.__class__.__name__, evtypes_rev[evt.type()], items)
        except Exception as e:
            print 'Horrific error!', e
            AppHelper.stopEventLoop()
            sys.exit(0)

class KeyHooker(Hooker): pass
class MouseButtonHooker(Hooker): pass
class MouseMoveHooker(Hooker): pass
class ScreenHooker(Hooker): pass

class SniffCocoa:

    def __init__(self):

        self.key_hook = KeyHooker()
        self.mouse_button_hook = MouseButtonHooker()
        self.mouse_move_hook = MouseMoveHooker()
        self.screen_hook = ScreenHooker()
        self.currentApp = None

    def createAppDelegate (self) :

        sc = self
        class AppDelegate(NSObject):
            def applicationDidFinishLaunching_(self, notification):
                mask = (
                          NSKeyDownMask 
                        | NSKeyUpMask
                        | NSLeftMouseDownMask 
                        | NSLeftMouseUpMask
                        | NSRightMouseDownMask 
                        | NSRightMouseUpMask
                        | NSMouseMovedMask 
                        | NSScrollWheelMask
                       )
                NSEvent.addGlobalMonitorForEventsMatchingMask_handler_(mask, sc.handler)
        return AppDelegate

    def run(self):
        NSApplication.sharedApplication()
        delegate = self.createAppDelegate().alloc().init()
        NSApp().setDelegate_(delegate)
        self.workspace = NSWorkspace.sharedWorkspace()
        AppHelper.runEventLoop()

    def cancel(self):
        AppHelper.stopEventLoop()

    def handler(self, event):

        try:
            activeApps = self.workspace.runningApplications()
            for app in activeApps:
                if app.isActive():
                    if app.localizedName() != self.currentApp:
                        self.currentApp = app.localizedName()
                        options = kCGWindowListOptionOnScreenOnly 
                        windowList = CGWindowListCopyWindowInfo(options, kCGNullWindowID)

                        for window in windowList:
                            if window['kCGWindowOwnerName'] == self.currentApp:
                                geom = window['kCGWindowBounds'] 
                                self.screen_hook( event=event,
                                                name = window['kCGWindowName'],
                                                owner = window['kCGWindowOwnerName'],
                                                x = geom['X'], 
                                                y = geom['Y'], 
                                                w = geom['Width'], 
                                                h = geom['Height'])
                                break
                    break

            loc = NSEvent.mouseLocation()

            # mouse clicky buttons
            if event.type() in ( NSLeftMouseDown, NSRightMouseDown, NSLeftMouseUp, NSRightMouseUp):
                self.mouse_button_hook(event=event, x=loc.x, y=loc.y)

            # mouse scrolly buttons 
            elif event.type() == NSScrollWheel:
                if event.deltaY() > 0 and event.deltaY() < 0:
                    self.mouse_button_hook(event=event, x=loc.x, y=loc.y)
                if event.deltaX() > 0 and event.deltaX() < 0:
                    self.mouse_button_hook(event=event, x=loc.x, y=loc.y)

            # keys down
            elif event.type() in ( NSKeyDown, NSKeyUp ):

                flags = event.modifierFlags()
                modifiers = [] # OS X api doesn't care it if is left or right
                if (flags & NSControlKeyMask):
                    modifiers.append('CONTROL')
                if (flags & NSAlternateKeyMask):
                    modifiers.append('ALTERNATE')
                if (flags & NSCommandKeyMask):
                    modifiers.append('COMMAND')

                self.key_hook(event=event, key=event.keyCode(), char=keycode.tostring( event.keyCode() ), mods=modifiers, is_repeat=event.isARepeat())

            # Mouse moved
            elif event.type() == NSMouseMoved:
                self.mouse_move_hook(event=event, x=loc.x, y=loc.y)
            else:
                pass

        except ( KeyboardInterrupt ) as e:
            print 'handler', e
            AppHelper.stopEventLoop()

if __name__ == '__main__':
    sc = SniffCocoa()
    sc.run()

答案 1 :(得分:1)

使用Keycode模块。只需从这里克隆它并运行&#34; sudo setup.py install&#34; 。你将拥有keycode模块 https://github.com/abarnert/pykeycode