SendMessage、PostMessage、keybd_event 发送键盘事件 及 虚拟键码表

大致介绍

  • SendMessage 与 PostMessage

  两者从函数结构上看主要区别其实就是返回值不同,SendMessage返回消息被处理后的返回值,而PostMessage则返回消息是否发送成功。

  其次,SendMessage是同步的,而PostMessage是异步的。SendMessage会等待消息被处理完成之后再返回,PostMessage则会将消息放入处理队列中直接返回。另外,再不同线程操作时,最好用PostThreadMessage代替。

  • keybd_event

  Windows提供的一个模拟键盘API函数,该函数能触发一个按键事件,也就是说同样会产生一个WM_KEYDOWN或WM_KEYUP消息。

  • SendKey

  需要 using System.Windows.Forms;功能是 将一个或多个按键消息发送到活动窗口,就如同在键盘上进行输入一样。其中一些字符都有特殊意义,

  语法:SendKeys.Send(string keys);SendKeys.SendWait(string keys);

几个主要函数

  首先,我们来看一下直接点击 Ctrl + S 在 Spy++ 上显示出的命令:键盘点击产生的事件信息

  下面介绍几个需要用到的函数,代码在下面已贴出。

  • SendMessage : 发送指定的消息到目标窗口。

   parm1:接收窗口的句柄

   parm2:发送的消息,根据不同的需求和不同的对象,需要填入不同的实参。我们在模拟用户操作时,需要填入 WindowMessage参数(下面代码中有给出)。

   parm3:附加的消息信息,对parm2的补充。这边我们应该填入 键盘操作的虚拟键值(键值表下面有给出)。

   parm4:附加的消息信息,对parm2的补充。此处我们需要填入一个32位的uint参数,具体的定义如下:

0~15位:表示发送的次数,一般就是1次

16~23位:表示键盘的操作的扫描码

24位:表示是左ALT、CTRL还是右ALT、CTRL(通常为0)

25~28位:保留

29位:决定了 消息内容中 fAltDown 的值为1还是0(不知道有什么用…)

30位:表示上一个键的状态KEY DOWN or UP,1为发送前的DOWN状态,0为UP

31位:0为按下,1为释放SendMesssage 结果
上图是通过 SendMessage 函数发送相应数据得到的结果。经过对比,spy++确实捕捉到了Ctrl + S 的键盘事件,然而,现象却是,钩子函数没有捕捉到… 很尴尬。(希望有懂的同志能交流下)

  • keybd_event : 模拟键盘事件,向当前活动窗口发送案件信息。

   parm1:键盘虚拟键值

   parm2:键盘键值扫描码(试过之后发现,填0也可以,根本不需要这个值)

   parm3:状态参数:非 KEYEVENTF_KEYUP 即 按下

   parm3:扩展信息(0)
keybd_event结果
上图为 keybd_event 的结果,可以看到,钩子函数捕捉到了!然鹅,spy++捕捉到的键盘事件却和真实点击出现的事件不完全相同。也就是,用了奇怪的方法却完成了需求… 依旧尴尬。

  • FindWindow : 获取某窗口句柄,parm1:窗口类名(null),parm2:窗口关键字

  • FindWindowEx :获取某窗口下的子窗口句柄,可以用 spy++ 获取到子窗口的类名Spy++ 找到的子窗口类名

  • SetForegroundWindow :设置某窗口为当前活动窗口

  • GetForegroundWindow : 获取当前活动窗口

  • ShowWindow :设置窗口,parm2:0:close, 1:normal, 2:min, 3:max

代码

