C# GetMouseMovePointsEx:Bounds/MOUSEMOVEPOINT in(mp_in)问题

C# GetMouseMovePointsEx:Bounds/MOUSEMOVEPOINT in(mp_in)问题,c#,winapi,mouse,native-methods,C#,Winapi,Mouse,Native Methods,我试图计算光标的加速度/速度 我阅读并决定采纳Hans的建议,使用GetMouseMovePointsEx(,) 我制作了一个演示程序来测试它(见下面的完整代码),但它有一个很大的限制 一旦光标离开窗口,它将不会返回点。 事实上,如果执行不限于主窗口内的点,则函数返回-1(win32Exception 1171,“传递给GetMouseMovePoints的点不在缓冲区中”) 我怀疑这可能是因为我正在使用Mouse.GetPosition()提供mp\u in值。 这可以通过使用“可能”来解决

我试图计算光标的加速度/速度

我阅读并决定采纳Hans的建议,使用
GetMouseMovePointsEx
(,)

我制作了一个演示程序来测试它(见下面的完整代码),但它有一个很大的限制

一旦光标离开窗口,它将不会返回点。
事实上,如果执行不限于主窗口内的点,则函数返回-1(win32Exception 1171,“传递给GetMouseMovePoints的点不在缓冲区中”)

  • 我怀疑这可能是因为我正在使用
    Mouse.GetPosition()
    提供
    mp\u in
    值。
    这可以通过使用“可能”来解决吗
移动或调整窗口大小会导致
myBounds.Contains(currentPosition)
在应该为真时为假。

  • 这可能是一个愚蠢的错误,与我如何设置边界有关,但我并不清楚这是为什么。它还可能连接到
    Mouse.GetPosition()
    。不管是什么原因,我的比较结果并不一致。请帮忙

它看起来像什么

MainWindow.xaml

