2016-07-28 7 views
2

Net 3.5를 대상으로하는 WPF 응용 프로그램을 상속했으며 Surface Pro 4 (I5)에 설치해야합니다. 응용 프로그램이 다른 지점에 매달려 있으며 애니메이션이 완료 이벤트를 실행하지 못하는 경우가 있습니다 (어쩌면 끝나기도하지만 Duration 속성으로 표시된 시점이 아닐 수도 있습니다).Surface 4 Pro에서 WPF Tablet Support를 비활성화하는 방법은 무엇입니까?

턴어라운드에서 여러 시도를 거친 후 DisableWPFTabletSupport 메서드가 실행되고 끝났음에도 불구하고 (DisableWPFTableSupport 메서드에서 로그 코드를 추가하고 Surface Pro 4에서 4 개의 장치가 제거 되었음) 아마도 WPF Tablet 응용 프로그램이 수시로 매달리고 화면 터치를 계속 캡처하기 때문에 지원이 내 응용 프로그램에서 계속 활성화됩니다.

Surface 4 Pro에서 Net 3.5를 겨냥한 WPF 응용 프로그램을 성공적으로 실행할 수있는 유일한 방법은 Windows 장치 관리자를 사용하여 휴먼 인터페이스의 모든 터치 스크린 관련 장치를 비활성화하는 것입니다.

누구나 Surface 4 Pro에서 WPF Tablet Support를 비활성화 할 수 있습니다.

참고. disable and enable the touchscreen driver에 언급 된 내용에도 불구하고 "HID 호환 터치 스크린 장치"를 비활성화하는 것으로는 충분하지 않습니다. "Intel (R) Precise 터치 장치"가 비활성화되지 않으면 터치 스크린이 활성화 된 상태로 유지되고 대부분의 WPF 응용 프로그램은 실패합니다.

답변

2

나는 동일한 문제가있어서 리플렉션을 사용하여 해결 방법을 찾을 수있었습니다.

이 문제는 창 메시지 WM_TABLET_ADDED, WM_TABLET_REMOVED 또는 WM_DEVICECHANGED (see .net referencesource)를 보낼 때 WPF에서 내부 타블렛 장치 처리를 업데이트 할 때 발생합니다. 이러한 메시지는 사용 된 하드웨어에 따라 생성되거나 생성되지 않을 수 있으므로 원래의 DisableWPFTabletSupport 메소드로 충분할 수도 있고 그렇지 않을 수도 있습니다.

class DisableWPFTouchAndStylus 
{ 

private static void DisableWPFTabletSupport() 
{ 
    // Get a collection of the tablet devices for this window. 
    var devices = Tablet.TabletDevices; 

    if (devices.Count > 0) 
    { 
     // Get the Type of InputManager. 
     var inputManagerType = typeof(InputManager); 

     // Call the StylusLogic method on the InputManager.Current instance. 
     var stylusLogic = inputManagerType.InvokeMember("StylusLogic", 
        BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic, 
        null, InputManager.Current, null); 

     if (stylusLogic != null) 
     { 
      // Get the type of the stylusLogic returned from the call to StylusLogic. 
      var stylusLogicType = stylusLogic.GetType(); 

      // Loop until there are no more devices to remove. 
      while (devices.Count > 0) 
      { 
       // Remove the first tablet device in the devices collection. 
       stylusLogicType.InvokeMember("OnTabletRemoved", 
         BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic, 
         null, stylusLogic, new object[] { (uint)0 }); 
      } 
     } 
    } 

    // END OF ORIGINAL CODE 

    // hook into internal class SystemResources to keep it from updating the TabletDevices on system events 

    object hwndWrapper = GetSystemResourcesHwnd(); 
    if (hwndWrapper != null) 
    { 
     // invoke hwndWrapper.AddHook(.. our method ..) 
     var internalHwndWrapperType = hwndWrapper.GetType(); 

     // if the delegate is already set, we have already added the hook. 
     if (_handleAndHideMessageDelegate == null) 
     { 
      // create the internal delegate that will hook into the window messages 
      // need to hold a reference to that one, because internally the delegate is stored through a WeakReference object 

      var internalHwndWrapperHookDelegate = internalHwndWrapperType.Assembly.GetType("MS.Win32.HwndWrapperHook"); 
      var handleAndHideMessagesHandle = typeof(DisableWPFTouchAndStylus).GetMethod(nameof(HandleAndHideMessages), BindingFlags.Static | BindingFlags.NonPublic); 
      _handleAndHideMessageDelegate = Delegate.CreateDelegate(internalHwndWrapperHookDelegate, handleAndHideMessagesHandle); 


      // add a delegate that handles WM_TABLET_ADD 
      internalHwndWrapperType.InvokeMember("AddHook", 
       BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, 
       null, hwndWrapper, new object[] { _handleAndHideMessageDelegate }); 
     } 
    } 
} 

private static Delegate _handleAndHideMessageDelegate = null; 

private static object GetSystemResourcesHwnd() 
{ 
    var internalSystemResourcesType = typeof(Application).Assembly.GetType("System.Windows.SystemResources"); 