using System.Runtime.InteropServices;

    class Program
    {
        [DllImport("user32.dll", EntryPoint = "FindWindow", CharSet = CharSet.Auto)]
        private extern static IntPtr FindWindow(string classname, string captionName);

        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [DllImport("user32.dll")]
        private static extern int SendMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);

        [DllImport("user32.dll", EntryPoint = "PostMessage")]
        public static extern bool PostMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);

        [DllImport("user32.dll")] private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);

        #region 预定义参数

        #endregion
        // 键盘虚拟键值
        private const int VK_CONTROL = 0X11;
        private const int VK_MENU = 0X12;
        private const int VK_S = 0X53;          // 'S'
        private const int VK_F4 = 0X73;

        private const int KEYEVENTF_EXTENDEDKEY = 0x1;
        private const int KEYEVENTF_KEYUP = 0x2;

        // WindowMessage 参数
        private const int WM_KEYDOWN = 0X100;
        private const int WM_KEYUP = 0X101;
        private const int WM_SYSCHAR = 0X106;
        private const int WM_SYSKEYUP = 0X105;
        private const int WM_SYSKEYDOWN = 0X104;
        private const int WM_CHAR = 0X102;
        private const int WM_DOWN = 0X0028;
        private const int WM_ENTER = 0X000D;
        private const int WM_CLOSE = 0X0010;
        private const int WM_QUIT = 0X0012;

        // keybd_event 状态参数
        public const int WM_SYSCOMMAND = 0x111;
        public const int SC_MINIMIZE = 0xF020;
        public const int SC_MAXIMIZE = 0xF030;

        static void SendMsg(IntPtr hwnd)
        {
            //hwnd = FindWindowEx(hwnd, IntPtr.Zero, "ToolbarWindow32", "");        // 获取子面板的窗口句柄
            Console.WriteLine("进程句柄:    " + hwnd);

            Console.WriteLine("Message : " + PostMessage(hwnd, WM_KEYDOWN, VK_CONTROL, 0x001D0001));                 // Ctrl + S
            Console.WriteLine("Message : " + PostMessage(hwnd, WM_KEYDOWN, VK_S, 0x001F0001));
            Console.WriteLine("Message : " + PostMessage(hwnd, WM_CHAR, 0x13, 0x001F0001));
            Console.WriteLine("Message : " + PostMessage(hwnd, WM_KEYUP, VK_CONTROL, 0xC01D0001));
            Console.WriteLine("Message : " + PostMessage(hwnd, WM_KEYUP, VK_S, 0xC01F0001));

            //Console.WriteLine("Message : " + PostMessage(hwnd, WM_SYSKEYDOWN, VK_MENU, 0x20380001));                 // Alt + F4
            //Console.WriteLine("Message : " + PostMessage(hwnd, WM_SYSKEYDOWN, VK_F4, 0x203E0001));
            //Console.WriteLine("Message : " + PostMessage(hwnd, WM_KEYUP, VK_MENU, 0xE0380001));
            //Console.WriteLine("Message : " + PostMessage(hwnd, WM_KEYUP, VK_F4, 0xE03E0001));
        }

        static void Keybd_event_Msg()
        {
            keybd_event(VK_CONTROL, 0, 0, 0);                   // Ctrl + S
            keybd_event(VK_S, 0, 0, 0);
            keybd_event(VK_S, 0, KEYEVENTF_KEYUP, 0);
            keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);

            //keybd_event(VK_MENU, 0, 0, 0);                   // Alt + F4
            //keybd_event(VK_F4, 0, 0, 0);
            //keybd_event(VK_F4, 0, KEYEVENTF_KEYUP, 0);
            //keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
        }

        static void Main()
        {
            IntPtr mwh1 = IntPtr.Zero;

            while (mwh1 == IntPtr.Zero)
            {
                Console.WriteLine("寻找窗口中...");

                mwh1 = FindWindow(null, "HookReceiverWpf");

                Thread.Sleep(1000);
            }

            //SendMsg(mwh1);
            SetForegroundWindow(mwh1);
            Keybd_event_Msg();

            //System.Windows.Forms.SendKeys

            Console.ReadKey();
        }
    }

虚拟键值表

