Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Different co-ords for DllCall GetPixel and mouse_event??


  • Please log in to reply
20 replies to this topic
Dr Spam
  • Members
  • 16 posts
  • Last active: Jan 23 2007 01:29 AM
  • Joined: 31 Dec 2006
Why is this? And how can I make DllCall GetPixel use the same co-ordinates as DllCall mouse_event?

DllCall mouse_event uses co-ords relative to top left of the screen but DllCall Getpixel uses the current screen resolution, which is awkward for anyone to use the script once its published.


Example: these two lines act on the same spot on the screen

DllCall("mouse_event", uint,1, int, 195, int, 105, uint,0, int,0 )
and
DllCall("GetPixel", "uint", hdc, "int", 466, "int", 248)


Ive played around with CoordMode, tried all the permutations of pixel, caret and mouse, with screen or relative but GetPixel stays in the same place - perhaps I need the DllCall equivalent of Coordmode?

Thanks for any help

EDIT: PixelGetColor doesnt work with all fullscreen apps so I cannot use it, hence the use of mouse_event and GetPixel.

tonne
  • Members
  • 1654 posts
  • Last active: May 06 2014 06:22 PM
  • Joined: 06 Jun 2006
From MSDN:

VOID mouse_event(
DWORD dwFlags,
DWORD dx,
DWORD dy,
DWORD dwData,
DWORD dwExtraInfo
);
dwFlags specifies various aspects of mouse motion and button clicking. The following table shows possible values for this parameter, which can be combined.

#define MOUSEEVENTF_MOVE 0x0001 /* mouse move */
#define MOUSEEVENTF_LEFTDOWN 0x0002 /* left button down */
#define MOUSEEVENTF_LEFTUP 0x0004 /* left button up */
#define MOUSEEVENTF_RIGHTDOWN 0x0008 /* right button down */
#define MOUSEEVENTF_RIGHTUP 0x0010 /* right button up */
#define MOUSEEVENTF_MIDDLEDOWN 0x0020 /* middle button down */
#define MOUSEEVENTF_MIDDLEUP 0x0040 /* middle button up */
#define MOUSEEVENTF_XDOWN 0x0080 /* x button down */
#define MOUSEEVENTF_XUP 0x0100 /* x button down */
#define MOUSEEVENTF_WHEEL 0x0800 /* wheel button rolled */
#define MOUSEEVENTF_VIRTUALDESK 0x4000 /* map to entire virtual desktop */
#define MOUSEEVENTF_ABSOLUTE 0x8000 /* absolute move */

If MOUSEEVENTF_ABSOLUTE value is specified, dx and dy contain normalized absolute coordinates between 0 and 65,535. The event procedure maps these coordinates onto the display surface. Coordinate (0,0) maps onto the upper-left corner of the display surface, and (65535,65535) maps onto the lower-right corner.


Bottom line: To move to absolute position use 0x8001 for dwFlags and calculate coords using the virtual screenresolution 65535x65535

Dr Spam
  • Members
  • 16 posts
  • Last active: Jan 23 2007 01:29 AM
  • Joined: 31 Dec 2006
wow thanks for the quick reply tonne

I have been googling and looking on MSDN but GetPixel does not seem to have the same dwFlags syntax as mouse_event does?

COLORREF GetPixel(
HDC hdc, // handle to DC
int nXPos, // x-coordinate of pixel
int nYPos // y-coordinate of pixel
);

Parameters

hdc
[in] Handle to the device context.
nXPos
[in] Specifies the x-coordinate, in logical units, of the pixel to be examined.
nYPos
[in] Specifies the y-coordinate, in logical units, of the pixel to be examined.



So im still a bit confused as to how to make GetPixel use any other co-ords? As soon as I mess with hdc it all breaks and googling GetPixel only ever describes it as "Returns the color of the pixel at the specified location" but never talks about the what the location is, just where.

Hopefully im doing something wrong, it would be great if there are absolute co-ordinates for GetPixel like that. Would there be perhaps somewhere in the handle getting process where I could specify a co-ord mode perhaps?

thanks!