    // get HwndWrapper from internal property SystemRessources.Hwnd; 
    var hwndWrapper = internalSystemResourcesType.InvokeMember("Hwnd", 
       BindingFlags.GetProperty | BindingFlags.Static | BindingFlags.NonPublic, 
       null, null, null); 
    return hwndWrapper; 
} 

private static IntPtr HandleAndHideMessages(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) 
{ 
    if (msg == (int)WindowMessage.WM_TABLET_ADDED || 
     msg == (int)WindowMessage.WM_TABLET_DELETED || 
     msg == (int)WindowMessage.WM_DEVICECHANGE) 
    { 
     handled = true; 
    } 
    return IntPtr.Zero; 
} 

enum WindowMessage : int 
{ 
    WM_TABLET_DEFBASE = 0x02C0, 
    WM_TABLET_ADDED = WM_TABLET_DEFBASE + 8, 
    WM_TABLET_DELETED = WM_TABLET_DEFBASE + 9, 
    WM_DEVICECHANGE = 0x0219 
} 

} 

일부이 구현에 대한 참고 사항 및 제한 사항 :

WPF는에 등록하지 않습니다

내 솔루션은 원래의 코드에 추가 WPF에서이 세 가지 윈도우 메시지를 처리하고 숨길 수 있었다 이러한 메시지는 응용 프로그램 MainWindow에 있지만 각 응용 프로그램 인스턴스에 대해 생성되는 "SystemResources ..."라는 숨겨진 창을 통해 표시됩니다. 따라서 MainWindow에서 이러한 메시지를 처리하는 것은 쉬운 일이 아닙니다.

또한 내 솔루션은 내부 클래스와 내부 속성에 대한 반영과 호출을 많이 사용합니다. .net 4.6.2에서 작동하며 이전 버전에서는 테스트하지 않았습니다. 또한, 닷넷 소스 코드에 대해 자세히 살펴보면이 솔루션에서 처리되지 않는 태블릿 처리가 업데이트되는 다른 두 가지 경로가 있음을 알게되었습니다. TabletCollection 및 HwndStylusInputProvider의 생성자.

+0

표면 4 프로에서 테스트 해 보셨습니까? 솔루션을 공유해 주셔서 감사합니다 – SERWare

+0

@SERWare : 예, SP4에서 작동합니다. 개인적으로 테스트하지는 않았지만 고객의 SP4에서 작동합니다. 내가 아직 서적 책에서 작동한다면, 나는 아직 모른다. 그러나 나는 확신한다. – tseifried

+0

저는 거의 같은 경우입니다. 고객의 SP4에서 오류를 감지했으며 솔루션을 테스트하기 위해 반환 할 때까지 기다려야합니다. 다시 한번 감사드립니다. – SERWare