如何在WPF中获取与桌面相关的鼠标位置?

时间:2010-10-20 19:21:58

标签: c# wpf mouse position

问题

当您使用谷歌搜索此类问题时,您会获得大量点击,但所有解决方案都假设您至少有一个窗口。

但我的问题就像我说的那样 - 根本不是假设。我可以有一个窗口,但我可以有零窗口(因为我甚至没有显示一个窗口,或者我只关闭了最后一个窗口)。所以简而言之,解决方案不能依赖于任何窗口小部件或窗口 - 唯一已知的,是桌面(和应用程序正在运行,但它没有任何窗口)。

所以问题是 - 如何获得鼠标位置?

背景

我想显示以鼠标位置为中心的窗口。在WPF中没有这样的模式(只有所有者的中心,或者屏幕的中心)所以我必须手动完成。丢失的部分是鼠标位置。

编辑

谢谢大家,所以现在我有解决方案的第一部分 - 原始位置。现在有一个问题如何转换WPF的数据。我找到了这样的话题: WPF Pixels to desktop pixels 但同样,它假设有一些窗口。

然后我用Google搜索更多,我找到了解决方案: http://jerryclin.wordpress.com/2007/11/13/creating-non-rectangular-windows-with-interop/

代码包括仅依靠桌面信息放大/缩小坐标的类。所以加入这两件,我终于得到了解决方案:-)。再次感谢。

3 个答案:

答案 0 :(得分:19)

获取屏幕坐标:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetCursorPos(out POINT lpPoint);

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

    public POINT(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }
}

private void WritePoint(object sender, RoutedEventArgs e)
{
    POINT p;
    if (GetCursorPos(out p))
    {
        System.Console.WriteLine(Convert.ToString(p.X) + ";" + Convert.ToString(p.Y));
    }
}

将像素转换为WPF单位:

[DllImport("User32.dll")]
static extern IntPtr GetDC(IntPtr hwnd);

[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

[DllImport("user32.dll")]
static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);

private Point ConvertPixelsToUnits(int x, int y)
{
    // get the system DPI
    IntPtr dDC = GetDC(IntPtr.Zero); // Get desktop DC
    int dpi = GetDeviceCaps(dDC, 88);
    bool rv = ReleaseDC(IntPtr.Zero, dDC);

    // WPF's physical unit size is calculated by taking the 
    // "Device-Independant Unit Size" (always 1/96)
    // and scaling it by the system DPI
    double physicalUnitSize = (1d / 96d) * (double)dpi;
    Point wpfUnits = new Point(physicalUnitSize * (double)x,
        physicalUnitSize * (double)y);

    return wpfUnits;          
}

将两者放在一起:

private void WriteMouseCoordinatesInWPFUnits()
{
    POINT p;
    if (GetCursorPos(out p))
    {
        Point wpfPoint = ConvertPixelsToUnits(p.X, p.Y);
        System.Console.WriteLine(Convert.ToString(wpfPoint.X) + ";" + Convert.ToString(wpfPoint.Y));
    }
}

答案 1 :(得分:4)

两个选项:

使用System.Windows.Forms.Control.MousePosition或p / invoke

[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern bool GetCursorPos([In, Out] NativeMethods.POINT pt);

第一个选项已经为你做了p / invoke。我不完全确定它需要你有一些用户界面泼溅,但我不这么认为。是的,它的winforms而不是wpf,但它确实与它所处的位置无关。

如果您想跳过system.windows.forms.dll上的任何依赖项,请查看more information about the second on pinvoke.net

答案 2 :(得分:0)

我在寻找同一问题的解决方案时偶然发现了这个问题。与此同时,我发现了PointToScreen,它不需要任何P / Invoke。该方法适用于任何Visual启动.NET 3.0(以及UIElementControl等),实现方式如下:

protected void OnMouseLeave(object Sender, MouseEventArgs e) {
    var relativePosition = e.GetPosition(this);
    var screenPosition = this.PointToScreen(relativePosition);
}