虚拟键十六进制值十进制值相应键盘或鼠标键
VK_LBUTTON11鼠标左键
VK_RBUTTON22鼠标右键
VK_CANCEL33Ctrl-Break键
VK_MBUTTON44鼠标中键
VK_BACK88Backspace键
VK_TAB99Tab键
VK_CLEAR0C12Clear键
VK_RETURN0D13Enter键
VK_SHIFT1016Shift键
VK_CONTROL1117Ctrl键
VK_MENU1218Alt键
VK_PAUSE1319Pause键
VK_CAPITAL1420Caps Lock键
VK_ESCAPE1B27Esc键
VK_SPACE2032Space键
VK_PRIOR2133Page Up键
VK_NEXT2234Page Down键
VK_END2335End键
VK_HOME2436Home键
VK_LEFT2537←键
VK_UP2638↑键
VK_RIGHT2739→键
VK_DOWN2840↓键
VK_SELECT2941Select键
VK_PRINT2A42Print键
VK_EXECUTE2B43Execute键
VK_SNAPSHOT2C44Print Screen键
VK_INSERT2D45Ins键
VK_DELETE2E46Del键
VK_HELP2F47Help键
VK_030480键
VK_131491键
VK_232502键
VK_333513键
VK_434524键
VK_535535键
VK_636546键
VK_737557键
VK_838568键
VK_939579键
VK_A4165A键
VK_B4266B键
VK_C4367C键
VK_D4468D键
VK_E4569E键
VK_F4670F键
VK_G4771G键
VK_H4872H键
VK_I4973I键
VK_J4A74J键
VK_K4B75K键
VK_L4C76L键
VK_M4D77M键
VK_N4E78N键
VK_O4F79O键
VK_P5080P键
VK_Q5181Q键
VK_R5282R键
VK_S5383S键
VK_T5484T键
VK_U5585U键
VK_V5686V键
VK_W5787W键
VK_X5888X键
VK_Y5989Y键
VK_Z5A90Z键
VK_LWIN5B91左Windows键
VK_RWIN5C92右Windows键
VK_APPS5D93应用程序键
VK_SLEEP5F95休眠键
VK_NUMPAD06096小数字键盘0键
VK_NUMPAD16197小数字键盘1键
VK_NUMPAD26298小数字键盘2键
VK_NUMPAD36399小数字键盘3键
VK_NUMPAD464100小数字键盘4键
VK_NUMPAD565101小数字键盘5键
VK_NUMPAD666102小数字键盘6键
VK_NUMPAD767103小数字键盘7键
VK_NUMPAD868104小数字键盘8键
VK_NUMPAD969105小数字键盘9键
VK_MULTIPLY6A106乘号键
VK_ADD6B107加号键
VK_SEPARATOR6C108分割键
VK_SUBSTRACT6D109减号键
VK_DECIMAL6E110小数点键
VK_DIVIDE6F111除号键
VK_F17012F1键
VK_F271113F2键
VK_F372114F3键
VK_F473115F4键
VK_F574116F5键
VK_F675117F6键
VK_F776118F7键
VK_F877119F8键
VK_F978120F9键
VK_F1079121F10键
VK_F117A122F11键
VK_F127B123F12键
VK_F137C124F13键
VK_F147D125F14键
VK_F157E126F15键
VK_F167F127F16键
VK_F1780128F17键
VK_F1881129F18键
VK_F1982130F19键
VK_F2083131F20键
VK_F2184132F21键
VK_F2285133F22键
VK_F2386134F23键
VK_F2487135F24键
VK_NUMLOCK90144Num Lock键
VK_SCROLL9145Scroll Lock键
VK_LSHIFTA0160左Shift键
VK_RSHIFTA1161右Shift键
VK_LCONTROLA2162左Ctrl键
VK_RCONTROLA3163右Ctrl键
VK_LMENUA4164左Alt键
VK_RMENUA5165右Alt键

最后附上 Spy++ 的链接: https://pan.baidu.com/s/1D3E4N3mRRVwW24i1PonbnA 提取码:azga

  • 6
    点赞
  • 25
    收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页
评论 1

打赏作者

YiZhe0731

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值