3

所以我被要求将一些内部帮助应用程序移植到 Mac OS X 10.7。

工作得很好,因为平台相关的代码无论如何都是最少的,但是一个应用程序需要一个系统范围的快捷方式来运行(即RegisterHotkey功能),我找不到任何关于如何在 Mac 上执行此操作的文档。

该程序使用 Python 3.2 的 PyQt gui。而windows对应的代码基本上是:

def register_hotkey(self):
    hwnd = int(self.winId())
    modifiers, key = self._get_hotkey()
    user32.RegisterHotKey(hwnd, self._MESSAGE_ID, modifiers, key)

然后接收热键事件:

def winEvent(self, msg):
    if msg.message == w32.WM_HOTKEY:
        self.handle_hotkey()
        return True, id(msg)
    return False, id(msg)

请注意,我不需要 python 变体,我可以轻松编写一个简单的 c 扩展 - 因此也欢迎 C/objective-c 解决方案。

4

3 回答 3

9

我最近编写了一个quodlibet的扩展来捕获多媒体键(因为被 quodlibet 本身所吸引);对于您的设置,同样的过程适用。

我使用 QuartzCGEventTapCreate钩子和事件循环以及 Cocoa AppKit 框架来破译关键代码来实现这一点。

以下代码注册了一个传递全局按键的python回调,并启动事件循环:

import Quartz
from AppKit import NSKeyUp, NSSystemDefined, NSEvent

# Set up a tap, with type of tap, location, options and event mask
tap = Quartz.CGEventTapCreate(
    Quartz.kCGSessionEventTap, # Session level is enough for our needs
    Quartz.kCGHeadInsertEventTap, # Insert wherever, we do not filter
    Quartz.kCGEventTapOptionListenOnly, # Listening is enough
    Quartz.CGEventMaskBit(NSSystemDefined), # NSSystemDefined for media keys
    keyboardTapCallback,
    None
)

runLoopSource = Quartz.CFMachPortCreateRunLoopSource(None, tap, 0)
Quartz.CFRunLoopAddSource(
    Quartz.CFRunLoopGetCurrent(),
    runLoopSource,
    Quartz.kCFRunLoopDefaultMode
)
# Enable the tap
Quartz.CGEventTapEnable(tap, True)
# and run! This won't return until we exit or are terminated.
Quartz.CFRunLoopRun()

我只为系统定义的键(媒体键)定义了一个水龙头;您必须指定不同的事件掩码(CGEventMaskBit具有一个或多个事件类型);例如Quartz.CGEventMaskBit(Quartz.kCGEventKeyUp)按键事件。

回调应该具有以下签名(它实现CGEventTapCallBack了 Quartz API 中的方法

def keyboardTapCallback(proxy, type_, event, refcon):
    # Convert the Quartz CGEvent into something more useful
    keyEvent = NSEvent.eventWithCGEvent_(event)

我将 Quartz 事件转换为NSEvent,因为我可以在 Mac 多媒体键上找到的所有信息都与该类有关。

原则上,您也可以使用 AppKit API 实现相同的功能,但是您的 Python 应用程序被视为 Mac 应用程序(在 Dock 中可见,带有图标和所有内容),而我希望它完全保留在后台。

于 2012-07-05T16:55:49.167 回答
2

借助谷歌的力量,我找到了这段代码,它允许注册 Mac OS X 的全局热键

在将 Objective-C 自指针传递给 C 函数时,您需要添加Carbon框架,并且可能需要添加桥接转换。ARC

至少,您还需要:

#import <Carbon/Carbon.h>

键码可以在这个页面上看到,解释虚拟键码

于 2012-07-05T15:56:17.283 回答
0

为什么从来没有人提到过hammerspoon,它支持自定义全局系统快捷方式,可以调用shell命令或启动像Safari、PHOTOSHOP这样的UI应用程序。

以下是我编写的示例,演示如何使用全局热键调用 shell 函数。 https://gist.github.com/BigSully/0e59ab97f148bc167ea19dbd42ebef4b

使用hs.execute来执行 shell 命令,可以是非交互的,也可以是交互的。

hs.hotkey.bind({"cmd", "alt", "ctrl"}, "P", function()
  local output = hs.execute("toggleProxy", true)
  hs.alert.show(output)
end)

或使用hs.application.launchOrFocus启动应用程序 hs.application.launchOrFocus("Safari")

于 2020-01-17T15:41:50.243 回答