MainWindow.xaml.cs
使用系统;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Input;
使用System.Windows.Threading;
使用System.Windows.Interop;
使用System.Runtime.InteropServices;
名称空间MouseVelocity
{
公共部分类主窗口:窗口
{
调度员GetMousePointsNow;
MOUSEMOVEPOINT[]mp_out=新的MOUSEMOVEPOINT[64];
鼠标移动点;
矩形边界;
双速度;
公共const int GMMP\u USE\u DISPLAY\u POINTS=1;
公共常数int GMMP使用高分辨率点=2;
int nnumpoints期望值=20;
uint模式=GMMP\u使用\u显示\u点;
字符串数据收集时间;
int nVirtualWidth=GetSystemMetrics(SystemMetric.SM_CXVIRTUALSCREEN);
int nVirtualHeight=GetSystemMetrics(SystemMetric.SM_CYVIRTUALSCREEN);
int nVirtualLeft=GetSystemMetrics(SystemMetric.SM\u XVIRTUALSCREEN);
int nVirtualTop=GetSystemMetrics(SystemMetric.SM_YVIRTUALSCREEN);
双屏幕宽度=System.Windows.SystemParameters.PrimaryScreenWidth;
双屏幕高度=System.Windows.SystemParameters.PrimaryScreenHeight;
[StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto)]
公共结构MOUSEMOVEPOINT
{
公共int x;
公共智力;
公共整数时间;
公共IntPtr dwExtraInfo;
}
[DllImport(“user32.dll”)]
静态extern int GetSystemMetrics(SystemMetric smIndex);
[DllImport(“user32.dll”,ExactSpelling=true,CharSet=CharSet.Auto,SetLastError=true)]
内部静态外部int GetMouseMovePointsEx(
uint cbSize,
[In]ref MOUSEMOVEPOINT points In,
[Out]MOUSEMOVEPOINT[]points bufferout,
int nBufPoints,
单位分辨率
);
公共主窗口()
{
初始化组件();
GetMousePointsNow=newdispatchermer(newtimespan(0,0,0,0,20),DispatcherPriority.Background,
GetMousePointsNow(勾选,Dispatcher.CurrentDispatcher);GetMousePointsNow.IsEnabled=false;
myBounds=newrect();
}
私有void pMouseDown(对象发送器,鼠标按钮ventargs e){
GetMousePointsNow.Start();}
私有void pMouseUp(对象发送器,鼠标按钮ventargs e){
GetMousePointsNow.Stop();}
私有void GetMousePointsNow_Tick(对象发送方,事件参数e)
{
双宽度=System.Windows.SystemParameters.PrimaryScreenWidth;
双倍高度=System.Windows.SystemParameters.PrimaryScreenHeight;
myBounds.Location=新点(this.Top,this.Left);
myBounds.Size=新大小(this.ActualWidth,this.ActualHeight);
Point currentPosition=指向屏幕(Mouse.GetPosition(this));
如果(!myBounds.Contains(currentPosition)){
GetMousePointsNow.Stop();return;}
var mp_in=new MOUSEMOVEPOINT();
mp_in.x=((int)currentPosition.x)和0x0000FFFF;
mp_in.y=((int)currentPosition.y)和0x0000FFFF;
int cpt=GetMouseMovePointsEx((uint)(封送大小(mp_in)),ref mp_in,mp_out,nnumpoints desired,mode);
如果(cpt==-1){
int win32Error=Marshal.GetLastWin32Error();
抛出新的System.ComponentModel.Win32异常(Win32错误);
}
对于(int i=0;i32767)
mp_out[i].x-=65536;
if(mp_out[i].y>32767)
mp_out[i].y-=65536;
打破
案例GMMP\u使用\u高分辨率\u点:
mp_out[i].x=((mp_out[i].x*(nVirtualWidth-1))-(nVirtualLeft*65536))/nVirtualWidth;
mp_out[i].y=((mp_out[i].y*(nVirtualHeight-1))-(nVirtualTop*65536))/nVirtualHeight;
打破
}
}
显示鼠标点();
显示速度();
}
私有void DisplayMousePoints()
{
字符串结果=”;
XVelocity=新双精度[20];
对于(int i=0;i<20;i++)
{
MOUSEMOVEPOINT thismp=mp_out[i];
int DeltaTime=lastmp.time-thismp.time;
如果(
<Window x:Class="MouseVelocity.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="450" Width="1200" Background="Gray"
    PreviewMouseUp="pMouseUp" PreviewMouseDown="pMouseDown">
<Grid Margin="1">
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition Height="75"/>
    </Grid.RowDefinitions>
    <TextBlock x:Name="txtOutput" Background="LightGray"  Margin="10" FontSize="18" Padding="20"/>
    <Label x:Name="lbl_Velo" FontSize="22" FontWeight="Bold" Background="Black" Foreground="Red" 
           HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Grid.Row="1" Margin="10"/>
</Grid>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using System.Windows.Interop;
using System.Runtime.InteropServices;

namespace MouseVelocity
{
    public partial class MainWindow : Window
    {
        DispatcherTimer GetMousePointsNow;
        MOUSEMOVEPOINT[] mp_out = new MOUSEMOVEPOINT[64];
        MOUSEMOVEPOINT LastMMP;
        Rect myBounds;
        double[] XVelocity;
        public const int GMMP_USE_DISPLAY_POINTS = 1;
        public const int GMMP_USE_HIGH_RESOLUTION_POINTS = 2;
        int nNumPointsDesired = 20;
        uint mode = GMMP_USE_DISPLAY_POINTS;
        string DataCollectionTime;
        int nVirtualWidth = GetSystemMetrics(SystemMetric.SM_CXVIRTUALSCREEN);
        int nVirtualHeight = GetSystemMetrics(SystemMetric.SM_CYVIRTUALSCREEN);
        int nVirtualLeft = GetSystemMetrics(SystemMetric.SM_XVIRTUALSCREEN);
        int nVirtualTop = GetSystemMetrics(SystemMetric.SM_YVIRTUALSCREEN);
        double ScreenWidth = System.Windows.SystemParameters.PrimaryScreenWidth;
        double ScreenHeight = System.Windows.SystemParameters.PrimaryScreenHeight;

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        public struct MOUSEMOVEPOINT
        {
            public int x;
            public int y;
            public int time;
            public IntPtr dwExtraInfo;
        }

        [DllImport("user32.dll")]
        static extern int GetSystemMetrics(SystemMetric smIndex);

        [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto, SetLastError = true)]
        internal static extern int GetMouseMovePointsEx(
                        uint cbSize,
                        [In] ref MOUSEMOVEPOINT pointsIn,
                        [Out] MOUSEMOVEPOINT[] pointsBufferOut,
                        int nBufPoints,
                        uint resolution
                        );

        public MainWindow()
        {
            InitializeComponent();

            GetMousePointsNow = new DispatcherTimer(new TimeSpan(0, 0, 0, 0, 20), DispatcherPriority.Background,
            GetMousePointsNow_Tick, Dispatcher.CurrentDispatcher); GetMousePointsNow.IsEnabled = false;

            myBounds = new Rect();
        }

        private void pMouseDown(object sender, MouseButtonEventArgs e) {
            GetMousePointsNow.Start(); }

        private void pMouseUp(object sender, MouseButtonEventArgs e) { 
            GetMousePointsNow.Stop(); }

        private void GetMousePointsNow_Tick(object sender, EventArgs e)
        {
            double width = System.Windows.SystemParameters.PrimaryScreenWidth;
            double height = System.Windows.SystemParameters.PrimaryScreenHeight;

            myBounds.Location = new Point(this.Top, this.Left);
            myBounds.Size = new Size(this.ActualWidth, this.ActualHeight);

            Point currentPosition = PointToScreen(Mouse.GetPosition(this));

            if (!myBounds.Contains(currentPosition)) {
                GetMousePointsNow.Stop(); return; }

            var mp_in = new MOUSEMOVEPOINT();
            mp_in.x = ((int)currentPosition.X) & 0x0000FFFF;
            mp_in.y = ((int)currentPosition.Y) & 0x0000FFFF;

            int cpt = GetMouseMovePointsEx((uint)(Marshal.SizeOf(mp_in)), ref mp_in, mp_out, nNumPointsDesired, mode);

            if (cpt == -1) {
                int win32Error = Marshal.GetLastWin32Error();
                throw new System.ComponentModel.Win32Exception(win32Error);
            }

            for (int i = 0; i < cpt; i++) {  // Fix for multi-display environment
                switch (mode) {
                    case GMMP_USE_DISPLAY_POINTS:
                        if (mp_out[i].x > 32767)
                            mp_out[i].x -= 65536;
                        if (mp_out[i].y > 32767)
                            mp_out[i].y -= 65536;
                        break;
                    case GMMP_USE_HIGH_RESOLUTION_POINTS:
                        mp_out[i].x = ((mp_out[i].x * (nVirtualWidth - 1)) - (nVirtualLeft * 65536)) / nVirtualWidth;
                        mp_out[i].y = ((mp_out[i].y * (nVirtualHeight - 1)) - (nVirtualTop * 65536)) / nVirtualHeight;
                        break;
                }
            }
            DisplayMousePoints();
            DisplayVelocity();
        }

        private void DisplayMousePoints()
        {
            string Result = ""; 
            XVelocity = new double[20];

            for (int i = 0; i < 20; i++)
            {
                MOUSEMOVEPOINT ThisMMP = mp_out[i];
                int DeltaTime = LastMMP.time - ThisMMP.time;

                if (ThisMMP.time == LastMMP.time) { } // Do nothing if same timestamp
                else {
                    XVelocity[i] = (LastMMP.x - ThisMMP.x) / (double)DeltaTime;  // V = x / t
                    if (DeltaTime > 0) // Don't include first point in the calculation
                    {
                        Result = Result += 
                            "X: " + mp_out[i].x + ",  " + 
                            "Timestamp: " + mp_out[i].time.ToString() + ",  " +
                            "Change: (" + DeltaTime.ToString() + "),  " +
                            "Point Velo: " + (XVelocity[i] * 100).ToString("0.000") + Environment.NewLine;
                    }
                }
                DataCollectionTime = DateTime.Now.Second.ToString("00") + DateTime.Now.Millisecond.ToString("000");
                txtOutput.Text = "Time Collected: " + DataCollectionTime + Environment.NewLine + Result;
                LastMMP = ThisMMP;
            }         
        }

        private void DisplayVelocity()
        {
            // Calculate a moving average of velocity values
            double aggregate = 0;
            double weight;
            int item = 1;
            int count = 1;

            foreach (var d in XVelocity)
            {
                weight = (double)item / (double)count;
                aggregate += (double)d * weight;
                count++;
            }
            double result = (aggregate / count) * 100;
            lbl_Velo.Content = result.ToString("0.000");      
        }

        public enum SystemMetric
        {
            SM_XVIRTUALSCREEN = 76, // 0x4C
            SM_YVIRTUALSCREEN = 77, // 0x4D
            SM_CXVIRTUALSCREEN = 78, // 0x4E
            SM_CYVIRTUALSCREEN = 79, // 0x4F
        } 
    }  
}