none
wpf程序如何进行全局键盘监听? RRS feed

  • 问题

  • 我要在wpf程序中,开启全局键盘监听功能,而且监听功能,wpf窗口程序,即使在非活动窗体下,也能正常使用。

    其使用方式,应该是,开启一个键盘监听器类的实例,然后赋值一个事件委托,委托中编写我的自定义代码,每次按下键盘时,会调用该事件委托。

    请问怎么做?


    • 已编辑 Trian555 2021年6月5日 15:37
    2021年6月5日 15:36

全部回复

  • Hi,Trian555.

    对于wpf全局键盘监听功能,你可以尝试使用以下代码

    wpf项目为项目添加引用System.Windows.Forms

    创建wpf 程序后,需要右击项目下的References->选择Add Reference…->点击Assemblies->搜索并打勾System.Windows.Forms –>点击OK

     

    using System;
    using System.Runtime.InteropServices;
    using System.Windows;
    using System.Windows.Forms;
    namespace globalkeyboard
    {
        public partial class MainWindow : Window
        {
             public MainWindow()
            {     
                 InitializeComponent();
                 KeyboardHook k_hook = new KeyboardHook();
                 k_hook.KeyDownEvent += new
                 System.Windows.Forms.KeyEventHandler(hook_KeyDown);//钩住键按下   
                k_hook.Start();
            }
    private void hook_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
    
            { 
                if(e.KeyValue == (int)Keys.A &&(int)System.Windows.Forms.Control.ModifierKeys == (int)Keys.Alt)
               {         
               System.Windows.MessageBox.Show("Alt+A");       
               }      
               else if (e.KeyValue == (int)Keys.A)     
               {      
                   System.Windows.MessageBox.Show("A");    
               }
            }
    
        }
        class KeyboardHook
        {   
             public event System.Windows.Forms.KeyEventHandler KeyDownEvent;
             public event KeyPressEventHandler KeyPressEvent;
             public event System.Windows.Forms.KeyEventHandler KeyUpEvent;
             public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
             static int hKeyboardHook = 0;  //值在Microsoft SDK的Winuser.h里查询   
             public const int WH_KEYBOARD_LL = 13;   //全局键盘监听鼠标消息设为13   
             HookProc KeyboardHookProcedure; //声明KeyboardHookProcedure作为HookProc类型
            //键盘结构
            [StructLayout(LayoutKind.Sequential)]
            public class KeyboardHookStruct
            {   
                public int vkCode;  //定一个虚拟键码。该代码必须有一个价值的范围1至254   
                public int scanCode; // 指定的硬件扫描码的关键     
                public int flags;  // 键标志     
                public int time; // 指定的时间戳记的这个讯息        
                public int dwExtraInfo; // 指定额外信息相关的信息
            }
            //使用此功能,安装了一个钩子
           [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention =CallingConvention.StdCall)]
           public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtrhInstance, int threadId);
            //调用此函数卸载钩子
           [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention =CallingConvention.StdCall)]
           public static extern bool UnhookWindowsHookEx(int idHook);
            //使用此功能,通过信息钩子继续下一个钩子
           [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention =
            CallingConvention.StdCall)]
            public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam,
    IntPtr lParam);
            // 取得当前线程编号(线程钩子需要用到)
            [DllImport("kernel32.dll")]
    static extern int GetCurrentThreadId();
            //使用WINDOWS API函数代替获取当前实例的函数,防止钩子失效 
            [DllImport("kernel32.dll")]
            public static extern IntPtr GetModuleHandle(string name);   
            public void Start()
            {       
             // 安装键盘钩子
                if (hKeyboardHook == 0)         
                {             
                   KeyboardHookProcedure = new HookProc(KeyboardHookProc);
                  hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,KeyboardHookProcedure,
    GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName),
    0);            
               //SetWindowsHookEx (int idHook, HookProc lpfn, IntPtr hInstance, 
                 int threadId)函数将钩子加入到钩子链表中
            //如果SetWindowsHookEx失败  
                     if (hKeyboardHook == 0)           
                     {                
                        Stop();             
                        throw new Exception("安装键盘钩子失败");          
                     }      
                 }
             }  
             public void Stop()
             {      
                 bool retKeyboard = true;
                 if (hKeyboardHook != 0)      
                 {            
                    retKeyboard =UnhookWindowsHookEx(hKeyboardHook);           
    hKeyboardHook = 0;=      
                 }          
                 if (!(retKeyboard)) throw new Exception("卸载钩子失败!");
            }     
            [DllImport("user32")]   
            public static extern int ToAscii(int uVirtKey, //[in] 指定虚拟关键代码进行翻译。                                    
            int uScanCode, // [in] 指定的硬件扫描码的关键须翻译成英文。                                     
            byte[] lpbKeyState, // [in] 指针,以256字节数组,包含当前键盘的状态。每个元素(字节)的数组包含状态的一个关键。                                     
            byte[] lpwTransKey, // [out] 指针的缓冲区收到翻译字符或字符。
            int fuState); // [in] Specifies whether a menu is active. This parameter must be 1
    if a menu is active, or 0 otherwise.
            [DllImport("user32")]
    public static extern int GetKeyboardState(byte[] pbKeyState);
            [DllImport("user32.dll", CharSet = CharSet.Auto,
    CallingConvention = CallingConvention.StdCall)]  
            private static extern short GetKeyState(int vKey);     
            private const int WM_KEYDOWN = 0x100;//KEYDOWN    
            private const int WM_KEYUP = 0x101;//KEYUP
            private const int WM_SYSKEYDOWN = 0x104;//SYSKEYDOWN
            private const int WM_SYSKEYUP = 0x105;//SYSKEYUP   
            private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
            {          
                  // 侦听键盘事件           
                  if ((nCode >= 0) && (KeyDownEvent != null || KeyUpEvent != null ||KeyPressEvent != null))           
                    {             
                        KeyboardHookStruct MyKeyboardHookStruct =(KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));         
                         // raise KeyDown             
                         if (KeyDownEvent != null && (wParam == WM_KEYDOWN ||wParam ==WM_SYSKEYDOWN))             
                          {                 
                             Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;                 
                             System.Windows.Forms.KeyEventArgs e = new
                             System.Windows.Forms.KeyEventArgs(keyData);                
                             KeyDownEvent(this, e);             
                           }             
    //键盘按下            
                         if (KeyPressEvent != null && wParam == WM_KEYDOWN)         
                         {               
                              byte[] keyState = new byte[256];              
                              GetKeyboardState(keyState);                
                              byte[] inBuffer = new byte[2];               
                              if (ToAscii(MyKeyboardHookStruct.vkCode, 
                              MyKeyboardHookStruct.scanCode,
                              keyState, inBuffer, MyKeyboardHookStruct.flags) ==1)                
                              {                   
                                   KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer[0]);                    
    KeyPressEvent(this, e);                
                               }              
                          }                         
                          if (KeyUpEvent != null && (wParam == WM_KEYUP || wParam ==
    WM_SYSKEYUP))           
                           {
                                Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;        
                                System.Windows.Forms.KeyEventArgs e = new
                                System.Windows.Forms.KeyEventArgs(keyData);            
                                KeyUpEvent(this, e);          
                            }        
                        }        
    //如果返回1,则结束消息,这个消息到此为止,不再传递。        
    //如果返回0或调用CallNextHookEx函数则消息出了这个钩子继续往下传递给接受者         
                       return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
    
            }  
            ~KeyboardHook()
            {
                Stop();
            }
        }
    }

    结果图:

    <audio controls="controls" style="display:none;"></audio>


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    <audio controls="controls" style="display:none;"></audio>
    2021年6月8日 3:18