我正在实现一种脚本语言,用户可能会意外地造成无限循环。我想让用户有机会在键入句点(“。”)键时按住命令键取消这种失控循环。
目前,每行一次,我会使用以下代码检查取消:
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-。如果我没有将事件排队,那么它背后。
有没有比去旧的碳备用GetKeys()更好的选择?幸运的是,这似乎可以在64位中使用。
另外,我正在考虑添加一个NSStatusItem,它添加一个按钮来取消脚本到菜单栏左右。但是我如何处理事件的方式不会让用户例如当脚本期望成为主线程的标尺时选择一个菜单?
有什么建议吗?建议?
答案 0 :(得分:2)
使用-addLocalMonitorForEventsMatchingMask:
作为Dave建议可能是解决此问题的最简单方法,是的。
我只是想补充一点,尽管你感觉不可靠,但事件队列实际上是一个队列,事件不会改变顺序。调用-nextEventMatchingMask:inMode:dequeue:NO
,检查事件,确定它是您要处理的事件,然后调用-nextEventMatchingMask:inMode:dequeue:YES
以便使用它是完全安全的(以及事件循环中的标准做法)。只需确保两次调用之间的掩码和模式相同。
答案 1 :(得分:1)
我建议使用事件监视器。由于您要求NSApp
查看事件,因此您似乎在当前流程中运行脚本,因此您只需要监控自己流程中的事件(而不是全局)。
有几种方法可以做到这一点(继承NSApplication
并覆盖-sendEvent:
,放入事件点击等),但最简单的方法是使用local event monitor :
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];
答案 2 :(得分:0)
因此,+[NSEvent modifierFlags]
旨在替代GetKeys()
。遗憾的是,它并没有涵盖你对句号键的使用情况。
事件队列的核心问题是您希望能够搜索它,这不是API公开的内容。我能想到的唯一解决方法是将所有事件出列到一个数组中,检查Command-.
事件,然后使用postEvent:atStart:
对它们进行重新排队。不漂亮。
也许作为优化,您可以使用+[NSEvent modifierFlags]
仅在按住命令键时检查事件队列,但这听起来对我来说是竞争条件。
最后的建议,覆盖-postEvent:atStart:
(在NSApplication
或NSWindow
上)并查看是否可以在那里删除所需的信息。我认为在最坏的情况下调试可能会很有趣。