我想模拟按下 Fn(地球仪)+Control+右箭头,但我遇到了一个问题,Fn 修饰符似乎被忽略,并且系统的行为就像只正在按下 Control+右箭头。
在 macOS 中,Fn+右箭头(键代码
124
)的组合被视为 End(键代码 119
),因此仅模拟 Control+End 组合是合乎逻辑的尝试一下,甚至使用它也没有达到预期的行为。在 Sequoia 上,它不是将窗口移动到屏幕的右边缘,而是切换到下一个空间,这是 Control+右箭头的默认行为。
演示:
import SwiftUI
@main
struct LittleKeypressDemo: App {
var body: some Scene {
Window("Keypress Demo", id: "keypress-demo") {
ContentView()
}
.windowStyle(.hiddenTitleBar)
.windowResizability(.contentSize)
.windowBackgroundDragBehavior(.enabled)
}
}
struct ContentView: View {
var body: some View {
VStack {
KeyPressButton(
icon: "arrowtriangle.right.fill",
keyCode: 124,
eventFlags: [.maskSecondaryFn, .maskControl]
)
KeyPressButton( // this works
label: "C",
keyCode: 8,
eventFlags: [.maskSecondaryFn, .maskControl]
)
KeyPressButton(
icon: "arrow.down.to.line",
keyCode: 119,
eventFlags: [ /* .maskSecondaryFn, */ .maskControl]
)
}
.padding()
}
}
struct KeyPressButton: View {
let icon: String?
let label: String?
let keyCode: CGKeyCode
let eventFlags: CGEventFlags
init(
icon: String? = nil,
label: String? = nil,
keyCode: CGKeyCode,
eventFlags: CGEventFlags
) {
self.icon = icon
self.label = label
self.keyCode = keyCode
self.eventFlags = eventFlags
}
var body: some View {
Button(action: {
simulateKeyPress(keyCode: keyCode, eventFlags: eventFlags)
}) {
HStack {
if eventFlags.contains(.maskSecondaryFn) {
Image(systemName: "globe")
}
if eventFlags.contains(.maskControl) {
Image(systemName: "control")
}
if let icon = icon {
Image(systemName: icon)
} else if let label = label {
Text(label)
}
}
}
.controlSize(.large)
}
}
func simulateKeyPress(keyCode: CGKeyCode, eventFlags: CGEventFlags) {
guard let eventDown = CGEvent(
keyboardEventSource: nil,
virtualKey: keyCode,
keyDown: true
),
let eventUp = CGEvent(
keyboardEventSource: nil,
virtualKey: keyCode,
keyDown: false
) else {
print("Error creating CGEvent for keyCode \(keyCode)")
return
}
eventDown.flags = eventFlags
eventUp.flags = eventFlags
eventDown.post(tap: .cghidEventTap)
eventUp.post(tap: .cghidEventTap)
}
(我添加了 Fn+Control+C 以显示窗口居中的效果。)
预期行为:在 macOS Sequoia 上模拟组合键 Fn+Control+右箭头 应将当前窗口移动到屏幕的右半部分,并激活菜单项 Window→Move &调整→Right的大小,就像Fn+Control+C在我的代码示例中为Window→Center所做的那样。
问题:我明显遗漏了什么?是否有其他方法或解决方法可以正确模拟此行为?
Apple 旧文档文章中关于 处理关键事件 的信息没有帮助,这个 answer 也没有帮助。
(顺便说一句,窗口管理在这里完全无关。我特别询问模拟这些按键。)
任何见解或建议将不胜感激。
.maskSecondaryFn
中的 CGEventFlags
对应于 0xFF0100000030
,但对于真正的硬件 IOHID
键,来自 Fn (Globe)
的使用 ID 是 0xFF00000003
。这种不匹配可能会导致按键模拟期间出现问题。现在的问题是:如何使用它来模拟按键?该问题完全是由于 macOS 事件处理系统中的错误造成的。您可以在 macOS 内置的屏幕键盘查看器中观察到相同的行为 - 当模拟
Fn
+ Control
+ any arrow
组合键时,会导致不正确的响应。不幸的是,在 Apple 解决这个问题之前,没有可用的解决方法。