YMP
  • Members
  • 424 posts
  • Last active: Apr 05 2012 01:18 AM
  • Joined: 23 Dec 2006

PixelGetColor doesnt work with all fullscreen apps so I cannot use it, hence the use of mouse_event and GetPixel

Sorry, but what exactly is wrong with PixelGetColor? From what you wrote in your previous posts, I could not figure it out. "Broken co-ordinates" - what does it actually mean? It sounds to me somewhat metaphorical and confusing. :roll:

Dr Spam
  • Members
  • 16 posts
  • Last active: Jan 23 2007 01:29 AM
  • Joined: 31 Dec 2006
PixelGetColor (and the others that rely on the same co-ord system, such as MouseGetPos) does not work with all fullscreen apps- theres no metaphore intended, it just doesnt work. Somehow the mouse acceleration gets involved and throws the whole system out of alignment.

EG. to get my head around the nature of the problem I wrote this small tool so I could see what was happening.

LControl & RAlt::
mousegetpos, mouseX, mouseY
sleep 50
DllCall("mouse_event", uint,1, int, mouseX, int, mouseY, uint,0, int,0 ) 
return

So what do you think happens when the key is pressed? The cursor should stay exactly where it is right? No, with each press it moves exponentially away from 0,0.

To get some kind of tracking numbers I measured each step (click) with a ruler (high tech eh? 'sok i was a carpenter in a former life) and only dealt with the Y axis (the X was behaving the same way so i didnt see the point of doing both).


click #1 1cm down from 0,0
click #2 3.5cm down from 0,0
#3 10cm down
#4 30.5cm

Then I changed my windows mouse acceleration slider to full and the numbers came up 1, 4.75, 22.25

Changed it again to exactly half and bang, there came a pattern I could recognise, 1, 2.2, 4.4, 8.8, 17.7.

Now to me that looks like a 2x gradient. So next i played around at the bottom end of the acceleration to see if I could find a 1:1 mapping point but it just went crazy, off the screen in one keypress. The best I could get was moving the slider to about 2/5ths of the way up where then the keypress would move in 1cm steps, but thats still no good.

So as you can see, its quite broken when it comes to certain fullscreen apps, thats why im having to use dll calls rather than the built in co-ordinate system.

EDIT: Yes I did try SetDefaultMouseSpeed, no change.

tonne
  • Members
  • 1654 posts
  • Last active: May 06 2014 06:22 PM
  • Joined: 06 Jun 2006
Well, as a consequence of the MSDN information:
LControl & RAlt:: 
  coordmode,mouse,screen
  mousegetpos, mouseX, mouseY
  sleep 50
  mouseX := mouseX*65535/a_screenwidth
  mouseY := mouseY*65535/a_screenheight
  DllCall("mouse_event", uint,0x8001, int, mouseX, int, mouseY, uint,0, int,0 )
return

I'm using the same coordmode as mouse_event and calculating a new position based on the virtual screen dimension 65535x65535 and the actual screen dimension.
Edit: The 0x8001 parameter tells mouse_event to use absolute position, without it the mouse will move mousex,mousey!

Nearly perfect - seems to be some unresolved rounding problem, the cursor may move a pixel.

Dr Spam
  • Members
  • 16 posts
  • Last active: Jan 23 2007 01:29 AM
  • Joined: 31 Dec 2006
tonne, sorry, I think we have our wires crossed a bit, I dont have a problem with mouse_event, thats ok with the co-ordinates it has (195,105), its the GetPixel event that I need to change from screen co-ordinates to either the same system as mouse_event, or the relative system that you showed me above (or any other co-ordinates, just not the screen resolution).

As for the tool I just mentioned, it has no other use than to map how screwed up the co-ordinates are while running the app im trying to manipulate in fullscreen - if you run it on a desktop it would be fine, the cursor wouldnt move, its only when my main app runs that the AHK co-ordinates get somehow multiplied by the mouse acceleration and the script tool correctly showed that.

tonne
  • Members
  • 1654 posts
  • Last active: May 06 2014 06:22 PM
  • Joined: 06 Jun 2006
Hm, yes, maybe...

I found this http://www.autohotke...opic.php?t=9300 it might help you.

Dr Spam
  • Members
  • 16 posts
  • Last active: Jan 23 2007 01:29 AM
  • Joined: 31 Dec 2006
I thought this was a known thing btw. I found several mentions about the broken co-ords in fullscreen apps in my searches on this forum when I first hit the problem.

<!-- m -->http://www.autohotke...pic.php?t=10566<!-- m -->
<!-- m -->http://www.autohotke...pic.php?t=11418<!-- m -->
<!-- m -->http://www.autohotke...pic.php?t=10494<!-- m -->
<!-- m -->http://www.autohotke...pic.php?t=10148<!-- m -->

I would get the same results as these guys, co-ords would either stick at 0,0 or fly across the screen - but noone had an answer how to deal with it so to progress I played around manually with different numbers to see where the cursor really went, which led me to write that little strip of code simply to see exactly what the problem was, without re-compiling for every test value.

Dr Spam
  • Members
  • 16 posts
  • Last active: Jan 23 2007 01:29 AM
  • Joined: 31 Dec 2006

Hm, yes, maybe...

I found this http://www.autohotke...opic.php?t=9300 it might help you.



Ahh yes it was that thread where I got the DllCall GetPixel idea from in the first place.

I know for sure that there is no problem with transparency, GetPixelColor and GetPixel did actually work for the colours, I tested for the color in 0,0, changed it and tested again and it worked, so theres no transparency problem. Also I have the function fully working with GetPixel just theres this damn issue with it using screen co-ordinates when another dllcall, mouse_event uses perfectly good relative co-ordinates.

It works for me in 1920x1200 but I cant switch resolution or pass it on to others without some relative co-ords.

Well, im thinking if its this hard to manipulate GetPixels co-ords, perhaps I ought to see if I can write a function that tests for resolution and then apply the relevant co-ordinate mask, but thats a helluva lot of script for every popular resolution from 800x600 up with the mask at 10 items = maybe 90-100 variables? just to fix a co-ordinate problem for one - theres got to be an easier way? :)

