none
GetKeyboardStateによる入力キー取得 RRS feed

  • 質問

  • VC++初めてのプログラムがキー入力制御で…四苦八苦してます。
    取得したいキー以外のキー入力は無視するようにしたいです。

    低レベルキーボードフック
    「hHook = SetWindowsHookEx(WH_KEYBOARD_LL, HookProc, hInst, 0);」
    というのを使うとキー入力が取得できるということがわかりました。

    しかし、キー入力を取得しようと
    LRESULT CALLBACK HookProc(int nCode, WPARAM wp, LPARAM lp)
    {
      BYTE state[256];
      if (GetKeyboardState( state ) == 0) return ::CallNextHookEx(hHook, nCode, wp, lp);
      if( state[0x53] & 0x80 )
      {
        // Sキーが押されている
        OutputDebugString(TEXT("S \n"));
      }
      ::CallNextHookEx(hHook, nCode, wp, lp);
      return TRUE;
    }
    としてもうまくいきません。

    どこがだめなのかさっぱりわからず、お手上げ状態です。

    どうか助言をお願いします。

    2011年10月11日 9:54

回答

  • 日本語のリファレンスではなく英語のほう(http://msdn.microsoft.com/en-us/library/ms644985(VS.85).aspx)を見るとわかりますが、LPARAM には、KBDLLHOOKSTRUCT 構造体へのポインタが渡されます。

    日本語のリファレンスには書いてないですね。何のポインタかわからなきゃ使えないのに...

     


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    • 回答の候補に設定 Jitta 2011年10月12日 13:22
    • 回答としてマーク 山本春海 2011年10月17日 6:51
    2011年10月12日 2:26

すべての返信

  • GetKeyboardState が見に行くキー入力状態は、キーの入力がメッセージキューにポストされたときに更新されます。

    低レベルキーボードフックはメッセージキューへのポストよりも先に発生するため、GetKeyboardState ではそのとき入力されている文字はまだ取得できません。

    GetAsyncKeyState ならできるかもしれませんが、通常、低レベルキーボードフックで入力されたキーは、lParam を参照します。lParam の中身は MSDN で LowLevelKeyboardProc の解説を参考にしてください。

    2011年10月11日 11:00
  • ちょっと気になったのですが、マルチプロセスについて理解されているのでしょうか?

    hInstの値にもよりますが、これが変数で指定されているということは他のプロセスのキー入力をフックされることを意味するはずです。ということはHookProc()はhInstのプロセス内で実行されます。その場合、hInstのプロセスに対してデバッグを行っているわけではないでしょうから、OutputDebugString()の出力を見ることはできないように思います。

    2011年10月11日 13:39
  • 低レベルキーボードフックは、対象の DLL に注入するたぐいのものではありません。システムがフックしたプロセスに配信する形です(だから .NET でもグローバルフックが可能)。
    2011年10月12日 0:02
  • そういうものなのですか、参考になりました。
    2011年10月12日 0:22
  • Hongliangさん返信ありがとうございます。

    ご指摘を参考に以下のように修正してみたのですが…
    取得できなかったです。
    LRESULT CALLBACK HookProc(int nCode, WPARAM wp, LPARAM lp)
    {
     if (nCode < 0 || nCode == HC_NOREMOVE ) return ::CallNextHookEx(hHook, nCode, wp, lp);
     SHORT sKeyState = GetAsyncKeyState('S');
     if( sKeyState & 0x8000)
     {
      OutputDebugString(TEXT("S(+) \n"));
      return ::CallNextHookEx(hHook, nCode, wp, lp);;
     }
     ::CallNextHookEx(hHook, nCode, wp, lp);
     return TRUE;
    }

    佐祐理さん返信ありがとうございます。

    デバッグは別のEXEファイル(同一ソリューションにて作成)でおこなっております。


    lparamについてはhttp://msdn.microsoft.com/ja-jp/library/cc429971.aspxを参照してみたのですが、
    理解できずに困ってます。
    デバッグ実行でブレイクポイントを設定し(HookProc内最初のif文のところ)
    lp変数をウォッチリストにいれてみたのですが、long型の1244076という値が入っているだけのようで…
    ぜんぜん見当違いなことやってたらすみません。

    2011年10月12日 2:00
  • もしかして、行うべきは、キーボードフックではなくアプリケーションが通常受け取るキー処理をどうするかではありませんか?

    GUI(WinMainで始まるプログラム) プログラムであれば、キー処理はフォーカスを持つウィンドウ(アクティブなフレームウィンドウでフォーカス入力を拒否しない子ウィンドウのいずれか)がキー入力を受け取ります。

    CUIであれば、キー入力処理は、コンソール入出力APIがOSからのキー処理を受け入れ、それを標準入出力などのC RuntimeやC++ Runtime で受け取れるようにしています。

    なんとなく思っただけで、本当にキーボードフックをして、特定キー入力のみに制限するのが目的なのかもしれませんが...

     


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    2011年10月12日 2:11
  • 日本語のリファレンスではなく英語のほう(http://msdn.microsoft.com/en-us/library/ms644985(VS.85).aspx)を見るとわかりますが、LPARAM には、KBDLLHOOKSTRUCT 構造体へのポインタが渡されます。

    日本語のリファレンスには書いてないですね。何のポインタかわからなきゃ使えないのに...

     


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    • 回答の候補に設定 Jitta 2011年10月12日 13:22
    • 回答としてマーク 山本春海 2011年10月17日 6:51
    2011年10月12日 2:26
  • とっちゃんさん 返信ありがとうございます。

    英語のサイト参考になりました(英語読めませんが…^^;)
    以下のように修正したところ取得することができました。
    助言いただいた皆様のおかげです。ありがとうございます。

    LRESULT CALLBACK HookProc(int nCode, WPARAM wp, LPARAM lp)
    {
     if (nCode < 0 || nCode == HC_NOREMOVE ) return ::CallNextHookEx(hHook, nCode, wp, lp);
     KBDLLHOOKSTRUCT*pK = (KBDLLHOOKSTRUCT*)lp;
     // Sキーが押されている
     if (pK->vkCode == 83 ){
      if (pK->flags == 0 )
      {
       OutputDebugString(TEXT("S(p+) \n"));
       sKeyFlg = true;
       return true;
      }else{
       OutputDebugString(TEXT("S(p-) \n"));
       sKeyFlg = false;
      }
     }
     return true;
    }

    これから実際のアプリを作らないといけないんですけどね~^^;

     

    2011年10月12日 6:40