基本的に、システムのメニュー バーで提供される効果を作成したいと考えています。ユーザーがメニューの見出しの 1 つを押して、さまざまな見出しを移動すると、メニューが自動的に開きます。
問題は、ボタンのポップアップ メニューを開くと、ユーザーがもう一度クリックして閉じる必要があることです。ポップアップメニューがモーダルだと思うので、ランループ全体が保留中です。ユーザーが次のボタンに移動したときに [somePopUpMenu cancelTracking] を送信できるようにするにはどうすればよいですか?
NSWindow サブクラスで現在試しているコードは次のとおりです。ポイントは、マウスがボタンから出ると、次のボタンでマウスが自動的にクリック (左下/左上) され、タイマーが無効になり、ポップアップ メニューがキャンセルされることです。
ポップアップ メニューが開いていて、マウスが存在すると仮定すると、leftdown/leftup イベントが発生し (これは、mouseDown と mouseUp の NSLog にログを記録するので、これが機能することがわかっています)、タイマーは無効になりますが、ポップアップ メニューは引き続き表示されます。偽のイベントによって「クリック」された他のボタンには何も表示されません。また、全体がループに陥り、何らかの理由で取り乱した mouseDown/mouseUp が送信されます。
hookToMenu には適切な参照がありますが、ポップアップ メニューが別のオブジェクトで作成されていることに注意してください (デバッグ/ステップ スルーで確認しました)。
イベント追跡タイマーを中断しているのか、間違った方法で実行しているのかはわかりません。ウィンドウコントローラーでも試してみましたが、同じ結果が得られました。
これに関する助けをいただければ幸いです。
-(void)stopTimer
{
[timer invalidate];
[hookToMenu cancelTracking]; //hookToMenu is NSMenu*
}
-startFireDateTimer
{
NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:0];
timer = [[NSTimer alloc] initWithFireDate:nil interval:0 target:self selector:@selector(targetMethod) userInfo:nil repeats:YES];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer forMode:NSEventTrackingRunLoopMode];
[timer release];
}
-(void)targetMethod
{
NSEvent *newEvent;
newEvent=[NSApp nextEventMatchingMask:NSMouseExitedMask untilDate:[NSDate distantFuture] inMode:NSEventTrackingRunLoopMode dequeue:NO];
if ([newEvent type]==NSMouseExited)
{
NSPoint mouseLoc;
mouseLoc=[newEvent locationInWindow];
int type=NSLeftMouseDown;
int type2=NSLeftMouseUp;
int windowNumber=[self windowNumber];
id fakeMouseUpEvent=[NSEvent mouseEventWithType:type
location:mouseLoc
modifierFlags:nil
timestamp:[NSDate timeIntervalSinceReferenceDate]
windowNumber:windowNumber
context:nil
eventNumber:nil
clickCount:1
pressure:1];
id fakeMouseUpEvent2=[NSEvent mouseEventWithType:type2
location:mouseLoc
modifierFlags:nil
timestamp:[NSDate timeIntervalSinceReferenceDate]
windowNumber:windowNumber
context:nil
eventNumber:nil
clickCount:1
pressure:1];
[NSApp sendEvent:fakeMouseUpEvent];
[NSApp sendEvent:fakeMouseUpEvent2];
[self stopTimer];
}
}
-(void)mouseDown:(NSEvent *)theEvent
{
[self startFireDateTimer];
NSLog(@"WINDOW: mouse down in window!");
[super mouseDown:theEvent];
}
-(void)mouseUp:(NSEvent *)theEvent
{
NSLog(@"WINDOW: mouse up in window!");
[super mouseUp:theEvent];
}