WPF模式下Chrome触摸失效的解决方案
现象:
从wpf画面跳转到Chrome画面会产生触摸失灵的现象。过一段时间后自动恢复。
原因分析
查阅相关资料后对产生现象的原因进行分析
1.触摸屏使用USB连接的外部连接设备。只能被一个进程独立占用。
2.触摸的消息传递机制是由微软系统本身控制的。
3.暴力测试后发现某些其他设备也会存在相关的无法触摸问题。
总结:当触摸点落在wpf程序上时,触发退出机制,触摸点未及时挪开,导致触摸点又落在浏览器上。系统未及时转交触摸权限给浏览器。导致触摸事件无法传达给浏览器。造成触摸失灵的假死现象。(鼠标点击正常无误)
解决方案
方法1.由于是触摸点未计时释放造成的,所以我们退出机制改为WPF程序不存在触摸点后退出程序。
在 windows 的头部加入下列参数
TouchEnter="Window_enter"
TouchLeave="Window_TouchLeaver"
Stylus.IsPressAndHoldEnabled="false"
Stylus.IsFlicksEnabled="false"
TouchEnter 代码如下:
lock (locker)
{
touchid.Add(e.TouchDevice.Id);
}
log.WriteLogFile(e.TouchDevice.Id.ToString(), "TouchDeviceID");
记录下按下的触摸点ID。
TouchLeave 代码如下:
lock (locker)
{
touchid.Remove(e.TouchDevice.Id);
}
if (touchid?.Count() > 0)
{
return;
}
this.Close();
监测触摸点是否完全释放,只有在完全释放时会执行关闭。
效果:
方法2.之前分析,是由于系统未及时将触摸的权限分配给浏览器,所以造成的假死,那我们可以用代码在关闭wpf程序后人为的手动激活一次浏览器。
代码如下
这是标准的微软提供的激活代码
private bool SetTopWindow(IntPtr hWnd)
{
try
{
IntPtr hForeWnd = GetForegroundWindow();
int dwForeID;
GetWindowThreadProcessId(hForeWnd, out dwForeID);
IntPtr dwCurID = GetCurrentThreadId();
AttachThreadInput(dwCurID.ToInt32(), dwForeID, 1);
SwitchToThisWindow(hWnd, true);
ShowWindow(hWnd, SW_SHOWMAXIMIZED);
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
SetForegroundWindow(hWnd);
AttachThreadInput(dwCurID.ToInt32(), dwForeID, 0);
SetFocus(hWnd);
return true;
}
catch (Exception ex)
{
log.WriteLogFile(ex.ToString(), "TimeMonitoring");
return false;
}
}
调用如下
Process[] pro = Process.GetProcesses();
for (int i = 0; i < pro.Length; i++)
{
if (pro[i].ProcessName.ToLower().Trim().Contains("chrome"))
{
try
{
var x = SetTopWindow(pro[i].MainWindowHandle);
}
catch (Exception ex)
{
log.WriteLogFile(ex.ToString(), "TimeMonitoring");
}
}
}
相关Api参照标准定义方式:
[DllImport("user32.dll")]
public static extern int AttachThreadInput(int idAttach, int idAttchTo, int fAttch);
方法3.查阅相关资料后,发现这类问题是.NETFramework 4.5出现的BUG,一直到4.7才修复,所以我们将框架升级到4.7之上。同时在程序启动最开始的地方加入
<runtime>
<AppContextSwitchOverrides value="Switch.System.Windows.Input.Stylus.EnablePointerSupport=true" />
</runtime>
完整版
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
</startup>
<runtime>
<AppContextSwitchOverrides value="Switch.System.Windows.Input.Stylus.EnablePointerSupport=true" />
</runtime>
</configuration>
总结
三种方法都实际经过上线测试。如果有更好的做法希望可以相互交流,共同学习