2011-09-14 10 views
26

アクセシビリティAPIを使用してウィンドウのサイズを変更するan applicationにパッチを適用しようとしています。OS X上でアクティブなウィンドウを一意に特定

以前のサイズのウィンドウで辞書を維持する必要があります。キーは、現在アクティブなウィンドウを識別する必要があります。現時点では、このアクティブなウィンドウは、ホットキーを押すとNSAccessibilityFocusedWindowAttributeを介して取得されます。

ただし、このメソッドが呼び出されるたびに、ウィンドウを識別する返されたAXUIElementRefは異なる!これはもちろん、私は辞書のキーとしてそれを使用することはできません - 辞書は、対応するエントリを見つけることはできませんことを意味します。

次のコードは、問題を再現します。

-(IBAction)testWindowIdentification:(id)sender{ 
    AXUIElementRef focusedApp; 
    AXUIElementRef focusedWindow; 

    AXUIElementCopyAttributeValue(_systemWideElement, 
            (CFStringRef) kAXFocusedApplicationAttribute, 
            (CFTypeRef*) &focusedApp); 
    AXUIElementCopyAttributeValue((AXUIElementRef) focusedApp, 
            (CFStringRef) NSAccessibilityFocusedWindowAttribute, 
            (CFTypeRef*) &focusedWindow); 
    CFShow(focusedWindow); 
} 

_systemWideElementAXUIElementCreateSystemWide()への呼び出しを使用してinit方法で初期化されています。

CFShow文が明確に方法が私のために無用である、(同じウィンドウがアクティブであっても)と呼ばれるたびに異なるIDを示しています

<AXUIElement 0x47e850> {pid=42463} 
<AXUIElement 0x47e890> {pid=42463} 
<AXUIElement 0x47e2c0> {pid=42463} 
… 

documentation on AXUIElementはユニークな属性を取得するいかなる方法を示していないがUI要素の場合はthat of the NSAccessibility protocolのいずれも表示されません。 一意のPIDはではなく、私にとってはではありません。プロセスは複数のウィンドウを持つことができるためです。

Cocoaでアクティブなウィンドウの一意の識別子を取得する方法を教えてください。

(ちなみに、実際のコードは、上記の呼び出しでリターンコードをチェックして、エラーが存在しない、呼び出しが成功します。)

+1

@JeremyBanks元の回答者は正しいアイデアをここに持っています。 [this answer](http://stackoverflow.com/a/312099/517815)を信じるならば、フォーカスされたウィンドウを決めると、実際にはQuartzを使って 'CGWindowID 'を得ることができます。これはあなたが望んでいるユニークなウィンドウ識別子を与えなければなりません。あなたは、現在のアプリケーションの文脈で無事に渡すことができます。実際の答えとしてこれをより一貫して完全なものにしたいのであれば教えてください。 – MrGomez

+0

@MrGomez確かに、そのような答えは素晴らしいでしょう。 :) –

+0

@JeremyBanksになります。私は今日は少しオーバーロードされていますが、私は今晩遅く(PST)これに答えるつもりです。 :) – MrGomez

答えて

16

Rob Kenigerはhis answer hereで正しい戦略を持っています。この回答に欠けているのは唯一のことです(そして実際にはバウンティプレースメントの理由)は、現在のアクティブなウィンドウを取り出し、現在の作業アプリケーションのコンテキストでインデックスに適した一意のキーに変換する実行可能な実装です。

Robのソリューションは、Quartz Window Servicesの文脈で与えられたCGWindowIDを使用してこれを説明しています。もちろん、このウィンドウ参照がonly useful for your current applicationであることを強く暗示しています。

アクセシビリティAPIとQuartz Window Servicesの間に強い保証が存在しないため、このウィンドウの参照は難解です。 documented hereとして

  1. 使用extern "C" AXError _AXUIElementGetWindow(AXUIElementRef, CGWindowID* out);、ただし、次の方法でこれを回避することができます。これはが保証されているわけではありませんが、ご使用のOSXのバージョンで動作する場合は、テストを開始するための基礎テストとして機能します。

  2. HIWindowGetCGWindowID()を使用してCGWindowIDを直接入手してください。アクティブなウィンドウの選択とIDの抽出の詳細については、the reference manual for the Carbon Window Manager(警告:大きなPDF)を参照してください。

  3. カタログ番号CGWindowIDは、CGWindowListCreateDescriptionFromArrayのように、ロブが提案したとおりに設定します。ここでの目標は、Accessibility APIとQuartzをブリッジするためのスキームを見つけることですが、これは、たとえば、現在のアクティブウィンドウのコンテキストにバインドされたコールバックを利用することで考えられます。私は正直なところ、このの最適な例は、将来の保証が適切に行われているとは知らないです。オプションの

あなたが一意に識別するために、あなたの窓のためのいくつかの他のデコレータを作成することができないなら、私は、あなたの現在のニーズに2.一緒に行くお勧めします。現在のところ、従来のコードベースで定義されていますが、それはあなたが望むことをするでしょう。

あなたのアプリケーションに最適です。

+0

ウィンドウが選択されていないか、すべてのウィンドウが非アクティブである(コントロールがデスクトップにある)ことを検出するにはどうすればよいですか? –

+0

すみません、 "extern"の使い方C "AXError _AXUIElementGetWindow(AXUIElementRef、CGWindowID * out);"スウィフトで? – allenlinli

8

私はあなたが石英ウインドウサービス機能を使用することができるかもしれないと思います具体的には、CGWindowListCreateDescriptionFromArrayを使用して、特定のアプリの現在アクティブなウィンドウを列挙します。

この呼び出しはAppKitよりも低レベルであり、アクティブなウィンドウは何もわかりませんが、現在のユーザーセッションで一意のウィンドウIDが与えられます。それは素晴らしい解決策ではありませんが、ウィンドウ境界情報をアクセシビリティAPIから受け取ったものと比較して、ウィンドウを実際のIDに関連付けることができます。

関連する問題