Jump to content



Photo

Capturing the mouse cursor


  • Please log in to reply
21 replies to this topic

#1 Noobie9876

Noobie9876

    Seeker

  • New Members
  • 9 posts

Posted 11 December 2005 - 01:15 PM

HyperSnapDX has a special function for capturing the mouse cursor only. I'd like to be able to do the same with AutoIt. Many users have asked how to get the pixel values of the mouse cursor. I guess one way to do it is to have an external program for the moment, but it is really somethig I wanna do with AutoIt.





#2 MHz

MHz

    Just simple

  • MVPs
  • 5,400 posts

Posted 11 December 2005 - 01:27 PM

Are you refering to needing something like the existing MouseGetPos() ?

Edited by MHz, 11 December 2005 - 01:28 PM.


#3 w0uter

w0uter

    resreveR nA

  • Active Members
  • PipPipPipPipPipPip
  • 2,262 posts

Posted 11 December 2005 - 01:45 PM

i think he means getting the color of the mouse pointer.
My UDF's:;mem stuff_Mem;ftp stuff_FTP ( OLD );inet stuff_INetGetSource ( OLD )_INetGetImage _INetBrowse ( Collection )_EncodeUrl_NetStat_Google;random stuff_iPixelSearch_DiceRoll

#4 Noobie9876

Noobie9876

    Seeker

  • New Members
  • 9 posts

Posted 11 December 2005 - 02:16 PM

Are you refering to needing something like the existing MouseGetPos() ?

I wanna get the colors of the mouse cursor. For instance in many games the ID of the mouse cursor is usually 0 (unknown) and changes of the mouse cursor in the game do not change the ID. So I need to read out the mouse cursor's color. One workaround I had was to use something like HyperSnap DX to grab a picture of the mouse cursor, then check the bytes of that file to detect differences and thus know which it is. If HyperSnap DX can capture the mouse cursor (and it is only the cursor it captures) out of games, then AutoIt can do it too (soon) I hope.

Something like MousePixelSearch() would seem an appropriate name (to do a pixelsearch on the mouse x-hair).

Note: I have actually no idea how easy/hard it is to implement. Common sense would say that if this was easy, they would have added it to v3 by now. So maybe it is hard?

Edited by Noobie9876, 11 December 2005 - 02:50 PM.


#5 nfwu

nfwu

    I'm not active on these forums

  • Active Members
  • PipPipPipPipPipPip
  • 1,234 posts

Posted 14 December 2005 - 03:01 AM

Will this UDF do?
Opt("MouseCoordMode", 1) Func _getMousePointPixelColor()      Local $pos = MouseGetPos ( )      Return PixelGetColor ( $pos[0] , $pos[1] ) EndFunc

Returns a decimal value of the pixel color of the mouse tip.

#6 w0uter

w0uter

    resreveR nA

  • Active Members
  • PipPipPipPipPipPip
  • 2,262 posts

Posted 14 December 2005 - 01:18 PM

it gets the value from UNDER the mouse (atleast thats what im told)

Edited by w0uter, 14 December 2005 - 01:19 PM.

My UDF's:;mem stuff_Mem;ftp stuff_FTP ( OLD );inet stuff_INetGetSource ( OLD )_INetGetImage _INetBrowse ( Collection )_EncodeUrl_NetStat_Google;random stuff_iPixelSearch_DiceRoll

#7 Kangaroo

Kangaroo

    Seeker

  • Active Members
  • 14 posts

Posted 14 December 2005 - 02:58 PM

it gets the value from UNDER the mouse (atleast thats what im told)


Tried this also with AutoIt, but couldnt find a proven way of doing it.

Wrote a little c++ routine which grabs the BitMap of the actual cursor and does a unique checksum on it. As it uses GetBitMapBits its extremely fast as well. Works only for colored cursors (games) at the moment.

Is that the kind of function you are looking for ?

Edited by Kangaroo, 14 December 2005 - 03:04 PM.


#8 Gigglestick

Gigglestick

    Universalist

  • Active Members
  • PipPipPipPipPipPip
  • 501 posts

Posted 14 December 2005 - 04:10 PM

it gets the value from UNDER the mouse (atleast thats what im told)

I Windows it would, but what about in a full-screen game where, as far as AutoIt knows, the cursor is rendered as part of the image on the screen?

Edited by c0deWorm, 14 December 2005 - 04:11 PM.

My UDFs: ExitCodes

#9 Kangaroo

Kangaroo

    Seeker

  • Active Members
  • 14 posts

