前回までのサンプルでステータスバーのメニューをキャプチャするとメニュー全体が含まれてしまう。
この場合は右上のステータスバーだけをキャプチャに含めたい。さてどうするか。
下図のようにステータスバーのメニューを出した状態で WindowListを調べてみた。
上2つが開いているメニューとサブメニューを表す。ステータスバーは Layer=25 ( kCGStatusWindowLevel ) で表される、ここでは4つのウィンドウが該当する。上から順番に次のようになる(名称は OwnerName)。
SystemUIServer ステータスバーのアイコン群を表す(図では Spaces から「湖」※ユーザ名までが範囲)
SimpleCap これはステータスバー左のカメラのアイコンを表す
Spotlight これは一番右の Spotlightアイコンを表す
SystemUIServer 最後のものは透明なウィンドウでキャプチャには無関係。
開いているウィンドウがステータスバーに所属するかどうかを判断する材料がないか、WindowListをじっと眺めて共通項を探してみる。
すると OwnerPIDが使えそうなのがわかった。今回の場合、メニュー2つと、ステータスバー(SystemUIServer)の OwnerPID が一致しているのがわかる。これを判断に使ってみよう。
で、結果から先に話すとうまくいった。こんな感じ。
悪くない。
サンプル:MenuCapture-06.zip
コードが長いので今回は細かい解説を割愛するが、アルゴリズムは次のようになっている。番号はソースコード上のコメントに対応している。
(1) ステータスーバーのウィンドウ情報を最初に専用の配列へ保管しておく。
(2) メニューウィンドウをすべて配列に保管する。
この時、(1)のウィンドウと OnwerPIDが同じものがあるかどうか調べておく。
(3) 次の3通りのケースについてキャプチャ範囲を調整する
[a] Context Menu
[b] ステータスバーのメニュー
[c] 通常のメニュー
(4) (3)のサイズがスクリーンをはみ出した場合、スクリーンに収まるように補正する
最後にキャプチャ画像を作成する。
アルゴリズムが泥臭いせいもあってコードはわかりづらいかもしれない。
念のため通常メニューの動作確認。問題なし。
コンテキストメニューも大丈夫。
- - - -
それにしても WindowListは役に立つ。これはこれでちゃんとしたツールに仕上げておきたいな。