tonne
  • Members
  • 1654 posts
  • Last active: May 06 2014 06:22 PM
  • Joined: 06 Jun 2006
Maybe a dumb question: Why not use
DllCall("SetCursorPos", int, mousex, int, mousey)

Doesn't it work in fullscreen mode!?

tonne
  • Members
  • 1654 posts
  • Last active: May 06 2014 06:22 PM
  • Joined: 06 Jun 2006
This function use, IMHO, the same coordinates as GetPixel (if a_screenwidth and a_screenheight have to right value in fullscreen mode):
MouseSetPos(mouseX,mouseY)
{
  DllCall("mouse_event", uint, 0x8001, int, ceil(mouseX*65535/a_screenwidth), int, ceil(mouseY*65535/a_screenheight), uint, 0, uint, 0)
}


YMP
  • Members
  • 424 posts
  • Last active: Apr 05 2012 01:18 AM
  • Joined: 23 Dec 2006
Dr Spam

Excuse me once more, but the example you gave cannot work as you say it should. You can't expect that the cursor stays where it is. MouseGetPos, by default, retrieves the cursor's co-ordinates that are relative to the active window. While mouse_event, in the form you used it in your example, takes those co-ordinates for relative to the cursor's current position. Hence the results you got.
And yes, it uses acceleration in that mode:

If the MOUSEEVENTF_ABSOLUTE value is not specified, dx and dy specify relative motions from when the last mouse event was generated (the last reported position). Positive values mean the mouse moved right (or down); negative values mean the mouse moved left (or up).

Relative mouse motion is subject to the settings for mouse speed and acceleration level. An end user sets these values using the Mouse application in Control Panel. An application obtains and sets these values with the SystemParametersInfo function.


With the improvement of tonne, it's still not perfect, indeed. Depending on the cursor's position on the screen, it may move a pixel or so, or not move. This may be unavoidable while two different co-ordinate systems are in use and you have to transform between them. So, I doubt that GetPixel will solve your problem, as it uses pixel-based co-ordinates. CoordMode seems to have nothing to do with it.

