GetMouseMovePointsEx: Bounds / MOUSEMOVEPOINT в (mp_in) проблемах

Я пытаюсь рассчитать ускорение / скорость курсора.

Я прочитал " Найти скорость мыши" в C# и решил принять предложение Ганса об использовании GetMouseMovePointsEx ( pinvoke.net, MSDN).

Я сделал демонстрационную программу для тестирования (см. Полный код ниже), но у нее есть большое ограничение.

Он не будет возвращать точки, как только курсор покинет окно.
Фактически, функция возвращает -1 (win32Exception 1171, "Точка, переданная GetMouseMovePoints, не находится в буфере"), если выполнение не ограничено точками в MainWindow.

  • Я подозреваю, что это может быть потому, что я использую Mouse.GetPosition() обеспечить mp_in значение.
    Может ли это быть решено с помощью GetCursorPos возможно?

Перемещение или изменение размера окна вызывает myBounds.Contains(currentPosition) быть ложным, когда это должно быть правдой.

  • Вероятно, это глупая ошибка, связанная с тем, как я устанавливаю границы, но для меня не сразу понятно, почему это так. Это также может быть связано с Mouse.GetPosition(), Безотносительно причины мои сравнения не совпадают. Пожалуйста помоги?

На что это похоже

MainWindow.xaml

<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>

MainWindow.xaml.cs

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
        } 
    }  
}

0 ответов

Другие вопросы по тегам