UIAssistant の機能考え中(迷走中)
新機能として、コンテキストメニュー的なものを作成中
下の画像はコンテキストメニューの例で、「無題 - メモ帳」を選択して、コンテキストメニューを表示させて、「文字列をコピー」した結果を貼り付けるまでの動画です。
とりあえずお試しで実装して動かしてみたけれど、微妙な点がいくつか浮上。
微妙な点
大改造必至
UIAssistant 本体側にコンテキストメニューを使用する土台をインフラ的に用意しておいて、 プラグイン側で、それを利用して楽にコンテキスメニューを実現できる状態にしたい、のだけれど、 今の UIAssistant の実装だと実現が面倒なので、大改造必至。
この機能、本当に使うか?
あると便利だろうけど、そんなしょっちゅう使う機能か?を考えると使用頻度は低いと思う。(個人の感想です)
今後
現状での実装の大変さと、結果の便利さが釣り合わないので、正式に実装するのに二の足を踏んでいます。 動かしてみた感じだと面白そうではあるのですが……とりあえず放置する方向。
UIAssistant 0.3.7.3 公開
コンテキストメニュー内の検索機能を追加しました。 すこし問題はあるのですが、対処のしようがない(下記、既知の問題点参照)ので、公開します。 だいたいの場合は問題にならない……はずです。
ダウンロード
以下からどうぞ。
更新内容
- SearchByText プラグイン
- コンテキストメニュー内を検索する機能を追加
- Hit-a-Hint プラグイン
- 「ヒントの再作成」使用時、UIAssistant がフリーズする場合があったのを修正
コンテキストメニューの検索
機能概要
ホットキー押下でコンテキストメニューを自動で開いて検索できます。
使用方法
ホットキーの設定で、以下のコマンドを指定してください。
/ ContextMenu
注意事項
- アプリケーションキーに別のキー(あるいは機能)を割り当てている場合、検索できません
UIAssistant 内で仮想的にアプリケーションキーを押下させてコンテキストメニューを開いているので、 AutoHotkey などでアプリケーションキーに別のキーを割り当てていると、コンテキストメニューが開かれず検索できません。
既知の問題点
- 検索後、実行できないメニュー項目がある
下図のようにコンテキストメニューの中身が多い場合、初期状態で見えていないメニュー項目(スクロールが必要な項目)は実行できません。
メニューをスクロールできる機能が UI Automation に無く、 UIAssistant から矢印の上下キーを送信して無理矢理にスクロールさせて、見えていなかったメニュー項目を表示させても実行できなかったので、 どうすれば実行できるようになるのか対処方法が不明です。 スクロールが必要になるくらいメニュー項目が多くなる場合は、たいてい階層化(ネスト化)してスクロールの必要がなくなるように対処するはずなので、あまり問題にはならない……といいなぁ。
(UIAssistant から矢印キー、Enter キーを送信して実行させるという手段しか無いのかなぁ。)
コンテキストメニューが開いたのを検知する方法
右クリックで出てくるアレの出現を検知したかったのです。 UIAssistant でコンテキストメニューの要素を扱えたら便利じゃないかと思って調べてみた結果がこれです。
対象
- Windows XP 以降
TL;DR
対象が非WPFアプリケーションの場合、以下のどちらかで検知できます。
- Win32API
SetWinEventHook
関数(EVENT_SYSTEM_MENUPOPUPSTART
を利用) - UI Automation
AddAutomationEventHandler
メソッド(UIA_MenuOpenedEventId
を利用)
対象がWPFアプリケーションの場合、以下でのみ検知できます。
- UI Automation
AddAutomationEventHandler
メソッド(UIA_MenuOpenedEventId
を利用)
なので、どの場合でも検知できるようにするには、UI Automation の AddAutomationEventHandler
メソッドを使うとよいです。
動機
「コンテキストメニューの UI を差し替えるなり、拡張できたら便利ではないだろうかと思った」などと供述している模様。
すなわち、
- コンテキストメニューが開かれるのを検知する
- 検知したら、コンテキストメニュー内の要素を取得する
- その要素の中から、入力した文字列によって検索、選択できるような UI を付加する
こんなことができれば便利かもしれないと考えました。UI を付加するのであれば、従来通りにも使えて、既存の使い勝手をなるべく阻害しない形になります。
SetWinEventHook
下記のサイト経由で、コンテキストメニューが開いたのを検知できると知り、試してみることに。
SetWinEventHook
の引数に EVENT_SYSTEM_MENUPOPUPSTART
を指定すると、コンテキストメニューが開かれたときに引数で指定した関数がコールバックされます。その際、コンテキストメニューのウィンドウハンドルを受けとれます。
というわけで ContextMenuObserverWin32
を作成してみました。(ソースコード@Gist)
以下のようなコマンドで、ビルドできます。(csc.exe にパスが通っているかの確認と、.NETFramework のバージョンについては環境ごとに変更する必要があります)
csc /t:winexe /lib:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1" /r:UIAutomationClient.dll /r:UIAutomationTypes.dll ContextMenuObserverWin32.cs
非WPF(Win32, Windows Forms)の場合
検知して、メニュー項目を取得できました。
WPF の場合
こちらは、検知できませんでした。
WPF とそれ以外では、コンテキストメニューの作られ方が異なり、そのため検知不可になっているのだと思われます。(下図参照)
Win32 アプリケーションのコンテキストメニュー
WPF アプリケーションのコンテキストメニュー
WPF も検知できる方法を探す → UI Automation を試す
以下のように、WPF だろうとなんだろうと利用できると公式に記載されていました。よさげです。
The UI Automation requirements apply to all menu controls, whether Microsoft Windows Presentation Foundation (WPF), Microsoft Win32, or Windows Forms.
...
Required UI Automation Events
Menu controls must raise the UIA_MenuOpenedEventId event when they appear on the screen.
UI Automation Support for the Menu Control Type
試してみた結果
ContextMenuObserverUIA
を作成してみました。(ソースコード@Gist)
SetWinEventHook
のときと同様に、以下のようなコマンドで、ビルドできます。
csc /t:winexe /lib:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1" /r:UIAutomationClient.dll /r:UIAutomationTypes.dll ContextMenuObserverUIA.cs
WPF でも問題なく検知できて、以下のようにコンテキストメニューの内容を取得できました。
Win32 アプリケーション
WPF アプリケーション
さいごに(所感)
たぶん、この投稿の需要はほとんどないと思います。PC をがっつり使う人って、もうそんなにいないだろうし。 アプリケーションによっては、コンテキストメニュー内に項目が多くあるので、検索できれば使い勝手向上に役立ちそうとは思うのです。まぁ、実際に試してみないと便利かどうかは評価できないわけですが……。
UIAssistant 0.3.6.2 公開(Bugfix)
月刊 UIAssistant、今回もバグ修正のみです。
(別に月刊を狙っているわけでも無いのですが……)
ダウンロード
以下からどうぞ。
主な修正点
以下の3点。
- 「キーバインド、使用方法の表示/非表示」がキーを押下しても表示されなかったのを修正(LCtrl+U のやつ)
ウィンドウの大きさをより正確に取得するように修正
- before
- after
- before
ポップアップが表示された場合も最前面に UIAssistant が表示されるように修正
- before
- after
- before
今後について
コンテキストメニュー(右クリックメニュー)内を文字で検索できたら楽しそう(実現できるかどうかは別として……)