As for the GetCursorPos and SetCursorPos functions, I suspect those are the ones employed by MouseGetPos and MouseMove.

Dr Spam
  • Members
  • 16 posts
  • Last active: Jan 23 2007 01:29 AM
  • Joined: 31 Dec 2006

Maybe a dumb question: Why not use

DllCall("SetCursorPos", int, mousex, int, mousey)

Doesn't it work in fullscreen mode!?


Hi tonne, thanks for the reply, no SetCursorPos is superfluous, I need a GetPixel event, setting the mouse after is not a problem. The problem is that I cannot use GetPixel without providing a co-ordinate (itll just get 0,0 if its left blank) and the co-ordinates I do give have to be based on screen resolution and will change from user to user.

Seems ive found another unsolvable puzzle? :(


Excuse me once more, but the example you gave cannot work as you say it should. You can't expect that the cursor stays where it is. MouseGetPos, by default, retrieves the cursor's co-ordinates that are relative to the active window. While mouse_event, in the form you used it in your example, takes those co-ordinates for relative to the cursor's current position. Hence the results you got.


Damn, I just wrote out a full answer and on review realised that I hadnt posted the complete code.

LControl & RAlt::
mousegetpos, mouseX, mouseY
sleep 50
MouseClick, Left, 0, 0, , , D
Sleep 50
MouseClick, Left, 0, 0, , , U
Sleep 50
DllCall("mouse_event", uint,1, int, mouseX, int, mouseY, uint,0, int,0 ) 
return

does that make more sense? Sorry for the mixup I thought I had recreated it correctly- just tested it and yes its still walking across the screen.

So, I doubt that GetPixel will solve your problem, as it uses pixel-based co-ordinates. CoordMode seems to have nothing to do with it.


Exactly, and theres only 2 ways I know to get a pixel colour, AHK GetPixelColor and DllCall(GetPixel), and only the latter seems to work, the former just returns 0,0 or some wierd unexpected value, depending on where it had been accelerated to.

YMP
  • Members
  • 424 posts
  • Last active: Apr 05 2012 01:18 AM
  • Joined: 23 Dec 2006
MouseClick, Left, 0, 0, , , D
Well, I supposed that you had been doing something of the kind. All the same, you are still using mouse_event in the relative mode, which seems to me a wrong way because, as MSDN says, "Relative mouse motion is subject to the settings for mouse speed and acceleration level." If you switched it to the absolute, as tonne suggested in his post, it would take any screen for being 65535 units high and 65535 units wide (regardless of its physical size and the resolution chosen by the user). So if you specified the coordinates, say, 32768 for X and 32768 for Y, you would be sure that it would point at the center of the screen on any monitor.
To pass the same coordinates to GetPixel, you have to express them in pixels, using A_ScreenWidth and A_ScreenHeight. The problem is that those two sets of coords are not always absolutely equivalent. But I don't actually know what precision is required for your purpose. If one pixel doesn't matter, you could try that way.
For example, if the center of the screen is the point you are interested in, it might look like this (note the use of 0x8001 in mouse_event's call):
F11::
  X:=1/2  ; Half way along X. Coords independent of anything.
  Y:=1/2  ; Half way along Y.
  mouse_eventX:=Round(65535*X)  ; The coords for mouse_event.
  mouse_eventY:=Round(65535*Y)  ; Round them to get integers.
  GetPixelX:=Round(A_ScreenWidth*X)  ; The same coords for GetPixel.
  GetPixelY:=Round(A_ScreenHeight*Y)

  ; Move the cursor to the center.
  DllCall("mouse_event", "int", 0x8001, "int", mouse_eventX, "int", mouse_eventY, "int", 0, "int", 0)

  ; Get the color of the center.
  hdc := DllCall("GetDC", "uint", 0) 
  if hdc 
  { 
    ColorBGR := DllCall("GetPixel", "uint", hdc, "int", GetPixelX, "int", GetPixelY) 
    DllCall("ReleaseDC", "uint", 0, "uint", hdc) 
    SetFormat, Integer, H  ; Change to hex format. 
    MsgBox % ColorBGR+0    ; Make the number become hex. 
  }
Return