我正在尝试在我的Mac OS X应用程序中使用Swift编写一个处理程序,用于全局(系统范围)热键组合,但我找不到适当的文档.我已经读过,我必须在一些传统的Carbon API中乱用它,有没有更好的方法?你能告诉我一些Swift代码的概念证明吗?提前致谢!
Cha*_*roe 12
从Swift 2.0开始,您现在可以将函数指针传递给C API.
var gMyHotKeyID = EventHotKeyID()
gMyHotKeyID.signature = OSType("swat".fourCharCodeValue)
gMyHotKeyID.id = UInt32(keyCode)
var eventType = EventTypeSpec()
eventType.eventClass = OSType(kEventClassKeyboard)
eventType.eventKind = OSType(kEventHotKeyPressed)
// Install handler.
InstallEventHandler(GetApplicationEventTarget(), {(nextHanlder, theEvent, userData) -> OSStatus in
var hkCom = EventHotKeyID()
GetEventParameter(theEvent, EventParamName(kEventParamDirectObject), EventParamType(typeEventHotKeyID), nil, sizeof(EventHotKeyID), nil, &hkCom)
/// Check that hkCom in indeed your hotkey ID and handle it.
}, 1, &eventType, nil, nil)
// Register hotkey.
let status = RegisterEventHotKey(UInt32(keyCode), UInt32(modifierKeys), gMyHotKeyID, GetApplicationEventTarget(), 0, &hotKeyRef)
Run Code Online (Sandbox Code Playgroud)
Rob*_*ier 10
我不相信你今天可以在100%Swift中做到这一点.你需要调用InstallEventHandler()或者CGEventTapCreate(),这两个都需要一个CFunctionPointer,不能在Swift中创建.您最好的计划是使用已建立的ObjC解决方案,如DDHotKey和桥接Swift.
您可以尝试使用NSEvent.addGlobalMonitorForEventsMatchingMask(handler:),但这只会复制事件.你不能消耗它们.这意味着热键也将传递给当前活动的应用程序,这可能会导致问题.这是一个例子,但我推荐ObjC方法; 它几乎肯定会更好地工作.
let keycode = UInt16(kVK_ANSI_X)
let keymask: NSEventModifierFlags = .CommandKeyMask | .AlternateKeyMask | .ControlKeyMask
func handler(event: NSEvent!) {
if event.keyCode == self.keycode &&
event.modifierFlags & self.keymask == self.keymask {
println("PRESSED")
}
}
// ... to set it up ...
let options = NSDictionary(object: kCFBooleanTrue, forKey: kAXTrustedCheckOptionPrompt.takeUnretainedValue() as NSString) as CFDictionaryRef
let trusted = AXIsProcessTrustedWithOptions(options)
if (trusted) {
NSEvent.addGlobalMonitorForEventsMatchingMask(.KeyDownMask, handler: self.handler)
}
Run Code Online (Sandbox Code Playgroud)
这还要求为此应用程序批准可访问性服务.它也不会捕获发送到您自己的应用程序的事件,因此您必须使用响应程序链捕获它们,我们使用它addLocalMointorForEventsMatchingMask(handler:)来添加本地处理程序.
设置的快速Swift 3更新:
let opts = NSDictionary(object: kCFBooleanTrue, forKey: kAXTrustedCheckOptionPrompt.takeUnretainedValue() as NSString) as CFDictionary
guard AXIsProcessTrustedWithOptions(opts) == true else { return }
NSEvent.addGlobalMonitorForEvents(matching: .keyDown, handler: self.handler)
Run Code Online (Sandbox Code Playgroud)
我维护这个 Swift 包,它可以轻松地将全局键盘快捷键添加到您的应用程序中,也可以让用户设置自己的键盘快捷键。
\nimport SwiftUI\nimport KeyboardShortcuts\n\n// Declare the shortcut for strongly-typed access.\nextension KeyboardShortcuts.Name {\n static let toggleUnicornMode = Self("toggleUnicornMode")\n}\n\n@main\nstruct YourApp: App {\n @StateObject private var appState = AppState()\n\n var body: some Scene {\n WindowGroup {\n // \xe2\x80\xa6\n }\n Settings {\n SettingsScreen()\n }\n }\n}\n\n@MainActor\nfinal class AppState: ObservableObject {\n init() {\n // Register the listener.\n KeyboardShortcuts.onKeyUp(for: .toggleUnicornMode) { [self] in\n isUnicornMode.toggle()\n }\n }\n}\n\n// Present a view where the user can set the shortcut they want.\nstruct SettingsScreen: View {\n var body: some View {\n Form {\n HStack(alignment: .firstTextBaseline) {\n Text("Toggle Unicorn Mode:")\n KeyboardShortcuts.Recorder(for: .toggleUnicornMode)\n }\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n本例中使用了 SwiftUI,但它也支持 Cocoa。
\n以下代码适用于 Swift 5.0.1。此解决方案是 Charlie Monroe 接受的答案中的解决方案和 Rob Napier 建议使用 DDHotKey 的组合。
DDHotKey 似乎开箱即用,但它有一个我必须更改的限制:eventKind 是硬编码的,kEventHotKeyReleased而我同时需要kEventHotKeyPressed和kEventHotKeyReleased事件类型。
eventSpec.eventKind = kEventHotKeyReleased;
Run Code Online (Sandbox Code Playgroud)
如果您想同时处理 Pressed 和 Released 事件,只需添加第二个InstallEventHandler调用来注册其他事件类型。
这是为该kEventHotKeyReleased类型注册“Command + R”键的代码的完整示例。
import Carbon
extension String {
/// This converts string to UInt as a fourCharCode
public var fourCharCodeValue: Int {
var result: Int = 0
if let data = self.data(using: String.Encoding.macOSRoman) {
data.withUnsafeBytes({ (rawBytes) in
let bytes = rawBytes.bindMemory(to: UInt8.self)
for i in 0 ..< data.count {
result = result << 8 + Int(bytes[i])
}
})
}
return result
}
}
class HotkeySolution {
static
func getCarbonFlagsFromCocoaFlags(cocoaFlags: NSEvent.ModifierFlags) -> UInt32 {
let flags = cocoaFlags.rawValue
var newFlags: Int = 0
if ((flags & NSEvent.ModifierFlags.control.rawValue) > 0) {
newFlags |= controlKey
}
if ((flags & NSEvent.ModifierFlags.command.rawValue) > 0) {
newFlags |= cmdKey
}
if ((flags & NSEvent.ModifierFlags.shift.rawValue) > 0) {
newFlags |= shiftKey;
}
if ((flags & NSEvent.ModifierFlags.option.rawValue) > 0) {
newFlags |= optionKey
}
if ((flags & NSEvent.ModifierFlags.capsLock.rawValue) > 0) {
newFlags |= alphaLock
}
return UInt32(newFlags);
}
static func register() {
var hotKeyRef: EventHotKeyRef?
let modifierFlags: UInt32 =
getCarbonFlagsFromCocoaFlags(cocoaFlags: NSEvent.ModifierFlags.command)
let keyCode = kVK_ANSI_R
var gMyHotKeyID = EventHotKeyID()
gMyHotKeyID.id = UInt32(keyCode)
// Not sure what "swat" vs "htk1" do.
gMyHotKeyID.signature = OSType("swat".fourCharCodeValue)
// gMyHotKeyID.signature = OSType("htk1".fourCharCodeValue)
var eventType = EventTypeSpec()
eventType.eventClass = OSType(kEventClassKeyboard)
eventType.eventKind = OSType(kEventHotKeyReleased)
// Install handler.
InstallEventHandler(GetApplicationEventTarget(), {
(nextHanlder, theEvent, userData) -> OSStatus in
// var hkCom = EventHotKeyID()
// GetEventParameter(theEvent,
// EventParamName(kEventParamDirectObject),
// EventParamType(typeEventHotKeyID),
// nil,
// MemoryLayout<EventHotKeyID>.size,
// nil,
// &hkCom)
NSLog("Command + R Released!")
return noErr
/// Check that hkCom in indeed your hotkey ID and handle it.
}, 1, &eventType, nil, nil)
// Register hotkey.
let status = RegisterEventHotKey(UInt32(keyCode),
modifierFlags,
gMyHotKeyID,
GetApplicationEventTarget(),
0,
&hotKeyRef)
assert(status == noErr)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7905 次 |
| 最近记录: |