模拟 Fn + Control + 箭头键事件会忽略 Fn

问题描述 投票:0回答:1

我想模拟按下 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+右箭头 应将当前窗口移动到屏幕的右半部分,并激活菜单项 WindowMove &调整Right的大小,就像Fn+Control+C在我的代码示例中为WindowCenter所做的那样。

问题:我明显遗漏了什么?是否有其他方法或解决方法可以正确模拟此行为?

Apple 旧文档文章中关于 处理关键事件 的信息没有帮助,这个 answer 也没有帮助。

(顺便说一句,窗口管理在这里完全无关。我特别询问模拟这些按键。)

任何见解或建议将不胜感激。


更新:我想我已经找到问题所在了。看起来像
.maskSecondaryFn
中的
CGEventFlags
对应于
0xFF0100000030
,但对于真正的硬件
IOHID
键,来自
Fn (Globe)
的使用 ID 是
0xFF00000003
。这种不匹配可能会导致按键模拟期间出现问题。现在的问题是:如何使用它来模拟按键?
swift macos swiftui appkit macos-carbon
1个回答
0
投票

该问题完全是由于 macOS 事件处理系统中的错误造成的。您可以在 macOS 内置的屏幕键盘查看器中观察到相同的行为 - 当模拟

Fn
+
Control
+
any arrow
组合键时,会导致不正确的响应。不幸的是,在 Apple 解决这个问题之前,没有可用的解决方法。

© www.soinside.com 2019 - 2024. All rights reserved.