WPF Applications Stop Responding to Touches after Adding or Removing Tablet Devices

栏目: 编程工具 · 发布时间: 6年前

内容简介:WPF framework handles touch devices and events mostly using its own code and COM components instead of using the windows message loop. Unfortunately, there may be some bugs in the WPF touch handling codes. So we sometimes suffer from the WPF touch failure

WPF framework handles touch devices and events mostly using its own code and COM components instead of using the windows message loop. Unfortunately, there may be some bugs in the WPF touch handling codes. So we sometimes suffer from the WPF touch failures. This changes after Microsoft introducing .NET Framework 4.7, but the developers have to switch on the Pointer message manually with some compliant issues.

In this article, I’ll post some codes of WPF to present its potential bugs of touch failure.

This post is written in multiple languages . Please select yours:

The touch failure issue

Even if you write a very simple WPF application which contains only a button, you’ll be suffering from the touch failure issue.

What you need is:

  1. Run any WPF application
  2. Keep plugging and unplugging a USB HID tablet device

The actions above helps reproduce touch failure with a small probability. But if you want a larger probability, you should:

  • Make a high CPU usage

Probably there may be other conditions such as the .NET Framework version and the Windows version but I’m not sure.

When you put them together, you’ll get a full touch failure issue description.

  • Run any WPF application with a high CPU usage, and then keep plugging and unplugging a USB HID tablet device, you’ll get the WPF application which stops responding to touches.
  • If multiple WPF applications are running at the same time, most of them will lose touch.

Preliminary analysis of the touch failure

WPF use two different threads to collect touch information from tablet devices and convert them to the Stylus and Mouse event that most of us are familiar to.

  1. The Main thread of WPF. WPF use windows message loop on this thread to handle mouse message and device change message.
  2. The Stylus Input thread. WPF run the unmanaged code and call COM component to collect device information and touch information.

The WPF stylus code uses the windows message loop to handle these messages:

  • LBUTTONDOWN, LBUTTONUP
  • DEVICECHANGE, TABLETADDED, TABLETREMOVED

The Stylus Input thread is created by the PenThreadWorker class. The PenThreadWorker call GetPenEvent and GetPenEventMultiple in the thread loop to fetch the whole touch events of tablet devices and then it will pass the raw touch data to other touch modules to translate them into regular Stylus/Touch/Mouse events. One of the touch modules is the WorkerOperationGetTabletsInfo class which contains an OnDoWork method to fetch tablet device count through COM components.

The touch failure comes from the code of the Stylus Input thread.

  1. An empty _handles array is passed into the GetPenEventMultiple method of PenThreadWorker and this action may cause infinite waiting.
  2. A COMException or ArgumentException may happen when the OnDoWork of WorkerOperationGetTabletsInfo is running. This method will catch the exceptions and returns an empty array which will cause the WPF application get empty tablet devices by mistake even if there are tablet devices in actual.

I’ve simplified the core .NET Framework code of the stylus handling above. You may understand what I mean more clearly by reading these codes:

// PenThreadWorker.ThreadProc
while(There are two loops in real)
{
    // The `break` below only exit one loop, not two.
    if (this._handles.Length == 1)
    {
        if (!GetPenEvent(this._handles[0], 其他参数))
        {
            break;
        }
    }
    else if (!GetPenEventMultiple(this._handles, 其他参数))
    {
        break;
    }
    // Other logics.
}
// WorkerOperationGetTabletsInfo.OnDoWork
try
{
    _tabletDeviceInfo = PenThreadWorker.GetTabletInfoHelper(pimcTablet);
}
catch(COMException)
{
    _tabletDevicesInfo = new TabletDeviceInfo[0];
}
catch(ArgumentException)
{
    _tabletDevicesInfo = new TabletDeviceInfo[0];
}
// Other exception handling.

I can definitely sure that the ArgumentException is the result of the thread-safety issue but I’m not sure whether COMException is the same. The handles argument is the handles of ResetEvent s which are used for the thread syncing between managed code and unmanaged code. So the infinite waiting of GetPenEventMultiple is actually a deadlock which is also a thread-safety issue.

Remember that we can make a high CPU usage to increase the probability of reproduction, we can infer that the touch failure issue is caused by the thread-safety issue of WPF stylus handling.

The solutions to the touch failure

After inferring the preliminary reason, there are only two fundamental solutions left for us:

  1. Fix the bug of WPF
    • Only Microsoft can fix this kind of bugs because we cannot rebuild WPF all by our selves.
    • Of course, this kind of patch can be introduced in .NET Framework, or be introduced in the WPF on .NET Core 3.
  2. Fix the bug of Windows
    • The COM components provided for WPF may need an update to fix the thread-safety issue or other tablet devices issues.

A more thorough solution is that both of them need to be fixed, but both can only be done by Microsoft .

So what can we non-Microsoft developers do?

  1. Reduce CPU usage
    • Although this is not controlled by us, if we can reduce some unexpected high CPU usage, we can greatly reduce the probability of WPF touch failure.

But what can I do if I’m only a normal user?

  1. Re-plug the touch device (if your touch frame can be manually plugged in via USB connection)

The details analysis for the touch failure

The above conclusions come from the reading and debugging of the .NET Framework source code.

Since WPF touch details involve more types and source code which requires a lot of descriptions, so it is not explained in this article. Read the following article to get a deeper understanding of the touch failure (all of the links are under translating):

All of the .NET Framework source code in this article is decompiled by dnSpy , and the analysis process is basically based on the dnSpy’s no-PDB debugging feature.

本文会经常更新,请阅读原文: https://walterlv.github.io/post/wpf-touch-fails-when-tablet-device-changed-en.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

WPF Applications Stop Responding to Touches after Adding or Removing Tablet Devices 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://walterlv.github.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系


以上所述就是小编给大家介绍的《WPF Applications Stop Responding to Touches after Adding or Removing Tablet Devices》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

人工智能

人工智能

(美)GeorgeF.Luger / 郭茂祖;刘扬;玄萍;王春宇 / 机械工业出版社 / 2010-1 / 79.00元

《人工智能复杂问题求解的结构和策略(原书第6版)》是一本经典的人工智能教材,全面阐述了人工智能的基础理论,有效结合了求解智能问题的数据结构以及实现的算法,把人工智能的应用程序应用于实际环境中,并从社会和哲学、心理学以及神经生理学角度对人工智能进行了独特的讨论。新版中增加了对“基于随机方法的机器学习”的介绍,并提出了一些新的主题,如涌现计算、本体论、随机分割算法等。 《人工智能复杂问题求解的结......一起来看看 《人工智能》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试