0

I'm making an "eyedropper" tool that will let you select/see a colour under your mouse cursor wherever it is on the screen. I wanted to display colour information on a window, and have the WPF window follow the cursor around as you move it.

The colour part is fine. I'm actually having the most trouble with just getting the window to follow the cursor around. The mouse data is completely incorrect.

The same code in Winforms works flawlessly.

I have tried adding app.manifests to both to make each project DPI aware. This seems to have no effect on the WPF project.

Using .NET 5 and C#. Currently testing on a 4k monitor scaled 150%.

Here's my code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.InteropServices;
using System.Windows.Threading;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool GetCursorPos(out POINT lpPoint);

        DispatcherTimer timer = new DispatcherTimer();

        public struct POINT
        {
            public int X;
            public int Y;


            public static implicit operator Point(POINT point)
            {
                return new Point(point.X, point.Y);
            }
        }

        public MainWindow()
        {
            InitializeComponent();

            timer.Interval = new TimeSpan(15);
            timer.Start();
            timer.Tick += Timer_Tick;
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            POINT p;
            GetCursorPos(out p);
            this.Left = p.X;
            this.Top = p.Y;
        }
    }
}
Dan
  • 1,163
  • 3
  • 14
  • 28
  • 1
    Be aware that `new TimeSpan(15)` creates a timer interval of 15 "ticks", which is 1.5 microseconds. Certainly not what you want. – Clemens Jun 21 '21 at 08:16
  • 1
    Did you try to handle `WM_MOUSEMOVE` events instead of using a timer to poll the cursor positon? – mm8 Jun 21 '21 at 13:32

1 Answers1

0

Check this thread:
How to configure an app to run correctly on a machine with a high DPI setting (e.g. 150%)?

If you opt for manual check of the scaling factor, you can query the display transformation matrix:

Matrix? matrix = PresentationSource.FromVisual(visual)?.CompositionTarget?.TransformToDevice;

visual is the System.Windows.Media.Visual object - your main window. The properties M11 and M22 contain the horizontal and vertical scaling factors (usually the same values). Use those scaling factors to calculate the actual mouse position.

Be careful if you're working on a multi-monitor setup, check which screen's scaling factor you're getting.

And here's another thread that may help you:
C# - How to get real screen resolution in multiple monitors context?

Mike
  • 1,225
  • 10
  • 21