2

ユーザーが誤って無限ループを引き起こしている可能性のあるスクリプト言語を実装しています。コマンド キーを押しながらピリオド (".") キーを入力することで、このような暴走ループをキャンセルする機会をユーザーに与えたいと考えています。

現在、行ごとに 1 回、次のコードでキャンセルを確認しています。

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 がデキューされる可能性があり、アプリケーションはキーが離されたことを認識できない可能性があります。

また、実際にキャンセル イベントであることがわかるまでイベントをデキューしたくありませんが、個別のデキュー呼び出しはなく、2 回目の呼び出しで最前面のイベントが同じものになると想定するだけでは信頼できません。また、それが最初であることが保証されている場合でも、それはユーザーが「a」を入力してから Cmd- を入力したことを意味します。つまり、「a」のみが表示され、Cmd- は表示されません。イベントをデキューしない場合はその背後にあります。

古い Carbon スタンバイ GetKeys() に行くよりも良いオプションはありますか? 幸いなことに、それは 64 ビットで利用できるようです。

また、スクリプトをキャンセルするボタンをメニューバーなどに追加する NSStatusItem を追加することも考えています。しかし、ユーザーがメニューを選択できないようにイベントを処理するにはどうすればよいでしょうか。

助言がありますか?おすすめは?

4

3 に答える 3

2

デイブが提案するように使用-addLocalMonitorForEventsMatchingMask:することは、おそらくこれを行う最も簡単な方法です。

信頼できないと感じているにもかかわらず、イベント キューは実際にはキューであり、イベントの順序は変更されないことを付け加えたいと思います。-nextEventMatchingMask:inMode:dequeue:NOを呼び出してイベントを調べ、それが処理したいものであると判断し、それ-nextEventMatchingMask:inMode:dequeue:YESを消費するために呼び出すことは完全に安全です (そしてイベント ループでの標準的な方法) 。マスクとモードが 2 つの呼び出し間で同一であることを確認してください。

于 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]ため、の代替として意図されているものがありGetKeys()ます。残念ながら、ピリオドキーのユースケースはカバーしていません。

ここでのイベント キューの主な問題は、検索できるようにすることですが、これは API が公開するものではありません。私が考えることができる唯一の回避策は、すべてのイベントを配列にデキューし、イベントをチェックしてからCommand-.postEvent:atStart:. かわいくない。

+[NSEvent modifierFlags]おそらく最適化として、コマンド キーが押されているときにのみイベント キューをチェックするために使用できますが、それは競合状態につながるように思えます。

したがって、最後の提案として、-postEvent:atStart:( または のいずれNSApplicationかでNSWindow) オーバーライドして、そこから目的の情報を取得できるかどうかを確認してください。最悪の場合、デバッグには興味深いものになると思います。

于 2013-04-21T22:04:56.543 に答える