据我所知,没有可用的 Python 库,因此您将调用本机 API。好消息是 PyObjC(在最近的操作系统版本中内置了 Python)通常可以让这变得简单。
有两个主要选择。要使其中任何一个工作,您的应用程序必须有一个 Cocoa/CoreFoundation 运行循环(就像在 Windows 中一样,很多东西要求您成为“Windows GUI 可执行文件”而不是“命令行可执行文件”),我赢了这里不解释怎么做。 (如果您不知道如何使用 Python,请找到一个关于在 Python 中构建 GUI 应用程序的好教程,因为这是最简单的方法。)
最简单的选择是 Cocoa 全局事件监视器 API。然而,它有一些主要的局限性。您只会收到前往另一个应用程序的事件 - 这意味着媒体键、全局热键以及由于某种原因被忽略的键将不会显示。此外,您需要“可访问性值得信赖”。 (最简单的方法是要求用户在系统偏好设置的通用访问面板中全局打开它。)
硬选项是 Quartz 事件 Tap API。它更加灵活,并且只需要适当的权限(根据您使用的设置,可能包括可信任的可访问性和/或以 root 身份运行),并且它更加强大,但需要很多开始需要做更多的工作,如果出错,可能会搞砸系统(例如,通过吃掉所有按键和鼠标事件,这样它们就永远不会进入操作系统,并且除非使用电源按钮,否则无法重新启动)。
有关所有相关函数的参考,请参阅https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nsevent_Class/Reference/Reference.html https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/nsevent_Class/Reference/Reference.html(对于 NSEvent)和https://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html https://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html(对于石英事件)。进行一些谷歌搜索应该会发现大量 Objective C(对于 NSEvent)或 C(对于 CGEventTap)的示例代码,但在 Python 中却很少或根本没有,所以我将展示一些小片段来说明如何移植示例到 Python:
import Cocoa
def evthandler(event):
pass # this is where you do stuff; see NSEvent documentation for event
observer = Cocoa.NSEvent.addGlobalMonitorForEventsMatchingMask_handler_(NSKeyDown, evthandler)
# when you're done
Cocoa.NSEvent.removeMonitor_(observer)
import Quartz
def evthandler(proxy, type, event, refcon):
pass # Here's where you do your stuff; see CGEventTapCallback
return event
source = Quartz.CGEventSourceCreate(Quartz.kCGEventSourceStateHIDSystemState)
tap = Quartz.CGEventTapCreate(Quartz.kCGSessionEventTap,
Quartz.kCGHeadInsertEventTap,
Quartz.kCGEventTapOptionListenOnly,
(Quartz.CGEventMaskBit(Quartz.kCGEventKeyDown) |
Quartz.CGEventMaskBit(Quartz.kCGEventKeyUp)),
handler,
refcon)
另一个选项,与 Quartz 事件的级别大致相同,是 Carbon 事件(从 InstallEventHandler 开始)。然而,Carbon 已经过时了,而且最重要的是,从 Python 中获取它更困难,所以除非你有某种特定的理由要这样做,否则不要这样做。
还有一些其他方法可以达到相同的目的 - 例如,使用 DYLD_INSERT_LIBRARIES 或 SIMBL 将一些代码插入到每个应用程序中 - 但我想不出可以在纯 Python 中完成的任何其他操作。