2

我正在实现一种脚本语言,用户可能会意外导致无限循环。我想让用户有机会通过在键入句点(“。”)键的同时按住命令键来取消这种失控循环。

目前,每行一次,我使用以下代码检查取消:

NSEvent *   evt = [[NSApplication sharedApplication] nextEventMatchingMask: NSKeyDownMask untilDate: [NSDate date] inMode: WILDScriptExecutionEventLoopMode dequeue: YES];
if( evt )
{
    NSString        *   theKeys = [evt charactersIgnoringModifiers];
    if( (evt.modifierFlags & NSCommandKeyMask) && theKeys.length > 0 && [theKeys characterAtIndex: 0] == '.' )
    {
        // +++ cancel script execution here.
    }
}

这样做的问题是它会在脚本运行时吃掉用户可能正在键入的任何键盘事件,即使脚本应该能够检查按键。此外,它不会使相应的 NSKeyUp 事件出列。但是,如果我告诉它也将按键事件出列,它可能会将 keyUp 出列,以便在我的脚本开始之前持有的按键,并且我的应用程序可能永远不会发现按键已被释放。

另外,在我知道它实际上是一个取消事件之前,我不想让任何事件出队,但是没有单独的出队调用,并且仅仅假设第二次调用中最前面的事件将是同一个事件感觉不可靠。即使它保证是第一个,这也意味着用户输入一个'a'然后Cmd-。这意味着我只看到'a'而从来没有看到Cmd-。如果我不使事件出队,则在它后面。

有没有比使用旧的 Carbon 备用 GetKeys() 更好的选择?幸运的是,这似乎在 64 位中可用。

另外,我正在考虑添加一个 NSStatusItem 来添加一个按钮来取消脚本到菜单栏左右。但是我将如何以一种不允许用户选择菜单的方式处理事件,例如,当脚本期望成为主线程的统治者时?

有什么建议么?建议?

4

3 回答 3

2

按照戴夫的建议使用-addLocalMonitorForEventsMatchingMask:可能是最简单的方法,是的。

我只是想补充一点,尽管您感觉不可靠,但事件队列实际上是一个队列,并且事件不会改变顺序。调用-nextEventMatchingMask:inMode:dequeue:NO、检查事件、确定它是您想要处理的事件,然后调用-nextEventMatchingMask:inMode:dequeue:YES以使用它是非常安全的(并且是事件循环中的标准做法)。只需确保两次调用之间的掩码和模式相同即可。

于 2013-04-21T14:56:31.453 回答
1

我建议使用事件监视器。由于您要请求NSApp事件,因此您似乎正在当前进程中运行脚本,因此您只需监视自己进程中的事件(而不是全局)。

有几种方法可以做到这一点(子类化NSApplication和覆盖-sendEvent:,放入事件点击等),但最简单的方法是使用本地事件监视器

id eventHandler = [NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDown handler:^(NSEvent *event) {
  // check the runloop mode
  // check for cmd-.
  // abort the script if necessary

  return event;
}];

当您完成对事件的监控后,不要忘记取消注册您的监控器:

[NSEvent removeMonitor:eventHandler];
于 2013-04-21T14:41:19.970 回答
0

所以有+[NSEvent modifierFlags]which 旨在替代GetKeys(). 遗憾的是,它不包括句点键的用例。

事件队列的核心问题是您希望能够搜索它,这不是 API 公开的内容。我能想到的唯一解决方法是将所有事件出列到一个数组中,检查一个Command-.事件,然后使用postEvent:atStart:. 不漂亮。

也许作为一种优化,您可以使用+[NSEvent modifierFlags]仅在按住命令键时检查事件队列,但这听起来对我来说是竞争条件。

所以最后的建议,覆盖-postEvent:atStart:NSApplication或者NSWindow),看看你是否可以在那里找到所需的信息。我认为在最坏的情况下调试可能会很有趣。

于 2013-04-21T22:04:56.543 回答