1

I'm trying to make a C++ code that prints the rgb value of pixel where mouse cursor is every second. I used GetDC(NULL) for HDC of desktop, GetCursorPos(&pos) for the position of mouse cursor, getPixel(hDC, pos.x, pos.y) for the RGB value of the pixel that the mouse cursor points.

Here is my full C++ code.

#include <iostream>
#include <Windows.h>

using namespace std;

int main(){

    POINT pos;
    int R;
    int G;
    int B;
    while (1) {
        GetCursorPos(&pos);
        HDC hDC = GetDC(NULL);
        COLORREF color=GetPixel(hDC, pos.x, pos.y);
        R = GetRValue(color);
        G = GetGValue(color);
        B = GetBValue(color);
        std::cout <<"x : "<<pos.x<<", y : "<<pos.y<<", R : "<< R <<", G : " <<G << ", B : "<<B << endl;
        ReleaseDC(NULL, hDC);
        Sleep(1000);
    }

    return 0;
}

When I compiled this, it prints the rgb value of some pixel every second, however, the pixel doesn't match the pixel where mouse is on. At first, I just thought that the client of some window may have different point, or the total number of pixels in my laptop is less than 1920x1080 (it's actually 1536x864), so there may be a bug, and it could be solved by just translating the point.

But although for some points, it did work, but most points, it didn't work.

And I tried some test. (The code is compiled using visual studio 2017.)

