キーボードフックでのPrintScreenに関して

[戻る]
2006/03/01(水) 21:18:46
こんにちは
キーボードフックをしたときのPrintScreenキーに関して質問です

環境:WindowsXPHome、VC++6.0、MFC、SDI

現在PrintScreenキーが押されたことを検出するためにローカルで
キーボードフックをしています
まず以下のフックプロシージャを見てください

LRESULT CALLBACK CKeyboardHook::KeyboardProc(int nCode, WPARAM wParam, LPARAM 
lParam)
{
   if(nCode < 0 || nCode == HC_NOREMOVE)
      return CallNextHookEx(m_hHook, nCode, wParam, lParam);

   // PrintScreenキーが押された
   if(wParam == VK_SNAPSHOT)   // && (lParam & 0x80000000) == 0)
   {
      AfxMessageBox("PrintScreenが押されました");
   }
   // その他のキー
   else
   {
      AfxMessageBox("その他のキーが押されました");
//    return CallNextHookEx(m_hHook, nCode, wParam, lParam);
   }

   CallNextHookEx(m_hHook, nCode, wParam, lParam);

   return TRUE;
}

これはテスト用の処理になっていますが、これを実際に動かしたところ、
ほとんどのキーが押したときと離したときの2回メッセージボックスが出るのに対し、
PrintScreenを押した時だけはなぜか離したときだけしかメッセージボックスが出ません

これはいったいなぜなのでしょうか?

ちなみに今回の目的はアクセラレータの代わりです
試してみた結果PrintScreenはアクセラレータに使用できないようなので、
他の手段を探してフックに行き着きました
どうやらPrintScreenはWindowsが標準で処理するため、それが影響しているとか・・・
このフックでの現象もそれが関係しているのでしょうか?

これに関して何か知っている人がいましたら教えていただけないでしょうか
よろしくお願いします

シロオ 2006/03/03(金) 10:05:14
ホットキーじゃ
ダメなのかしら??

2006/03/03(金) 12:38:34
シロオさん、レスありがとうございます

候補としてホットキーも挙がっていたのですが、これは調べてみたところ自アプリだけ
でなくどんな状態でもそのキーの入力を感知してしまうグローバルなものですよね

今回は自アプリ以外のPrintScreenには一切干渉する必要がありません
というよりも標準の機能(ディスプレイやウインドウのコピー)を潰してしまってはユ
ーザーが困りますよね・・・

もしホットキーでも、自前の処理をさせたくない場合はデフォルトの処理をさせる(フ
ックで言うCallNextHookEx()のような)手段があれば問題は解決するのですが、調べて
みてもそういった情報を探し出すことができませんでした

それと親記事には書きませんでしたが、このアプリはウインドウを複数持っています
キーボードフックならば自アプリ内であればどのウインドウがアクティブになっていよ
うとキーの押下を検出できます
ですがホットキーだとWindows上の全てのウインドウの内どれがアクティブかを調べて、
それが自アプリのウインドウかどうかを調べたりしないといけなくなりますよね・・・

そういった点からホットキーは不採用とし、ローカルでのキーボードフックを採用した
のですが、もし何か考え違いをしていて「ホットキーでもこうすればできるよ」など、
もし何かしら手段があるならアドバイスいただけるとありがたいです

補足として、親記事ではわかりにくかったかもしれないので一部書き加えておきます
「アクセラレータの代わり」と書きましたが、要はメニューなどに対して「Ctrl+A」な
どのキー操作を割り当てるあの(他にあるかわかりませんが)アクセラレータです
つまり単にPrintScreenを検出して特定のメニューやツールバーのボタンと同じ処理をさ
せたいだけなのです

しかしアクセラレータとしてVK_SNAPSHOTを指定してみても反応はなく、またOnKeyDown
()やOnKeyUp()でも検出することはできず、最終的にキーボードフックに行き着いたわけ
です

シロオ 2006/03/03(金) 14:10:33
私が言ってるホットキーはRegisterHotKeyのことで、
これだと登録したスレッドに対してWM_HOTKEYが送られるので
目的のことが出来ると思うんですけど。どうでしょうか?

シロオ 2006/03/03(金) 14:29:36
あ、すみません。
やっといいたいことわかった。
RegisterHotKeyダメですね。
スレ汚してすみません。

Maya 2006/03/03(金) 16:08:38
PrintScreenは1度押されると離されるまで
KeyPressを無視するってどこかで見た気がする
押された1発目はシステムがフックしてそうだし。
だから離されたときしか検出できないんじゃないかな?

Kerry 2006/03/03(金) 18:18:23
自アプリがアクティブ化されるときにホットキーを登録して、
非アクティブ化されるときに解除する、という方法はいかが?

もしくは、低レベルキーボードフック(WH_KEYBOARD_LL)を
使用するか。ただ、こちらはOS依存(NT系のみ)。

2006/03/03(金) 19:39:37
[[解決]]
みなさん、レスありがとうございます

とりあえず自アプリ限定でというのは考えず、単純にPrintScreenをホットキーとして登
録してみました
その結果ですが、PrintScreenを押した瞬間にWM_HOTKEYが飛んできました
ちなみに押し続けた場合は連続してWM_HOTKEYが飛んできました
なお、キーを離した時には特に何もありませんでした

> 自アプリがアクティブ化されるときにホットキーを登録して、
> 非アクティブ化されるときに解除する

この方法と合わせて使用すればかなり理想的なものができるかもしれません
ちょっと内部でごちゃごちゃしちゃいそうな気はしますけどね

> PrintScreenは1度押されると離されるまで
> KeyPressを無視するってどこかで見た気がする
> 押された1発目はシステムがフックしてそうだし。
> だから離されたときしか検出できないんじゃないかな?

これに関しては情報を探してみたんですが、見つけることができませんでした
実際のところどうなんでしょうね?

> 低レベルキーボードフック(WH_KEYBOARD_LL)を使用する

対象としているOSが9x系も含まれているので今回は無理そうです

結論ですが、今回はコードを簡潔にするためにフックを使おうと思います
押した瞬間でないといけないようなタイミングを必要とするわけではないですし、キー
が離されたということはその前に押されていることは明らかなわけですから、それで充
分かなという感じです
それに今回は押しっぱなしで処理させる必要性もないので

ホットキーは結局使わないことになってしまいましたが、今まで触ったことの無かった
ホットキーのことを少し知ることができました
アドバイスをしてくれたみなさん、どうもありがとうございました

古いスレッドには追加発言できません。