我有一个WPF应用程序,既可以使用鼠标又可以使用Touch。我禁用所有窗口“增强功能”以仅具有触摸事件:

Stylus.IsPressAndHoldEnabled="False"
Stylus.IsTapFeedbackEnabled="False"
Stylus.IsTouchFeedbackEnabled="False"
Stylus.IsFlicksEnabled="False"

结果是,单击行为与我想要的一样,但有两点:
  • 拖动时,在单击的位置会出现一个小的“触摸”光标(小白星)。由于用户的手指已经在该位置,因此完全没有用,不需要反馈(除非我的元素可行,否则可能会改变颜色)。
  • 元素/移动结束后,元素保持“悬停”状态。

  • 两者都是以下事实的结果:在窗口正确传输触摸事件的同时,他仍将鼠标移至最后一个主触摸事件。

    当我在应用程序内部使用touch时,我根本不希望Windows完全移动鼠标。有没有一种方法可以完全避免这种情况?

    笔记:
  • 处理触摸事件对此没有任何改变。
  • 使用SetCursorPos移开鼠标会使光标闪烁,并且不是很友好。
  • 禁用触摸面板作为输入设备会完全禁用所有事件(而且我也更喜欢应用程序本地解决方案,而不是系统范围的解决方案)。
  • 我不在乎解决方案是否涉及COM/PInvoke或将在C/C++中提供,我将进行翻译。
  • 如果有必要修补/挂接某些Windows dll,则该软件将始终在专用设备上运行。
  • 我正在研究Surface SDK,但我怀疑它会显示任何解决方案。由于表面是纯触摸设备,因此不会与鼠标发生不良互动。
  • 最佳答案

    这是我从现在开始发现的最佳解决方案。不要犹豫,发表自己的文章,特别是如果它更好。

    使用 SetWindowsHookEx 低级鼠标事件捕获(WH_MOUSE_LL)以及将所有从Touch转换为Mouse的事件都标记为这样的事实(在事件的ExtraInfo中设置了MOUSEEVENTF_FROMTOUCH标志,请参阅Microsoft's FAQ),我能够全局删除所有鼠标事件来自触摸面板。

    这不是一个理想的解决方案,但是当它以全屏模式运行时(在99%的时间中它是专用的硬件设备),它将在我的应用程序中实现。

    第二步也仅在全屏模式下很好(我不会提供代码,因为它非常简单),只是将鼠标移到“安全”位置,如 SetCursorPos 在屏幕的右下角。

    如果您需要代码,则在a Gist on Github中,我将在本文末尾发布当前版本。要使用它:

    // As long as the instance is alive the conversion won't occur
    var disableTouchMouse = new DisableTouchConversionToMouse();
    
    // To let the conversion happen again, Dispose the class.
    disableTouchMouse.Dispose();
    

    该类的完整源代码:
    namespace BlackFox
    {
        using System;
        using System.ComponentModel;
        using System.Runtime.InteropServices;
        using System.Security;
    
        /// <summary>
        /// As long as this object exists all mouse events created from a touch event for legacy support will be disabled.
        /// </summary>
        class DisableTouchConversionToMouse : IDisposable
        {
            static readonly LowLevelMouseProc hookCallback = HookCallback;
            static IntPtr hookId = IntPtr.Zero;
    
            public DisableTouchConversionToMouse()
            {
                hookId = SetHook(hookCallback);
            }
    
            static IntPtr SetHook(LowLevelMouseProc proc)
            {
                var moduleHandle = UnsafeNativeMethods.GetModuleHandle(null);
    
                var setHookResult = UnsafeNativeMethods.SetWindowsHookEx(WH_MOUSE_LL, proc, moduleHandle, 0);
                if (setHookResult == IntPtr.Zero)
                {
                    throw new Win32Exception();
                }
                return setHookResult;
            }
    
            delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
    
            static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
            {
                if (nCode >= 0)
                {
                    var info = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
    
                    var extraInfo = (uint)info.dwExtraInfo.ToInt32();
                    if ((extraInfo & MOUSEEVENTF_MASK) == MOUSEEVENTF_FROMTOUCH)
                    {
                        if((extraInfo & 0x80) != 0)
                        {
                            //Touch Input
                            return new IntPtr(1);
                        }
                        else
                        {
                            //Pen Input
                            return new IntPtr(1);
                        }
    
                    }
                }
    
                return UnsafeNativeMethods.CallNextHookEx(hookId, nCode, wParam, lParam);
            }
    
            bool disposed;
    
            public void Dispose()
            {
                if (disposed) return;
    
                UnsafeNativeMethods.UnhookWindowsHookEx(hookId);
                disposed = true;
                GC.SuppressFinalize(this);
            }
    
            ~DisableTouchConversionToMouse()
            {
                Dispose();
            }
    
            #region Interop
    
            // ReSharper disable InconsistentNaming
            // ReSharper disable MemberCanBePrivate.Local
            // ReSharper disable FieldCanBeMadeReadOnly.Local
    
            const uint MOUSEEVENTF_MASK = 0xFFFFFF00;
    
            const uint MOUSEEVENTF_FROMTOUCH = 0xFF515700;
            const int WH_MOUSE_LL = 14;
    
            [StructLayout(LayoutKind.Sequential)]
            struct POINT
            {
    
                public int x;
                public int y;
            }
    
            [StructLayout(LayoutKind.Sequential)]
            struct MSLLHOOKSTRUCT
            {
                public POINT pt;
                public uint mouseData;
                public uint flags;
                public uint time;
                public IntPtr dwExtraInfo;
            }
    
            [SuppressUnmanagedCodeSecurity]
            static class UnsafeNativeMethods
            {
                [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
                public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelMouseProc lpfn, IntPtr hMod,
                    uint dwThreadId);
    
                [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
                [return: MarshalAs(UnmanagedType.Bool)]
                public static extern bool UnhookWindowsHookEx(IntPtr hhk);
    
                [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
                public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
                    IntPtr wParam, IntPtr lParam);
    
                [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
                public static extern IntPtr GetModuleHandle(string lpModuleName);
            }
    
            // ReSharper restore InconsistentNaming
            // ReSharper restore FieldCanBeMadeReadOnly.Local
            // ReSharper restore MemberCanBePrivate.Local
    
            #endregion
        }
    }
    

    编辑:从Troubleshooting ApplicationsSystem Events and Mouse Messages的注释部分,可以消除笔触的歧义。

    关于c# - 如何避免鼠标在Touch上移动,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8010104/

    10-16 10:28