.NET桌面程序混合开发之四:键盘事件的响应

.NET桌面程序混合开发之四:键盘事件的响应

1. 问题

在生产环境中,有一些场景需要窗体来响应键盘事件(注意,是窗体响应,而不是窗体上的控件响应),如解析扫码枪的扫描结果。但在嵌入WebView2的Form程序,Host Form无法对键盘事件(如窗体的KeyPress)进行截获,同样,也无法对WebView2本身进行键盘事件的响应处理。

2. 传统的键盘事件如何响应

在解决问题前,回顾一下在C#中,传统的窗体键盘事件如何响应。

  • 在窗体属性中,设置KeyPreview属性为Ture;
    enter description here
  • 在窗体事件中,为窗体添加KeyPress事件;
    enter description here
  • 在IDE为你自动添加的响应处理函数中,编写你的处理逻辑
  1. private void Form1_KeyPress(object sender, KeyPressEventArgs e) 
  2. { 
  3. //编写你的响应逻辑 
  4. MessageBox.Show(e.KeyChar.ToString()); 
  5. } 

而在嵌入WebView2的Form程序,Form对键盘事件,无法按照传统处理方式进行截获,也就无法按照原来的处理方式处理了。

3. 问题产生的原因

先来梳理一下窗体响应事件的顺序。

  • 当窗体上没有任何其他控件的时候,窗体是可以直接响应这些消息的,也就是说可以正常响应键盘事件。
  • 但是当窗体存在其他控件后,我们会发现窗体再也不会响应按键消息了,因为这些消息都由其上的控件所处理掉并且不再发给父窗体。
  • 通过Form类的KeyPreview的属性,它是可以接收得到按键消息。也就是第2部分提到的处理方式

分析到这里,基本上能找到webView2加入后引发的怪异行为了。总结起来就是:WebView2拦截了键盘事件。为什么WebView2要这么做?因为WebView本看上是浏览器内核,它要通过最高级别的键盘事件处理一些浏览器事件。如F5刷新,F12调试等,你会发现,哪怕焦点不在webView上,WebView2仍然能响应F5的刷新事件。当然,浏览器的快捷键可以被禁止,但这是另一话题。不可否认的事实就是:WebView影响了消息传递机制。微软可能也意识到这个问题,但对于浏览器的快捷键与用户自定义按键事件的协调,确实是个头疼的事情。这部分是我的猜测。

4. 问题的解决

托管(managed)方式的消息响应失效,尝试非托管方式的处理。思路是:调用Win32的钩子函数,对键盘事件进行拦截,同时将扫描行为进行包装,将获得到的扫描结果(以回边键为结束符),返回托管调用方。

  • 编写单独的ScanerHook类,处理扫描键盘事件。
  • 托管代码,通过注册ScanerEvent事件响应函数,来接收扫描结果。在WinForm中的关键代码如下:
  1. private ScanerHook listener = new ScanerHook(); 
  2.  
  3. public WebViewForm() 
  4. { 
  5. InitializeComponent(); 
  6. InitializeAsync(); 
  7.  
  8. listener.ScanerEvent += (s) => 
  9. { 
  10. webView.CoreWebView2.PostWebMessageAsString(s.Result); //将扫描结果交给页面 
  11. }; 
  12. } 
  • 当窗体打开时,在托管代码中安装钩子
  1. private void WebViewForm_Load(object sender, EventArgs e) 
  2. { 
  3. listener.Start(); 
  4. } 
  • 在窗体关闭时,不要忘记卸载钩子
  1. private void WebViewForm_FormClosed(object sender, FormClosedEventArgs e) 
  2. { 
  3. listener.Stop(); 
  4. } 

至此,页面已经“具备了”扫描条码(二维码)的能力。示例代码是在VS2022,用.net6实现的。

dotnet6form.zip 10.59 KB

posted @ 2022-01-15 14:27  sammy621  阅读(833)  评论(1编辑  收藏  举报