[BlueLeaf1336]> PROBLEMS> PasteIt>

PasteIt > ちゃんとデスクトップでのダブルクリックを検出する

historyTOP

2007/02/04:作成
2007/02/05:第1案
2007/02/08:第2案は第1案の焼き直し

不具合修正TOP

何よりもまず、激しく問題のあるソースコードでした。MouseHook を CallNextHookEx で次にまわすときに、CBTHook のハンドルを渡していました。

ちゃんとデスクトップでのダブルクリックを検出するTOP

一気にやってしまいましたが、いったん途中報告です。基本方針は最初に書いたとおり「デスクトップでのダブルクリックを検出した直後に、何かのウィンドウが作成されたらそれはデスクトップのアイコンがダブルクリックされたと考える」です。

ただ、常駐ソフトが定期的な処理の最中に何らかのウィンドウを作成する場合、たまたま(本当の)デスクトップのダブルクリックとタイミングが合えば、このプログラムではデスクトップをダブルクリックしたことにはならないわけですが、そこはそれ。別にダブルクリックを見極め損なったぐらいで乳酸がたまるわけではないのでよしとします。

今回は CBTHook で HCBT_CREATEWND かつ 作成されつつあるウィンドウが一番てっぺんのウィンドウ(エディットボックスの作成まで検出するのはあまりにも無駄)の場合に、アプリケーションに通知する処理を追加しました。

それでも明らかにおんなじプロセスの持ち物のウィンドウを何度も連続で検出してしまうので、アプリケーション側で、1秒以内に同じプロセスIDの持ち物のウィンドウの作成を検出した場合は画面表示は省略するようにしています。(もちろん全てそう作ったつもり、という程度の信用度で。)

20070204PasteIt.zip(221,488bytes) 実行ファイルとソースコード。

さて、現時点での見極めテストの画面はこんなんです。誤解のないように書いておくと、赤い矢印や青い矩形はペイントを使って描き加えています。

で、上のスクリーンショットでいえば、検出したダブルクリックのうち、青い矩形のように直後に何らかのウィンドウの作成が検出されたらそれはアイコンをダブルクリックしたものとして扱えば、残りは赤い矢印で示した「本当のダブルクリック」だけが残るよね、といえるかと(最初に書いたような問題はアレとして)。

後は、ダブルクリックで「待ち状態」に入って、しばらくウィンドウが作成されなければ「ダブルクリックされたときの処理」を行うようにすれば基本的には終わりです。

まあ、ダブルクリックばかりがゴンゴンと繰り返された場合は、最後のダブルクリックだけを対象にするぐらいのことはした方が使いやすいか、と思うぐらいのものです。

でもなぁ、どうやって「待ち状態」を実現するかを考えるのが面倒な気がします。

第1案(2007/02/05)TOP

これまでうだうだと書いてきたことを実際にやってみました。

20070205PasteIt.zip(223,158bytes) 実行ファイルとソースコード。

今回はスクリーンショットを載せる気にならないがっくり具合です。この方針が正しいと無理やり考えたとしても、ダブルクリックを検出してから何らかのウィンドウが作られるまでの時間ってどうやって決めるか、が思った以上に問題のようです。

確かに全てのデスクトップクリックを検出するよりはましになっていますが、アイコンをクリックした場合にも結構な確率で引っ掛けてしまっています。フォルダは比較的いい感じでフィルターかけられているような感じですが、例えば、デスクトップにおいてある「コマンドプロンプト」のショートカットをダブルクリックすると間違いなく「デスクトップをダブルクリックした」と判定してしまいます。

ひょっとしたら、ウィンドウの作成を検出したときにかけているフィルタリングで、コマンドプロンプトが根本的にフィルターできていないのかもしれませんが、起動に時間のかかる重たいプログラムとかになると...

どうしたもんかなぁ。shell hook ?

第2案は第1案の焼き直し(2007/02/08)TOP

第1案はもうひとつでした。なんとなく、ですが、デスクトップのアイコンをダブルクリックした後に、何らかのウィンドウが作成されるまでのタイムラグが結構、ってすぐ上でおんなじこと書いてました。

結局のところ何の解決にもならないことはわかっているんですが、前回の最後にかいた「SHELL HOOK」を試して、だめなことを確認したら、壁紙の変更に進むことにします。このままだと飽きてしまうのが、目に見えています。

さて、なぜ「SHELL HOOK」を思いついたかですが、Platform SDK にこうあります。

ShellProc Function
ms-help://MS.PSDKSVR2003R2.1033/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/shellproc.htm

HSHELL_WINDOWCREATED:A top-level, unowned window has been created. The window exists when the system calls this hook.

結局 CBTフックと何の違いもないように思いますが、自前でダイタイで「top-level, unowned window」をフィルタリングしているのを、もっといい感じにやってくれるだろうと。ただはっきりしているのは、これを採用しても、ダブルクリックからウィンドウ作成までのタイミングのズレには関係ないということです。

20070208PasteIt.zip(223,290bytes) 実行ファイルとソースコード。

実行結果。各行末のカギカッコ内は手で書き加えています。TMemoなので。

やっぱり重いプログラムはだめのようです。IEとかWordなんて2秒ほどかかってます。CBTHookのときにはExcelもだめでしたが、ShellHookのほうが優秀というわけではなく単なる偶然のように思います。もうひとつ、やっぱりコマンドプロンプトは根本的にウィンドウの作られ方が違うように見えます。IEにしろWordにしろ、少なくともダブルクリックを先に検出してますが、ウィンドウの作成自体はちゃんと検出できているのに、コマンドプロンプトではダブルクリックしか飛んできてません。

その前に、今の構造は、ダブルクリックを検出したら「処理の実行」を予約します。500ms待つ間に何らかのウィンドウが作成されたら「処理の実行」をキャンセルし、何もウィンドウが作成されなければ「処理の実行」を行っています。ここで、「ウィンドウ」とは、「他のウィンドウに所有されていないウィンドウ」をさしています。こういうフィルタをかけないとテキストボックスやコンボボックスなんかの部品が作成されるたびにメッセージが飛んできてデバッグも邪魔くさい、という程度の意味です。

また、デスクトップのダブルクリックの検出とウィンドウ作成の検出は、パラで行っていますので、デスクトップがダブルクリックされようがされまいが、ウィンドウ作成の検出自体はずーーーっと行っています。このため、同じプロセスが何個もこういうウィンドウを作る場合(本当にそんなに作るんだろうか。CBTHookのときに自前で判定していたので条件漏れなだけかも知れません)は、これまた何度もメッセージが飛んできて邪魔くさいので、直前に検出したウィンドウの持ち主のプロセスIDを覚えておいて、連続して1秒以内に同じプロセスIDの持ち物であるウィンドウが作成された場合は、これまた適当に間引いています。

あいまいな記憶だけで書きましたが、ソースを見よう>自分。

さて、予想通りでした。とりあえずデスクトップのダブルクリック検出は保留とします。残念。期待していた方にはすみません。引っ張るだけ引っ張りましたが、失敗例ということで。

EOFTOP