AppleScriptであらゆるウィンドウを操作できなかった原因が分かった!

以前の日記 MacBookのあらゆるウィンドウをキー操作で自在に操るために(AppleScript + Quicksilver で作成していたAppleScriptには、解決できない二つの問題が残っていた。

  • フローティングウィンドウがあると、編集中のメインウィンドウよりも優先して操作対象になってしまい、肝心のメインウィンドウが操作できない。
  • Aptana StudioとNeo Officeで操作できないことが判明...。何故だろう?GUIスクリプティングを利用しているのに...。

GUIスクリプティングを使えば、あらゆるウィンドウを自在に操作できるはずなのだが、一部のウィンドウが思い通りに動いてくれなかったのだ...。

修正前のコード

  • その時の主要な部分のコードは、およそ以下のように書いていた。
tell application "System Events"
  set pList to name of every process whose frontmost is true
  set appName to item 1 of pList
  tell process appName
    set front window's size to {800, 500}
    set front window's position to {100, 100}
  end tell
end tell

ウィンドウのプロパティ

  • ウィンドウにはプロパティ(属性)があり、上記コードではsizeやpositionといったプロパティを設定することでウィンドウを操作している。
  • 操作するウィンドウがその時どのようなプロパティを持っているのか、以下のコードで確認してみた。
tell application "System Events"
  set pList to name of every process whose frontmost is true
  set appName to item 1 of pList
  tell process appName
    properties of every window
  end tell
end tell
  • これで、その時アクティブなアプリケーションのすべてのウィンドウプロパティを結果として確認することができる。(下段)


フローティングウィンドウが動いてしまう理由
  • テキストエディットを起動して、フォントパネルを開いた状態で実行してみた。(名称未設定ウィンドウと、フォントパネルが開いた状態)
  • テキストエディットをアクティブにして、commandキーを押しながらスクリプトエディタの実行ボタンを押すと、テキストエディットがアクティブなままスクリプトを実行できる。
{
{size:{445, 290}, focused:false, description:"フローティングウインドウ", subrole:"AXFloatingWindow", minimum value:missing value, enabled:missing value, role:"AXWindow", name:"フォント", value:missing value, selected:missing value, class:window, title:"フォント", help:missing value, position:{736, 44}, orientation:missing value, entire contents:{}, maximum value:missing value}, 

{size:{550, 442}, focused:false, description:"標準ウインドウ", subrole:"AXStandardWindow", minimum value:missing value, enabled:missing value, role:"AXWindow", name:"名称未設定", value:missing value, selected:missing value, class:window, title:"名称未設定", help:missing value, position:{286, 162}, orientation:missing value, entire contents:{}, maximum value:missing value}
}
  • 見易いように途中で改行を入れてみた。ウィンドウごとのプロパティのリストが二つ取得できた。
    • そこにはフォントパネル、名称未設定ウィンドウの順に表示されていた。
    • front windowを指定すると、このwindowリストの最初の部分が参照されるはず。
    • つまり、フローティングウィンドウであるフォントパネルが参照されるのだ。
    • どうもwindowリストの順は、デスクトップ上のウィンドウの重なり順が再現されているようだ。
NeoOfficeでウィンドウを動かせない理由
  • 次に、NeoOfficeを起動して、同じようにウィンドウのプロパティを確認してみた。(フォントパネルは開かず、Writerの無題1ウィンドウのみ開いた状態)
{
{size:{15, 15}, focused:false, description:"AXWindow:AXUnknown", subrole:"AXUnknown", minimum value:missing value, enabled:missing value, role:"AXWindow", name:missing value, value:missing value, selected:missing value, class:window, title:"", help:missing value, position:{100, 100}, orientation:missing value, entire contents:{}, maximum value:missing value}, 

{size:{1003, 751}, focused:false, description:"標準ウインドウ", subrole:"AXStandardWindow", minimum value:missing value, enabled:missing value, role:"AXWindow", name:"無題1 - NeoOffice Writer", value:missing value, selected:missing value, class:window, title:"無題1 - NeoOffice Writer", help:missing value, position:{247, 22}, orientation:missing value, entire contents:{}, maximum value:missing value}
}
  • あれれ、ウィンドウを1つだけしか開いてないはずなのに、サイズが15×15のウィンドウがリストの最初に表示されている。
    • 操作したいウィンドウは、リストの2番目になってしまっている...。
    • front windowを指定すると、この未知の15×15のウィンドウが参照されてしまっていたのだ。
    • ちなみに、この未知のウィンドウは何かと思ったら、どうもツールチップ(マウスを重ねると表示される説明)のようだ。
    • ツールチップが表示されている時に操作すると、それが動いてしまった。

修正後のコード

  • 動かない理由は理解できた。つまり、操作したいウィンドウが一番上のウィンドウになっていなかったのだ。
  • だから、windowリストの中から操作したいウィンドウを確実に参照することができれば、自在に操作できるようになるはず。
  • いろいろなウィンドウのプロパティを確認してみると、subrole:"AXStandardWindow"が一般的な書類ウィンドウのようだ。
  • そこで、ウィンドウの種類をsubrole:"AXStandardWindow"に限定して、その中で一番上のウィンドウを取得するようにしてみた。
tell application "System Events"
  set pList to name of every process whose frontmost is true
  set appName to item 1 of pList
  tell process appName
    set topWindow to item 1 of (every window whose subrole is "AXStandardWindow") --1番上の書類ウィンドウ
    set topWindow's size to {800, 500}
    set topWindow's position to {100, 100}
  end tell
end tell
  • しかし、これだとフローティングウィンドウは全く操作できないことになってしまう ...。それもちょっと不便。
  • さらに、この修正で、こよなく愛するスティッキーズも操作できなくなってしまったようだ...。(スティッキーズは何と!subrole:"AXUnknown" なのであった。)
  • そこで、subrole:"AXStandardWindow"が一つも存在しない時は、普通にfront windowを返すようにしてみた。
tell application "System Events"
  set pList to name of every process whose frontmost is true
  set appName to item 1 of pList
  tell process appName
    try
      set topWindow to item 1 of (every window whose subrole is "AXStandardWindow") --1番上の書類ウィンドウ
      topWindow --1番上の書類ウィンドウが存在しない場合、エラーになる。
    on error
      set topWindow to front window
    end try
    set topWindow's size to {800, 500}
    set topWindow's position to {100, 100}
  end tell
end tell
  • これで、一般的な書類ウィンドウが表示されていなければ、フローティングウィンドウも含めて一番上のウィンドウを操作できるようになった。
  • スティッキーズのウィンドウもちゃんと動かせる。

スティッキーズのウィンドウをサイズ変更できない謎

  • あらゆるウィンドウを自在にキー操作できるようになった!と思ったのも束の間、問題はまだ残っていた...。
  • スティッキーズのウィンドウをサイズ変更できないことに気付いた。(ウィンドウの移動はできる。)
プロパティ
  • ウィンドウのプロパティを確認すると、以下のようになっていた。
    • 意外なことに、subrole:"AXUnknown" になっていた。("AXStandardWindow"ではない。何故?)
    • その他のプロパティで気になる点は見当たらない。何故サイズ変更できないのだろう?
{
{size:{543, 371}, focused:false, description:"AXWindow:AXUnknown", subrole:"AXUnknown", minimum value:missing value, enabled:missing value, role:"AXWindow", name:"名称未設定", value:missing value, selected:missing value, class:window, title:"名称未設定", help:missing value, position:{100, 100}, orientation:missing value, entire contents:{}, maximum value:missing value}
}
UIElementInspector.app

  • command-F7でウィンドウの状態をロック、コピーして並べてみた。(スティッキーズとテキストエディット)
    • リンゴマークを削除して多少見易くなった。
    • Attributes項目の先頭のAX...を取り除けば、これはつまりウィンドウのプロパティと同じだ。
<AXApplication: スティッキーズ>                      <AXApplication: テキストエディット>            
 <AXWindow: 名称未設定>                              <AXWindow: 名称未設定>                      
Attributes:                                         Attributes:                              
   AXRole:  AXWindow                                 AXRole:  AXWindow                       
   AXRoleDescription:  AXWindow:AXUnknown            AXRoleDescription:  標準ウインドウ         
   AXSubrole:  AXUnknown                             AXSubrole:  AXStandardWindow            
   AXTitle:  名称未設定                                AXTitle:  名称未設定                      
   AXFocused:  0                                     AXFocused:  0                           
   AXParent:  <AXApplication: スティッキーズ>         AXParent:  <AXApplication: テキストエディット>
   AXChildren:  <array of size 5>                    AXChildren:  <array of size 6>          
   AXPosition (W):  x=630 y=149                      AXPosition (W):  x=451 y=99             
   AXSize:  w=543 h=371                              AXSize (W):  w=550 h=442                
   AXMain (W):  1                                    AXMain (W):  1                          
   AXMinimized:  0                                   AXMinimized (W):  0                     
   AXCloseButton:  (null)                            AXCloseButton:  <AXButton>              
   AXZoomButton:  (null)                             AXZoomButton:  <AXButton>               
   AXMinimizeButton:  (null)                         AXMinimizeButton:  <AXButton>           
   AXToolbarButton:  (null)                          AXToolbarButton:  (null)                
   AXProxy:  (null)                                  AXProxy:  (null)                        
   AXTitleUIElement:  (null)                         AXTitleUIElement:  <AXStaticText>       
   AXGrowArea:  (null)                               AXGrowArea:  <AXGrowArea>               
   AXDefaultButton:  (null)                          AXDefaultButton:  (null)                
   AXCancelButton:  (null)                           AXCancelButton:  (null)                 
   AXDocument:  (null)                               AXDocument:  (null)                     
   AXModal:  0                                       AXModal:  0                             
Actions:                                            Actions:                                 
   AXRaise - 上げる                                     AXRaise - 上げる                        
  • 気になるところが、スティッキーズのAXSize: w=543 h=371と、テキストエディットのAXSize (W): w=550 h=442の違い。
  • command-F7でロックした後に表示されるLocked on で確認すると...
    • スティッキーズは、書き込みNG

    • テキストエディットは、書き込みOK(プロパティ名の後ろに(W)が付く項目は書き込み可能になるようだ。)


  • スティッキーズのウィンドウサイズは、変更できない仕様になっていたのだ!


しかし、実際にはスティッキーズのウィンドウ右下をマウスでドラッグすればサイズ変更できるのだが...。だから、キー操作でもサイズ変更できるようにしたいのだが、その方法は未だ謎だ。