鼠标事件后,自定义碳键事件处理程序失败

p0d*_*eje 6 cocoa macos-carbon appkit swift

我正在尝试编写一个自定义的NSMenu,它能够列出键输入并拦截必要的事件.这是为我的开源剪贴板管理器提供简单的搜索功能.

看起来这样做的唯一方法是安装一个自定义Carbon事件处理程序,它将侦听键事件并相应地处理它们,但似乎这样的自定义处理程序存在问题.

通常情况下,我可以传播下探至其他处理的事件(例如,系统的),他们应该被正常处理.这可以通过简单的回调来完成:

let eventHandlerCallback: EventHandlerUPP = { eventHandlerCallRef, eventRef, userData in
  let response = CallNextEventHandler(eventHandlerCallRef, eventRef!)
  print("Response \(response)")
  return response
}
Run Code Online (Sandbox Code Playgroud)

此回调功能完美,并Response 0始终打印.此响应意味着事件处理正确.

但是,一旦我们在键盘事件之前发送鼠标事件,事情会变得奇怪.在这种情况下,回调失败并打印.此响应表示事件未正确处理.Response -9874

看起来事件无法在我的自定义视图下面的某个地方处理,我不知道究竟在哪里或如何克服这个问题.

为了重现,我已经将代码上传到Gist,可以将其添加到XCode playground并运行.一旦你看到弹出菜单,按某些键(最好是方向键,因为它们不会关闭菜单),然后观察Response 0在控制台中.之后,将光标移动到菜单内并按下更多箭头键.你Response -9874现在应该在控制台中看到.

p0d*_*eje 0

我没能弄清楚为什么会发生这个问题或如何解决它,但我知道可以通过拦截所有按键并手动模拟它们的行为来解决这个问题。

例如,这就是我现在处理向下箭头键的方式,该键应该选择菜单列表中的下一个项目:

class Menu: NSMenu {
  func selectNext() {
    var indexToHighlight = 1
    if let item = highlightedItem {
      indexToHighlight = index(of: item) + 1
    }

    if let itemToHighlight = self.item(at: indexToHighlight) {
      let highlightItemSelector = NSSelectorFromString("highlightItem:")
      perform(highlightItemSelector, with: itemToHighlight)

      if itemToHighlight.isSeparatorItem || !itemToHighlight.isEnabled || itemToHighlight.isHidden {
        selectNext()
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这样,当我收到带有向下箭头键的按键事件时 - 我可以调用该函数并return true防止该事件到达默认NSMenu处理程序。同样,向上键也可以完成。

如果使用返回键,我最终得到以下代码:

class Menu: NSMenu {
  func select() {
    if let item = highlightedItem {
      performActionForItem(at: index(of: item))
      cancelTracking()
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

实现此功能的完整提交是https://github.com/p0deje/Maccy/commit/158610d1d