Posted 14 December 2005 - 05:30 PM

I Windows it would, but what about in a full-screen game where, as far as AutoIt knows, the cursor is rendered as part of the image on the screen?


Good question, but the cursor bitmap is still separate, so you wont get the Cursor pixel that way.

Just tested it with an Online RPG to be 100% sure.

@Noobie no , its not hard to implement, the checksum thingy is actually 12 lines of code only.
But it probably wasnt implemented a long time ago, as AutoIt is not intended mainly for the Gamers scene I guess.

Edited by Kangaroo, 14 December 2005 - 05:40 PM.


#10 Noobie9876

Noobie9876

    Seeker

  • New Members
  • 9 posts

Posted 15 December 2005 - 12:21 AM

Good question, but the cursor bitmap is still separate, so you wont get the Cursor pixel that way.

Just tested it with an Online RPG to be 100% sure.

@Noobie no , its not hard to implement, the checksum thingy is actually 12 lines of code only.
But it probably wasnt implemented a long time ago, as AutoIt is not intended mainly for the Gamers scene I guess.

I spend some time to try and do the same. I managed to get it to work, but I got stuck after I got a handler for the cursor. I was about to try to turn the handler into a pointer and getting the data from there, but then I realised I actually could detect a cursor change with the handler, so I was happy anyway. That was untill I realised that the game has 3 cursors. hehe. After that I went to look into some online code repositories & MSDN. I found some code, but they all stopped after getting the handle :P

Would love to see your code. This is the code I got now (which works for the game, but I wanna get the data from the handle).

Plain Text         
#include <stdio.h> #include <windows.h> #include <string.h> HCURSOR GetCurrentCursorHandle() {     DWORD cursorWindowIDDword, currentFocusedWindowIDDword;     HCURSOR cursorHandle = NULL;     HWND currentWindowHandle;     POINT cursorCoordinatesPoint;         GetCursorPos(&cursorCoordinatesPoint);     currentWindowHandle = WindowFromPoint(cursorCoordinatesPoint);     cursorWindowIDDword = GetWindowThreadProcessId(currentWindowHandle, NULL);     currentFocusedWindowIDDword = GetCurrentThreadId();     if (currentFocusedWindowIDDword != cursorWindowIDDword)     {         if (AttachThreadInput(currentFocusedWindowIDDword, cursorWindowIDDword, TRUE))         {             // Returns NULL on failure             cursorHandle = GetCursor();             // Detach for good measure             AttachThreadInput(currentFocusedWindowIDDword, cursorWindowIDDword, FALSE);         }     }     else     {         cursorHandle = GetCursor();     }     return cursorHandle; } int main(int argc, char **argv) {     HANDLE cursorHandle;     while (1 == 1)   {     Sleep(1000);     cursorHandle = GetCurrentCursorHandle();         if (cursorHandle != NULL)     {          printf("%d\n",cursorHandle);     }   }   return 0; }


#11 Kangaroo

Kangaroo

    Seeker

  • Active Members
  • 14 posts

Posted 15 December 2005 - 09:48 AM

No problem, as I said the code is quite straight forward. As with most BITMAP handling the solution is quite obvious once you found out how :P
Plain Text         
//------------------------------------------------------- //---   GetCursorID: get unique Cursor ID (proprietary) //------------------------------------------------------- int GetCursorID( ) {   // get the cursor, return if no handle     CURSORINFO cCursor;     ZeroMemory(&cCursor,sizeof(cCursor));     cCursor.cbSize=sizeof( cCursor );     if (!GetCursorInfo(&cCursor)) return 0;     // get the icon, return if no color icon     ICONINFO cIcon;     if (!GetIconInfo((HICON)(cCursor.hCursor),&cIcon))return 0;     if (!(cIcon.hbmColor)) return 0;     // get the color icon bits, return if not 32x32 , 32bit/pixel     BYTE lpColor[32*32*8];     if (!( ::GetBitmapBits( cIcon.hbmColor ,32*32*8,lpColor)==4096)) return 0;     // do a checksum of scanline 15     int cs=0;     int i1= 32*15*4;        for (int i=0;i<32*4;++i){cs += lpColor[i1+i];}     return cs; }


Please note that I just did a checksum of scanline 15 of the actual cursor to identify it instead of a proper alder checksum. This would get rid of the 32x32, 4bytes/pixel limitation for the cursor as well.

Hope it helps ...

Edited by Kangaroo, 15 December 2005 - 09:55 AM.


#12 Noobie9876

