WPF 觸控失效 試試重啟觸控

2021-10-25 20:07:09 字數 3290 閱讀 6947

在使用一些詭異的系統以及詭異的觸控框的時候,也許會出現 wpf 程式觸控失效,失效的本質原因是 win32 層應用觸控失效。也許出現的問題是某個視窗設定 topmost 然後插拔一些觸控裝置等,這些行為,如果觸控裝置太過詭異,也許就會讓 win32 視窗觸控失效。剛好 wpf 也是乙個 win32 視窗,此時的 wpf 也會觸控失效

這個方法因為過於強,我建議只有你在嘗試過其他方法無法修復之後才能使用。本文的方法修復觸控是根據沒有什麼是重啟解決不了的方法修復的,本文的方法將會使用反射呼叫 wpf 的**,我僅僅有測試 .net framework 4.8 的框架裡面的邏輯,這就意味著需要你在執行的裝置上安裝有 .net framework 4.8 框架,但是對於執行的 wpf 沒有任何限制,可以使用 .net framework 4.5 甚至是 .net framework 4.0 的版本。當然,本文方法對於 .net core 3.1 和 .net 5 同樣生效

本文的核心邏輯就是呼叫 wisplogic 的 registerhwndforinput 和 unregisterhwndforinput 來實現重啟觸控,但是沒有真的結束觸控執行緒,因此不夠徹底。而我自己基於開源的 wpf 框架也定製了可以從觸控執行緒都重啟的強力版本,當然了,這個版本非開源的版本

在使用本文的方法之前,請確定你對觸控有足夠的了解

如果你對觸控的了解很少,那麼我推薦你先看以下部落格

wpf 觸控螢幕應用需要了解的知識

** windows 桌面端觸控架構演進

wpf 客戶端開發需要知道的觸控失效問題

對於 win32 應用來說,如果應用的觸控失效了,可以的解決方法是重新註冊一次觸控,或者重啟應用。而在 wpf 中,沒有公開的方法可以讓咱重啟註冊觸控,但是使用非公開的方法可以呼叫到。關於在 wpf 中的觸控呼叫細節請看 wpf 觸控到事件 和 wpf 通過 inputmanager 模擬排程觸控事件

重啟註冊觸控的步驟就是先反註冊,然後再次註冊。分別呼叫的是 wisplogic 的 unregisterhwndforinput 和 registerhwndforinput 方法,以下是步驟

在 wpf 中,可以使用下面**獲取 styluslogic 物件

private object getstyluslogic()

return null;

}

在沒有開啟 pointer 的情況下,這裡的 styluslogic 就是 wisplogic 物件,因為 wisplogic 的定義如下

internal class wisplogic : styluslogic

在 win10 中,大多數的觸控失效問題,都可以通過開啟 pointer 訊息解決。而在 .net 5 中,修復了 wpf 使用 wm_pointer 訊息在高 dpi 下的相容觸控。如何開啟 pointer 訊息請看 wpf dotnet core 如何開啟 pointer 訊息的支援

在獲取到 wisplogic 就可以通過反射呼叫 registerhwndforinput 和 unregisterhwndforinput 方法來重啟觸控

通過開源的 wpf **可以看到兩個方法的定義如下

internal void registerhwndforinput(inputmanager inputmanager, presentationsource inputsource)

internal void unregisterhwndforinput(hwndsource hwndsource)

這裡的 inputmanager 可以使用 inputmanager.current 獲取,而 presentationsource 可以使用presentationsource.fromvisual(this)獲取,上面的this需要乙個在介面顯示的元素

而 hwndsource 可以使用下面**獲取

var windowinterophelper = new windowinterophelper(this);

var hwndsource = hwndsource.fromhwnd(windowinterophelper.handle);

先呼叫 unregisterhwndforinput 禁用觸控,然後呼叫 registerhwndforinput 開啟觸控

object styluslogic = getstyluslogic();

if (styluslogic == null)

type inputmanagertype = typeof(system.windows.input.inputmanager);

var wisplogictype = inputmanagertype.assembly.gettype("system.windows.input.styluswisp.wisplogic");

var windowinterophelper = new windowinterophelper(this);

var hwndsource = hwndsource.fromhwnd(windowinterophelper.handle);

var unregisterhwndforinputmethodinfo = wisplogictype.getmethod("unregisterhwndforinput",

bindingflags.instance | bindingflags.nonpublic);

unregisterhwndforinputmethodinfo.invoke(styluslogic, new object );

var registerhwndforinputmethodinfo = wisplogictype.getmethod("registerhwndforinput",

bindingflags.instance | bindingflags.nonpublic);

registerhwndforinputmethodinfo.invoke(styluslogic, new object

);

以上**放在 github 和 gitee 歡迎小夥伴訪問

本文的方法不能解決內部邏輯呼叫問題的觸控失效問題,也不能解決太過詭異的系統的觸控失效問題。本文的重啟觸控的方法的執行速度是很慢的

以上方法也是有缺點的,使用了上面方法之後,就不能使用 高效能 dynamicrenderer 書寫 的方式。解決 dynamicrenderer 丟失的方法就是重新註冊一次 stylusplugin 元素

更多觸控請看 wpf 觸控相關 更多筆跡相關請看

2019 11 29 WPF 從觸控訊息轉觸控事件

title author date createtime categories wpf 從觸控訊息轉觸控事件 lindexi 2019 11 29 08 47 55 0800 2019 05 12 15 12 31 0800 wpf在 wpf 程式可能因為一些坑讓程式觸控失效,如果此時還可以收到系統...

2018 5 4 WPF 獲得觸控精度和觸控點

title author date createtime categories wpf 獲得觸控精度和觸控點 lindexi 2018 05 04 21 11 51 0800 2018 5 4 21 8 4 0800 wpf 觸控 需要通過反射的方法才可以拿到觸控的精度。使用 tablet.tabl...

2018 5 4 WPF 獲得觸控精度和觸控點

title author date createtime categories wpf 獲得觸控精度和觸控點 lindexi 2018 05 04 21 11 51 0800 2018 5 4 21 8 4 0800 wpf 觸控 需要通過反射的方法才可以拿到觸控的精度。使用 tablet.tabl...