3

私は奇妙な問題に遭遇しています。別のプログラム (課金システム エミュレーター) を開き、それを子ウィンドウとして設定してから無効にする WinForms アプリケーションがあります。これは正常に機能し、ユーザーはその子ウィンドウにキーを送信できず、winforms アプリケーションは子ウィンドウにコマンドを送信して処理を行います。

ただし、shiftまたはを押すとcontrol、winforms アプリケーションにフォーカスがない場合でも、有効なキーではないため、課金システム エミュレーターでエラーが発生することがわかっています。ユーザーは、winforms アプリの実行中にshiftまたはcontrolキーを使用しないようにしていますが、それは明らかに実用的な解決策ではありません。

私の試みた解決策は次のとおりです。

  1. これらのキーが押されたときにキャプチャするグローバル キーボード フック。
  2. OnKeyDownこれらのキーを停止するには、winforms アプリケーションでオーバーライドします。

ただし、winforms アプリがフォーカスされていないときに子ウィンドウに送信されるshiftおよびキーの問題は解決しません。winformsアプリの実行中にグローバルにalt停止できますが、それは有効ではないと思います。したがって、グローバルフックで、winformsアプリとその子を停止する必要がありますが、グローバルに許可する必要があります。アイデア/考えはありますか?shiftaltkeypress

これは私のコードです。

4

2 に答える 2

2

あなたのシナリオに適切な答えがあるとは思いません... =\

これがあなたが試すことができるハックです。コントロール/シフトがダウンしている場合は「解放」し、その後メッセージを送信します。

    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)]
    public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int extraInfo);

    [DllImport("user32.dll")]
    static extern short MapVirtualKey(int wCode, int wMapType);

    private void button1_Click(object sender, EventArgs e)
    {
        if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift)
        {
            keybd_event((int)Keys.ShiftKey, (byte)MapVirtualKey((int)Keys.ShiftKey, 0), 2, 0); // Shift Up
        }
        if ((Control.ModifierKeys & Keys.Control) == Keys.Control) 
        {
            keybd_event((int)Keys.ControlKey, (byte)MapVirtualKey((int)Keys.ControlKey, 0), 2, 0); // Control Up
        }

        // ... now try sending your message ...
    }

これは明らかに絶対確実ではありません。

于 2013-10-28T16:11:00.307 に答える
0

の唯一のコンストラクターを調べたところ、globalKeyboardHookグローバルフック専用に設計されているようです。次のようにのみ、現在実行中のモジュールにフックする別のオーバーロードを追加できます。

class globalKeyboardHook {  
  [DllImport("kernel32")]
  private static extern int GetCurrentThreadId();
  [DllImport("user32")]
  private static extern IntPtr SetWindowsHookEx(int hookType, KeyBoardProc proc, IntPtr moduleHandle, int threadId);
  [DllImport("user32")]
  private static extern int CallNextHookEx(IntPtr hHook, int nCode, IntPtr wParam, IntPtr lParam);

  public globalKeyboardHook(bool currentModuleOnly){
     if(currentModuleOnly){
       proc = KeyBoardCallback;
       //WH_KEYBOARD = 0x2
       hhook = SetWindowsHookEx(2, proc, IntPtr.Zero, GetCurrentThreadId());       
     } else hook();
  }
  public delegate int KeyBoardProc(int nCode, IntPtr wParam, IntPtr lParam);
  public int KeyBoardCallback(int nCode, IntPtr wParam, IntPtr lParam) {
        if (nCode >= 0) {
            Keys key = (Keys)wParam;
            var lp = lParam.ToInt64();
            //your own handling with the key
            if ((lp >> 31) == 0)//Key down 
            { 
              //your own code ...
            } else { //Key up
              //your own code ...
            }
        }
        return CallNextHookEx(hHook, nCode, wParam, lParam);
  }
  KeyBoardProc proc;
  //other code ...
}
//then use the new overload constructor instead of the parameterless constructor:
globalHook = new globalKeyboardHook(true);

:上記の投稿(コメント)に基づいて、独自のイベントをKeyDown実装できます。いくつかの検索の後、 はグローバル フックのみをサポートし、は専用であることがわかりました。の代わりにそれが必要です。KeyUpyour own code ...WH_KEYBOARD_LLWH_KEYBOARDthread hookWH_KEYBOARD_LL

ところで、IMessageFilterこの場合、アプリケーションで登録/追加できる を使用できるとは思えません。PreFilterMessageでのキーおよびマウス メッセージをインターセプトするのに役立つ方法もサポートしていapplication-levelます。それを検索してみてください。簡単にフォローできます。

于 2013-10-28T16:01:26.460 に答える