While the code running, I dragged the console window by mouse. (Note that the console window's Non-client window is almost white. i.e. the RGB value is (255, 255, 255). ) So, the relative position of mouse cursor on the console window doesn't change. However, the printed rgb value changed!

I suggest that it may be related to the ppi, but I don't know why exactly.

What should I do and know to get the rgb value of pixel that the mouse cursor points?

정재우
  • 11
  • 5
  • `HDC hDC = GetDC(NULL);` you could have put this above the loop. – drescherjm Jul 17 '20 at 18:48
  • You really need to check the return-values of Win32 function calls to detect errors. Perhaps that's why you're seeing unexpected results? – Dai Jul 17 '20 at 18:51
  • ReleaseDC((HWND)0x001806E6, hDC); it was a mistake... (I revised my code several times and it was one of some window handle. I edited it.) – 정재우 Jul 17 '20 at 19:01
  • How do you know the pixel isn't matching what you get. – Michael Chourdakis Jul 17 '20 at 19:04
  • When the mouse cursor is on small white area, it doesn't return (255, 255, 255). But the mouse cursor is on large white area, it returns (255, 255, 255). I think it means that the code prints the pixel near the mouse cursor, not exactly where the mouse is on. – 정재우 Jul 17 '20 at 19:09
  • Are you sure the pixel at the mouse position is actually pure-white pixel, and not an off-white? What are the actual `color` and `R` `G` `B` values that are being returned? – Remy Lebeau Jul 17 '20 at 19:19
  • Yes. the pixel at the mouse position was pure-white pixel and there was a pure-black pixel left to the white area. if white area is small, printed rgb value was (0, 0, 0) and if white area is wide enough, printed rgb value was (255, 255, 255). And if mouse cursor doesn't move and desktop image doesn't change, then the printed rgb value doesn't change. – 정재우 Jul 17 '20 at 19:36
  • Is this problem only for me? – 정재우 Jul 17 '20 at 19:38

1 Answers1

0

UPDATED ANSWER: The solution appears to be related to the system's DPI setting and the level of DPI awareness of the application as reported by @정재우 and @Remy Lebeau in the comments. In Windows 10, the relevant setting can be found in:

Settings -> Display -> Scale and Layout

The OP's code works fine if this setting is 100%. Otherwise the coordinates returned by GetCursorPos() are scaled. More information can be found in the following articles:

Windows scaling issues for high-DPI devices

High DPI Desktop Application Development on Windows

Setting the default DPI awareness for a process

ORIGINAL ANSWER (WITH SPECULATION): Your code appears to display the correct pixel values on my machine, however you may get different results from different screen configurations such as when using multiple monitors as coordinates left of your primary monitor can be given in negative values. However on my Windows 7 machine using multiple monitors, negative mouse coordinates still properly translate.

Additionally, the "client" area of the screen excludes areas like the taskbar, at least this is how I remember older versions of Windows working. To address this possibility, try replacing your GetDC() call with GetWindowDC() or GetDCEx(NULL,NULL,DCX_WINDOW) and see if you get different results.

To help with debugging, add the following call directly after your GetPixel() call to create subtle red pixel artifacts:

SetPixel(hdc,pos.x,pos.y,RGB(255,0,0));

This places a red pixel on the screen from the same spot you just read the pixel value. Observe how near your red pixels are to the actual mouse cursor as you move the mouse around.

byteptr
  • 1,275
  • 11
  • 15
  • Thanks for the debugging technique. In my laptop (not using multiple display), the changed pixel is lefter and upper than the mouse. the position (0, 0) is well matched. But in (x, y), as x increases, the horizontal gap between mouse and changed pixel increases. And as y increases, the vertical gap between mouse and changed pixel increases. I think there may be a ratio between the position of mouse and changed pixel. – 정재우 Jul 17 '20 at 19:52
  • I found the ratio. changed pixel position : mouse cursor position = 8 : 10 (both x and y) So, I changed COLORREF color=GetPixel(hDC, pos.x, pos.y); to COLORREF color=GetPixel(hDC, pos.x*10/8, pos.y*10/8); And it works! (Still, I don't know why there is a ratio 8:10....) Thank you. – 정재우 Jul 17 '20 at 20:04
  • I found the meaning of 8:10. 1536/1920 is 8/10. When my mouse is at rightmost at the laptop, then the pos.x=1535. (from 0 to 1535, there are 1536 positions of x.) – 정재우 Jul 17 '20 at 20:16
  • When you hit the *"Post Your Answer"* button, you need to make sure to actually have an answer. This proposed answer doesn't even attempt to provide an answer. – IInspectable Jul 17 '20 at 20:32
  • 1
    @정재우 What's the DPI setting of your display(s)? I wonder if you are observing virtualized values. – IInspectable Jul 17 '20 at 20:35
  • Do you get different results with GetWindowDC() rather than GetDC()? What OS version is this? Compare the desktop resolution as reported by display properties with the dimensions of the hdc as described [here](https://stackoverflow.com/questions/3154620/how-to-find-out-dcs-dimensions). GetDeviceCaps() can at least allow you to calculate the ratio rather than hardcoding it. – byteptr Jul 17 '20 at 22:20
  • 1
    My OS is window10. When I checked System-display-Change the size of text, apps, and other items (I guess it is the dpi), it was 125% (Recommended). 125%=10/8, which is the ratio. So, I changed it to 100%. Then, the position (x, y) of mouse at the rightmost is (1919, 1079) and finally the code in the question matches well. – 정재우 Jul 18 '20 at 02:53
  • 1
    @정재우 is your app DPI-aware? If not, then Windows will lie to you using virtualized screen coordinates that don't actually match the physical coordinates, hence the ratio you are seeing. You need to be DPI-aware to get real coordinates, or else take DPI into account when calculating coordinates. – Remy Lebeau Jul 18 '20 at 03:05
  • I get the same results with HDC hDC=GetWindowDC(NULL); when "the size of text, apps, and other items" was 125% (Recommended). And when I printed GetDeviceCaps(hDC, HORZRES), it returns 1536. – 정재우 Jul 18 '20 at 03:14
  • I saw a related article. https://learn.microsoft.com/en-us/visualstudio/designers/disable-dpi-awareness?view=vs-2019 Actually, my project was Windows Desktop Application, not Windows Forms Application. (Since I didn't use C#.) DPI-awareness would be the related option. – 정재우 Jul 18 '20 at 04:07