【问题标题】:c# How to get the Mouse move direction?c#如何获取鼠标移动方向?
【发布时间】:2012-08-31 03:27:42
【问题描述】:

即使鼠标不在屏幕上移动,是否可以获取鼠标移动方向?例如它与边缘碰撞。

编辑: 用户将鼠标移动到顶部并与屏幕的顶部边缘发生碰撞。 然后他继续向上移动鼠标。所以鼠标在现实世界中移动但不在屏幕上移动,因为它不能。我想得到一个信号或其他任何东西来告诉我鼠标在哪个方向移动。

【问题讨论】:

  • 不确定你的意思。有没有机会提供更多细节?
  • 如果鼠标不动,怎么会有移动方向?
  • @Oded:就像你开车撞墙一样。你的轮子正在运转,无法继续前进,但如果你面前没有墙,你仍然可以确定当前的前进方向。
  • @O.R.Mapper - 是的,因为汽车有前后。这将如何与鼠标一起工作?汽车有一个固有的方向 - 屏幕上的鼠标图标没有。
  • @Oded:鼠标光标实际移动时也是如此。关键是鼠标设备,即物理对象,正在向某个方向移动,即使鼠标光标可能不会。 OP 想要检索前一个方向,即物理设备正在移动的方向。以汽车为例,汽车的前后方向无关紧要,只有车轮施加动力的力是相关的。

标签: c# mouseevent


【解决方案1】:

在我看来,基本上您要问的是如何检测鼠标位于屏幕边缘并试图向边缘方向移动的情况。当然,MouseMove 事件不会检测到这一点,因为坐标没有改变。

使用全局低级鼠标钩子可能是获取鼠标移动消息的唯一方法,即使光标没有改变位置。

这允许检查自上一条消息以来坐标是否已更改。如果没有,我们可能处于屏幕边缘。

public partial class Form1 : Form
{
    private const int WH_MOUSE_LL = 14;
    private const int WM_MOUSEMOVE = 0x200;

    [DllImport("kernel32.dll")]
    static extern IntPtr GetModuleHandle(string moduleName);

    [DllImport("user32.dll")]
    static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll")]
    public static extern int UnhookWindowsHookEx(IntPtr hhook);

    [DllImport("user32.dll")]
    static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, uint wParam, IntPtr lParam);
    delegate IntPtr HookProc(int nCode, uint wParam, IntPtr lParam);

    [StructLayout(LayoutKind.Sequential)]
    public struct MSLLHOOKSTRUCT
    {
        public POINT pt;
        public int mouseData; // be careful, this must be ints, not uints (was wrong before I changed it...). regards, cmew.
        public int flags;
        public int time;
        public UIntPtr dwExtraInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;
    }

    private HookProc hookProc;
    private IntPtr hook;

    private POINT formerPoint = new POINT() { X = 0, Y = 0 };

    public Form1() { InitializeComponent(); }

    IntPtr LowLevelMouseProc(int nCode, uint wParam, IntPtr lParam)
    {
        if (wParam == WM_MOUSEMOVE)
        {
            MSLLHOOKSTRUCT infoStr = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
            if (infoStr.pt.X == formerPoint.X && infoStr.pt.Y == formerPoint.Y)
            {
                Console.WriteLine("Mouse moved without coordinates changing");
                //use the standard way of finding the direction of travel here.
            }
            formerPoint = infoStr.pt;
        }
        return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
    }

    protected override void OnHandleDestroyed(EventArgs e)
    {
        UnhookWindowsHookEx(hook);
        base.OnHandleDestroyed(e);
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        if (!DesignMode)
        {
            hookProc = new HookProc(LowLevelMouseProc);
            hook = SetWindowsHookEx(WH_MOUSE_LL, hookProc, GetModuleHandle(null), 0);
        } 
    }
}

*钩子代码取自this博客

这种方法的问题是,如果鼠标的移动速度低于每条鼠标消息 1 个像素,则会产生误报。

对此可能的部分解决方案是预先检测屏幕边缘的 X 和 Y 值并对其进行测试,但即使这样也不能消除 100% 的误报,因为鼠标可能会(例如)位于屏幕的边缘并非常缓慢地向左移动(小于 1 个像素),这仍会被检测为阳性。 p>

也许有人对如何消除这些误报有更好的想法。

【讨论】:

  • 另一个你必须考虑的情况是角落。如果你在右上角。仅通过检查鼠标移动事件触发但 x 或 y 位置没有变化,您不会知道用户是要向右还是顶部移动。
  • @lorenz 是的。不幸的是,在我看来,这些信息只能在鼠标设备和操作系统之间被截获。
  • 不知何故我不能强迫你的案子被弹出。我尽可能慢地移动鼠标,光标没有移动,但也没有触发鼠标事件。
  • @lorenz 钩子是否已经注册或进入?
  • 注册或进入是什么意思?
猜你喜欢
  • 2019-07-10
  • 2015-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多