Noobie9876

    Seeker

  • New Members
  • 9 posts

Posted 15 December 2005 - 10:01 AM

No problem, as I said the code is quite straight forward. As with most BITMAP handling the solution is quite obvious once you found out how :P

Plain Text         
//------------------------------------------------------- //---   GetCursorID: get unique Cursor ID (proprietary) //------------------------------------------------------- int GetCursorID( ) {   // get the cursor, return if no handle     CURSORINFO cCursor;     ZeroMemory(&cCursor,sizeof(cCursor));     cCursor.cbSize=sizeof( cCursor );     if (!GetCursorInfo(&cCursor)) return 0;     // get the icon, return if no color icon     ICONINFO cIcon;     if (!GetIconInfo((HICON)(cCursor.hCursor),&cIcon))return 0;     if (!(cIcon.hbmColor)) return 0;     // get the color icon bits, return if not 32x32 32bit     BYTE lpColor[32*32*8];     if (!( ::GetBitmapBits( cIcon.hbmColor ,32*32*8,lpColor)==4096)) return 0;     // do a checksum of scanline 15     int cs=0;     int i1= 32*15*4;    // 15 row adress     for (int i=0;i<32*4;++i){cs += lpColor[i1+i];}     return cs; }

Please note that I just did a checksum of scanline 15 of the actual cursor to identify it instead of a proper alder checksum. This would get rid of the 32x32 limitation for the cursor as well.

Hope it helps ...

That's fantastic! Thanks a zillion times!!!

#13 psylem

psylem

    Seeker

  • Active Members
  • 17 posts

Posted 13 March 2007 - 09:12 PM

Well it took me all night to figure how to do it, but finally I've created a DLL which wraps your function. This should make it easier for people to plug into their scripts...
http://www.geocities.com/subnetjet/CursorTool.zip

#14 hoang anh

hoang anh

    Seeker

  • Active Members
  • 17 posts

Posted 02 April 2007 - 03:49 PM

