我有一个能够与鼠标一起使用和使用Touch的WPF应用程序。我禁用所有窗口“增强功能”以便只触摸事件:
Stylus.IsPressAndHoldEnabled="False"
Stylus.IsTapFeedbackEnabled="False"
Stylus.IsTouchFeedbackEnabled="False"
Stylus.IsFlicksEnabled="False"
结果是点击表现得像我想要的,除了两点:
这两个事实的结果是,当Windows正确传输触摸事件时,他仍然将鼠标移动到最后一个主触摸事件。
当我在应用程序中使用触摸时,我不希望窗口完全移动鼠标。有没有办法完全避免这种情况?
注意:
答案 0 :(得分:10)
这是我从现在开始找到的最佳解决方案。不要犹豫发布自己的,特别是如果它更好。
使用SetWindowsHookEx
低级鼠标事件捕获(WH_MOUSE_LL
)以及从Touch转换为鼠标的所有事件都标记为(在事件的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 Applications的评论部分和System Events and Mouse Messages其他信息,以消除笔触摸的歧义。
答案 1 :(得分:0)
我曾经用过一次应用程序的东西,就是简单地设置一个自定义光标,其图像只是一个空白.CUR文件。
关于第二个问题,我确实建议将光标移动到另一个位置,但后来我看到你做了同样的事情。如果您的应用程序无法全屏运行,您只需将该安全位置定义为应用程序窗口的右下角。
答案 2 :(得分:0)
对我来说,是否真正要避免将触摸屏提升为鼠标还不是很清楚,因为您首先要询问如何避免将鼠标光标从触摸屏上移开,但是随后在评论中您明确表示确实要鼠标促销。
如果要避免鼠标升级,我发布了一个适用于Windows 8和更高版本here的答案。
答案 3 :(得分:-1)
遇到了同样的问题,我发现here可以使用PreviewXXX事件确定事件是通过触摸还是通过鼠标输入启动的。看看下面的代码:
private void UIElement_OnPreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.StylusDevice != null)
{
AddInfoItem("Stylus or Touch recognized");
e.Handled = true;
return;
}
AddInfoItem("No Stylus or Touch recognized");
}
您可以查看StylusDevice
的{{1}}属性,以确定之前是否涉及过触摸事件。如果它不为null,则可以将MouseEventArgs
设置为true,以防止引发与PreviewXXX事件对应的事件。
希望有所帮助。可以从here(Dropbox链接)下载此演示项目。