翼度科技»论坛 编程开发 .net 查看内容

Winform虚拟/模拟键盘

7

主题

7

帖子

21

积分

新手上路

Rank: 1

积分
21
项目需要在触摸屏上增加一个虚拟键盘。记录下过程中遇到的问题及解决方法。
1.模拟按键

网上找到如下3种方法
1)SendKeys.Send

测试单独的shift不好用,所以最终未采纳此方法
  1. SendKeys.Send("^{E}");//shift+e
  2. SendKeys.Send("{Enter}");
复制代码
2)keybd_event

最终选择了这个方法,简单有效。
虚拟按键对照表:https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
  1. [DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)]
  2. public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
  3. [DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)]<br>public static extern void keybd_event(Keys bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
复制代码
  1. public static uint KEYEVENTF_KEYDOWN = 0;// 键按下 KEYEVENTF_KEYDOWN = 0<br>public static uint KEYEVENTF_KEYUP = 2;//键弹起 KEYEVENTF_KEYUP = 2
复制代码
  1. keybd_event(0x14, 0, KEYEVENTF_KEYDOWN, 0); //键按下 KEYEVENTF_KEYDOWN = 0<br>keybd_event(0x14, 0, KEYEVENTF_KEYUP, 0);  //键弹起 KEYEVENTF_KEYUP = 2
复制代码
3)PostMessage

这个方法也是简单有效,但是据说有些其他问题,没有仔细研究,有兴趣的可以自己研究。
  1. [DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
  2. public static extern int PostMessage(IntPtr hWnd, int Msg, Keys wParam, int lParam);
  3. PostMessage(textBox2.Handle, 256, Keys.D, 2);//模拟按下2次 Keys.D
复制代码
2.各种类型键的处理

微软对键盘输入有进行了分类,可以参考这个。
https://learn.microsoft.com/zh-cn/windows/win32/learnwin32/keyboard-input
1)CapsLock键/NumLock键

想要实现键盘按下抬起与界面效果相同,就需要捕获键盘操作。我使用了Hook
以下这篇博客写的很清晰明了,就不赘述了。
https://www.cnblogs.com/chorm590/p/14199978.html
在hook回调函数中做了如下处理
  1. private int keyboardHookCallback(int code, IntPtr wParam, IntPtr lParam)
  2. {
  3.   if (code < 0)
  4.     {
  5.        return User32.CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
  6.     }
  7.    else
  8.    {
  9.      Keyboard_LL_Hook_Data khd = (Keyboard_LL_Hook_Data)Marshal.PtrToStructure(lParam, typeof(Keyboard_LL_Hook_Data));
  10.       System.Diagnostics.Debug.WriteLine($"key event:{wParam}, key code:{khd.vkCode}, event time:{khd.time}");
  11.       if ((int)wParam == 256 && khd.vkCode == 0x14)
  12.       {
  13.         IsCapsLockDown = !IsCapsLockDown;
  14.       }
  15.       return User32.CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
  16.    }
  17. }
  18. private bool isCapsLockDown;
  19. private bool IsCapsLockDown
  20. {
  21.   get { return isCapsLockDown; }
  22.    set
  23.     {
  24.       isCapsLockDown = value;
  25.        this.buttonCapsLock.BackColor = value ? Color.Gray : Control.DefaultBackColor;
  26.     }
  27. }
  28. private void buttonCapsLock_Click(object sender, EventArgs e)
  29. {
  30.   User32.keybd_event(VirtualKeyCode.CAPS_LOCK, 0, 0, 0);   //键按下 KEYEVENTF_KEYDOWN = 0
  31.    User32.keybd_event(VirtualKeyCode.CAPS_LOCK, 0, 2, 0);  //键弹起 KEYEVENTF_KEYUP = 2
  32. }
复制代码
初始化时同步键盘CapsLock/NumLock状态,使用user32.GetKeyState.返回值等于1则按下状态
  1. [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
  2. public static extern short GetKeyState(int keyCode);
  3. public static bool GetState(byte VKeyCode)
  4. {
  5.   return (User32.GetKeyState(VKeyCode) == 1);
  6. }
复制代码
2)其他组合键处理

ctrl+shift切换输入法,只响应这一种功能键+功能键。其他小伙伴有好的方法可以分享一下。
3)输入键+组合键

如ctrl+c,ctrl+v,ctrl+a,ctrl+z等等。
此方法不是最优方式,可以改进功能键存放在Queue中,遍历功能键,按顺序响应。
  1. private void HandleKeysCombin(byte VKCode)
  2. {
  3.   //设置焦点控件
  4.    this.ActiveControl = this.m_CustomActiveControl;
  5.    lock (this)
  6.    {
  7.      if (IsCtrlDown)
  8.       {
  9.         keybd_event(VirtualKeyCode.CTRL, 0, KEYEVENTF_KEYDOWN, 0);                //键按下 KEYEVENTF_KEYDOWN = 0
  10.       }
  11.       if (IsShiftDown)
  12.       {
  13.         keybd_event(VirtualKeyCode.SHIFT, 0, KEYEVENTF_KEYDOWN, 0);                //键按下 KEYEVENTF_KEYDOWN = 0
  14.       }
  15.       if (IsAltDown)
  16.       {
  17.         keybd_event(VirtualKeyCode.ALT, 0, KEYEVENTF_KEYDOWN, 0);                //键按下 KEYEVENTF_KEYDOWN = 0
  18.       }
  19.       keybd_event(VKCode, VKCode, User32.KEYEVENTF_KEYDOWN, 0);                //键按下 KEYEVENTF_KEYDOWN = 0
  20.       keybd_event(VKCode, VKCode, User32.KEYEVENTF_KEYUP, 0);           //键弹起 KEYEVENTF_KEYUP = 2
  21.       if (IsCtrlDown)
  22.       {
  23.         keybd_event(VirtualKeyCode.CTRL, 0, KEYEVENTF_KEYUP, 0);                //键弹起 KEYEVENTF_KEYUP = 2
  24.          IsCtrlDown = false;
  25.       }
  26.       if (IsShiftDown)
  27.       {
  28.         keybd_event(VirtualKeyCode.SHIFT, 0, KEYEVENTF_KEYUP, 0);              //键弹起 KEYEVENTF_KEYUP = 2
  29.          IsShiftDown = false;
  30.       }
  31.       if (IsAltDown)
  32.       {
  33.          keybd_event(VirtualKeyCode.ALT, 0, KEYEVENTF_KEYUP, 0);                //键弹起 KEYEVENTF_KEYUP = 2
  34.         IsAltDown = false;
  35.      }
  36.   }
  37. }
复制代码
3.窗体/UserControl焦点的处理

这篇里面方法简单好用,不赘述
 https://blog.csdn.net/accomp/article/details/7209052

来源:https://www.cnblogs.com/lotusgu/archive/2023/05/23/17422796.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具