Using this script make my program working very nice. But It stop working after sometime. I dun know why. Plz help me
;(

Plain Text         
func _run() $size = WinGetPos("") $tam_x= $size[0]+470 $tam_y= $size[1]+380     $r = 20     $alpha = 0     $n = $n +1     Do         $r = $r +1         $alpha =$alpha + 0.2         $x = $r*sin($alpha)         $y = 3/4*$r*cos($alpha)         MouseMove($x+$tam_x, $y+$tam_y, 0)         $ReturnArray = DllCall("CursorTool.dll", "int", "GetCursorId")                 If $ReturnArray[0]= 8760 then             mouseclick($click, $x+$tam_x, $y+$tam_y, 1, 0)             $cursorId = return[0]             $r = 20             $alpha = 0             sleep(GUICtrlRead($input)*1000)         EndIf     until $r > 400 return endfunc


Working nice about 5mins. After that, mouse still moving without click ( seem dllcall not working, cant check Mouse ID)

Edited by hoang anh, 03 April 2007 - 05:52 AM.


#15 aquaandi

aquaandi

    Seeker

  • Active Members
  • 7 posts

Posted 21 April 2007 - 12:50 PM

Using this script make my program working very nice. But It stop working after sometime. I dun know why. Plz help me
;(


Working nice about 5mins. After that, mouse still moving without click ( seem dllcall not working, cant check Mouse ID)


I've got the same problem. Maybe you should integrate a timer that restarts the script every 5 minutes.

#16 Guest_Guest_*

Guest_Guest_*
  • Guests

Posted 30 April 2007 - 04:40 AM

can do other way ?

#17 Zedna

Zedna

    AutoIt rulez!

  • MVPs
  • 8,315 posts

Posted 30 April 2007 - 12:47 PM

Plain Text         
//------------------------------------------------------- //---   GetCursorID: get unique Cursor ID (proprietary) //------------------------------------------------------- int GetCursorID( ) {   // get the cursor, return if no handle     CURSORINFO cCursor;     ZeroMemory(&cCursor,sizeof(cCursor));     cCursor.cbSize=sizeof( cCursor );     if (!GetCursorInfo(&cCursor)) return 0;     // get the icon, return if no color icon     ICONINFO cIcon;     if (!GetIconInfo((HICON)(cCursor.hCursor),&cIcon))return 0;     if (!(cIcon.hbmColor)) return 0;     // get the color icon bits, return if not 32x32 , 32bit/pixel     BYTE lpColor[32*32*8];     if (!( ::GetBitmapBits( cIcon.hbmColor ,32*32*8,lpColor)==4096)) return 0;     // do a checksum of scanline 15     int cs=0;     int i1= 32*15*4;        for (int i=0;i<32*4;++i){cs += lpColor[i1+i];}     return cs; }

Yesterday I written Autoit translation of calling GetCursor and GetCursorInfo API for someone look here

typedef struct { DWORD cbSize; DWORD flags; HCURSOR hCursor; POINT ptScreenPos; } CURSORINFO, *PCURSORINFO, *LPCURSORINFO;


struct = DllStructCreate("dword;dword;hwnd;long;long") DllStructSetData($struct,1, DllStructGetSize($struct)) $return = DllCall("user32.dll", "int", "GetCursorInfo", "ptr", DllStructGetPtr($struct)) If $return[0] = 0 Then     MsgBox(48,'Error','Error code = ' & $return[0]) Else         MsgBox(0,'Info','Flag = ' & DllStructGetData($struct,2) & @CRLF & 'Handle = ' & DllStructGetData($struct,3) & @CRLF & _         'Pos.X = ' & DllStructGetData($struct,4) & @CRLF & 'Pos.Y = ' & DllStructGetData($struct,5) ) EndIf $struct = 0 ƒo݊÷ ÙÊxp”E#‘ëBº»(¯8€ø×÷(uæ®¶ˆ­sbb33c¶†7W'6÷"ÒFÆÄ6ÆÂ‚gV÷C·W6W#3"æFÆÂgV÷C²ÂgV÷C¶‡væBgV÷C²ÂgV÷C´vWD7W'6÷"gV÷C²

Edited by Zedna, 30 April 2007 - 12:48 PM.


#18 psylem

psylem

    Seeker

  • Active Members
  • 17 posts

Posted 12 June 2007 - 04:47 AM

I've got the same problem. Maybe you should integrate a timer that restarts the script every 5 minutes.


Yeah, the DLL is buggy unfortunately. When I find time I will try to make a more reliable version (can't see that happening any time soon).

If you would like to do this your self, you'll need a compiler that can build DLL's. I used Visual Studio 6, then found some tutorials on how to make a simple DLL that just returns a number and make a simple script that can talk to the DLL for testing purposes. After much trial and error I managed to produce this. You could achieve the same thing if you have a basic programming background, some Google skills and a free day to sit down and mess about with it. Debugging memory leaks in C is another thing entirely, but at least knowing how to build the DLL will be a good start.

#19 Guest_someguy_*

Guest_someguy_*
  • Guests

Posted 25 February 2008 - 08:55 AM

Hi,

I was using the C++ Code stated above for some other things. Anyways I found the "Bug":
As stated here: http://msdn2.microsoft.com/en-us/library/m...070(VS.85).aspx you have to free
the bitmaps with the cursor-Image. So just add:

DeleteObject(cIcon.hbmColor);
DeleteObject(cIcon.hbmMask);

after
if (!(GetBitmapBits( cIcon.hbmColor ,32*32*8,lpColor)==4096)) return 0;

Complete code should just look like:

#include <windows.h>
int GetCursorID( )
{ CURSORINFO cCursor;
ZeroMemory(&cCursor,sizeof(cCursor));
cCursor.cbSize=sizeof(cCursor);
if (!GetCursorInfo(&cCursor)) return 0;
ICONINFO cIcon;
if (!GetIconInfo((HICON)(cCursor.hCursor),&cIcon)) return 0;
if (!(cIcon.hbmColor)) return 0;
BYTE lpColor[32*32*8];
if (!(GetBitmapBits( cIcon.hbmColor ,32*32*8,lpColor)==4096)) return 0;
DeleteObject(cIcon.hbmColor);
DeleteObject(cIcon.hbmMask);
int cs=0;
int i1= 32*15*4; // 15 row adress
for (int i=0;i<32*4;++i){cs += lpColor[i1+i];}
return cs;
}

Futher information:
Windows registeres 2 Bitmap-Handles with 32*64 Pixels after calling GetIconInfo owned by the DLL, so used memory gets more and more. You just wont notice, because this is a very small amout. But you also allocate Windows Device Handles. If your DLL has to many handles in use, all handle-creating functions cease to work.
At least i think thats the way things are.

Yes, im aware of how old the initial post is.

#20 BrettF

BrettF

    My Drunk Monkey Guerilla is gonna getcha!

  • MVPs
  • 7,662 posts

Posted 25 February 2008 - 09:58 AM

Great bump of an almost year old topic...




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users