Jump to content

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

Compare current cursor to saved image


  • Please log in to reply
4 replies to this topic
glucos
  • Members
  • 4 posts
  • Last active: Nov 19 2011 09:01 PM
  • Joined: 14 Nov 2011
I wrote these two scripts so that I could compare my cursor to a saved bitmap image and perform an operation if they matched. I'm putting them here as two separate scripts, but it's easy to combine them.

;This script will make a bitmap image of the current cursor and put it in the clippboard when you press CTRL + Z

^z::
	VarSetCapacity(mi, 20, 0), mi := Chr(20)
	DllCall("GetCursorInfo", "Uint", &mi)
	bShow   := NumGet(mi, 4)					;1 ==> cursor is visible
	hCursor := NumGet(mi, 8)					;cursor handle
	xCursor := NumGet(mi,12)					;not really needed for this script, but might want later
	yCursor := NumGet(mi,16)

	mDC := DllCall("CreateCompatibleDC", "Uint", 0)			;make a DC compatible with screen
	hBM := CreateDIBSection(mDC, 32, 32)				;makes a blank bitmap based on mDC but 32x32
	oBM := DllCall("SelectObject", "Uint", mDC, "Uint", hBM)		;put hBM into the DC but save contents in oBM

	DllCall("DrawIcon", "Uint", mDC, "int", 0, "int", 0, "Uint", hCursor)	;draw the icon into the DC
	DllCall("DestroyIcon", "Uint", hCursor)				;delete the icon
	DllCall("SelectObject", "Uint", mDC, "Uint", oBM)			;switch back to original DC then delete
	DllCall("DeleteDC", "Uint", mDC)
	SetClipboardData(hBM)					;put the image on the clipboard
return


;this function creates a blank bitmap based on hDC with width=nW and height=nH
CreateDIBSection(hDC, nW, nH, bpp = 32, ByRef pBits = "")
{
	NumPut(VarSetCapacity(bi, 40, 0), bi)
	NumPut(nW, bi, 4)
	NumPut(nH, bi, 8)
	NumPut(bpp, NumPut(1, bi, 12, "UShort"), 0, "Ushort")
	NumPut(0,  bi,16)
	Return	DllCall("gdi32\CreateDIBSection", "Uint", hDC, "Uint", &bi, "Uint", 0, "UintP", pBits, "Uint", 0, "Uint", 0)
}


;this function saves an HBITMAP memory object to the clippboard
SetClipboardData(hBitmap)
{
	DllCall("GetObject", "Uint", hBitmap, "int", VarSetCapacity(oi,84,0), "Uint", &oi)
	hDIB :=	DllCall("GlobalAlloc", "Uint", 2, "Uint", 40+NumGet(oi,44))
	pDIB :=	DllCall("GlobalLock", "Uint", hDIB)
	DllCall("RtlMoveMemory", "Uint", pDIB, "Uint", &oi+24, "Uint", 40)
	DllCall("RtlMoveMemory", "Uint", pDIB+40, "Uint", NumGet(oi,20), "Uint", NumGet(oi,44))
	DllCall("GlobalUnlock", "Uint", hDIB)
	DllCall("DeleteObject", "Uint", hBitmap)
	DllCall("OpenClipboard", "Uint", 0)
	DllCall("EmptyClipboard")
	DllCall("SetClipboardData", "Uint", 8, "Uint", hDIB)
	DllCall("CloseClipboard")
}


;not used in this script, but saves an HBITMAP memory object to file
SaveHBITMAPToFile(hBitmap, sFile)
{
	DllCall("GetObject", "Uint", hBitmap, "int", VarSetCapacity(oi,84,0), "Uint", &oi)
	hFile:=	DllCall("CreateFile", "Uint", &sFile, "Uint", 0x40000000, "Uint", 0, "Uint", 0, "Uint", 2, "Uint", 0, "Uint", 0)
	DllCall("WriteFile", "Uint", hFile, "int64P", 0x4D42|14+40+NumGet(oi,44)<<16, "Uint", 6, "UintP", 0, "Uint", 0)
	DllCall("WriteFile", "Uint", hFile, "int64P", 54<<32, "Uint", 8, "UintP", 0, "Uint", 0)
	DllCall("WriteFile", "Uint", hFile, "Uint", &oi+24, "Uint", 40, "UintP", 0, "Uint", 0)
	DllCall("WriteFile", "Uint", hFile, "Uint", NumGet(oi,20), "Uint", NumGet(oi,44), "UintP", 0, "Uint", 0)
	DllCall("CloseHandle", "Uint", hFile)
}

;This script takes two saved bitmap images and compares them pixel by pixel when you press CTRL + C
#Include %A_ScriptDir%

#p::Pause

^c::
hBM1 := LoadBMPIntoDC("file_address")					;put in the file adress
hBM2 := LoadBMPIntoDC("file_address")
result := CompareBMP32(hBM1, hBM2)
if result = 1
MsgBox, didn't match
else
MsgBox, matched
return


;this function loads a bitmap into memory and returns the handle
LoadBMPIntoDC(bmpfile)
{
	hBmp := DllCall("LoadImage","Uint", 0, "str", bmpfile, "Uint", 0, "int", 32, "int",32, "Uint", 0x00000010)	;load the image from file
	return hBmp
}


;this function takes two bitmaps and compares the first 32x32 pixel square on them
;returns 0 if they match and 1 if they don't
CompareBMP32(hBM1, hBM2)
{
	x=0
	mDC1 := DllCall("CreateCompatibleDC", "Uint", 0)				;create DC compatible with screen
	mDC2 := DllCall("CreateCompatibleDC", "Uint", 0)
	DllCall("GetObject", "Uint", hBM1)					;retrieve the object with handle hBM1
	DllCall("GetObject", "Uint", hBM2)
	oBM1 := DllCall("SelectObject", "Uint", mDC1, "Uint", hBM1)			;put the object in the device context
	oBM2 := DllCall("SelectObject", "Uint", mDC2, "Uint", hBM2)
	while x < 32
	{
		 y=0
		while y < 32
		{
			color1 := DllCall("GetPixel", "Uint", mDC1, "int", x, "int",y)	;get the RGB of pixel (x, y)
			color2 := DllCall("GetPixel", "Uint", mDC2, "int", x, "int",y)
			if color1 <> %color2%				;if colors are different, didn't match
			{
				MsgBox %color1% and %color2% at (%x%, %y%)
				return 1
			}
			y+=1
		}
		x+=1
	}
	DllCall("SelectObject", "Uint", mDC1, "Uint", oBM1)			;put the original contents back in DC
	DllCall("SelectObject", "Uint", mDC2, "Uint", oBM2)
	DllCall("DeleteDC", "Uint", mDC1)					;delete DC (prevent memory leak)
	DllCall("DeleteDC", "Uint", mDC2)
	DllCall("DeleteObject", "Uint", hBM1)					;delete the images in memory
	DllCall("DeleteObject", "Uint", hBM2)
	return 0								;if it made it this far, matched
}

If you want to actually see the image loaded into memory for debugging or whatever you will need to create an extra dc and blit the image into it.

hBmp := DllCall("LoadImage","Uint", 0, "str", bmpfile, "Uint", 0, "int", 32, "int",32, "Uint", 0x00000010)	;load the image
	mDC1 := DllCall("CreateCompatibleDC", "Uint", 0)						;create screen compatible DC
	mDC2 := DllCall("CreateCompatibleDC", "Uint", 0)
	hBM := CreateDIBSection(mDC, 32, 32)							;makes blank bmp based on mDC
	oBM1 := DllCall("SelectObject", "Uint", mDC1, "Uint", hBmp)					;puts hBmp in mDC
	oBM2 := DllCall("SelectObject", "Uint", mDC2, "Uint", hBM)
	DllCall("BitBlt", "Uint", mDC, "int", 0, "int", 0, "int", 32, "int", 32, "Uint", mDC1, "int", 0, "int", 0, "Uint", 0x00CC0020)	;blits mDC1 over mDC2
	DllCall("SelectObject", "Uint", mDC1, "Uint", oBM1)					;puts original contents back in DC
	DllCall("SelectObject", "Uint", mDC2, "Uint", oBM2)
	DllCall("DeleteDC", "Uint", mDC1)							;delete DC
	DllCall("DeleteDC", "Uint", mDC2)
	DllCall("DeleteObject", "Uint", hBM)
	dosomethingwith(hBmp)
;make sure the required functions are present


I got some of the functions from this post:
http://www.autohotke...t=screencapture

Thanks for checking it out! :D
Posted Image

chaidy
  • Members
  • 57 posts
  • Last active: Oct 21 2015 05:53 PM
  • Joined: 20 Apr 2010
nice script.

Moderated
  • Members
  • 124 posts
  • Last active: Aug 27 2015 04:01 PM
  • Joined: 28 May 2012

Why would you use two common hotkeys?



gregster
  • Members
  • 283 posts
  • Last active: Nov 09 2015 03:08 AM
  • Joined: 19 Mar 2009

Why would you use two common hotkeys?

 

 How is this even a question, when it would take fractions of a second to change that to your preferences?

 

 

@ glucos: Thank you for the scripts. Haven't tried them yet, but I'll have use for them, for sure.



chaidy
  • Members
  • 57 posts
  • Last active: Oct 21 2015 05:53 PM
  • Joined: 20 Apr 2010

i did edit your script for 32 bit and 64bit compatible code.

 

F11: capture current mouse cursor and save to bitmap file for cursor matching test. (testCursor.bmp)

F12: cursor matching test

#SingleInstance Force
^\::ExitApp

;capturing current mouse cursor and save to "testCursor.bmp"
F11::
	CaptureCursor("testCursor.bmp")
return

;compare to testCursor.bmp and current mouse cursor
F12::
	loop
	{
		ToolTip, % IsMatchCursor("testCursor.bmp")? "match" : "unmatch"
		Sleep, 100
	}
return

;---------------------------------------------------------------
;	CaptureCursor and IsMatchCursor
;---------------------------------------------------------------
;captureTo: "clipboard"=save to clipboard , "bitmap_handle"=return current cursor bitmap handle.
;return: 0=fail , 1=success
CaptureCursor(captureTo="clipboard", cursorSize=32)
{
	VarSetCapacity(CURSORINFO, A_PtrSize=8? 24:20, 0)
	VarSetCapacity(ICONINFO, A_PtrSize=8? 32:20, 0)
	NumPut(A_PtrSize=8? 24:20, CURSORINFO, 0,"UInt")
	DllCall("GetCursorInfo", "UPTR", &CURSORINFO)
	hCursor := NumGet(CURSORINFO, 8, "UPtr")
	flags := NumGet(CURSORINFO, 4, "UInt")
	if !hCursor or !flags
		return 0
	hCursor := DllCall("CopyIcon", "UPTR", hCursor)
	DllCall("GetIconInfo", "UPTR", hCursor, "UPTR", &ICONINFO)

	mDC := DllCall("CreateCompatibleDC", "UPTR", 0, "UPTR")
	hBM := CreateDIBSection(mDC, cursorSize, cursorSize)
	oBM := DllCall("SelectObject", "UPTR", mDC, "UPTR", hBM, "UPTR")
	
	DllCall("DrawIcon", "UPTR", mDC, "int",0, "int",0, "UPTR", hCursor)
	
	DllCall("SelectObject", "UPTR", mDC, "UPTR", oBM)
	DllCall("DeleteDC", "UPTR", mDC)
	DllCall("DestroyIcon", "UPTR", hCursor)
	If hbmMask := NumGet(ICONINFO, A_PtrSize=8? 16:12, "UPtr")
		DllCall("DeleteObject", "UPTR", hbmMask)
	If hbmColor := NumGet(ICONINFO, A_PtrSize=8? 24:16, "UPtr")
		DllCall("DeleteObject", "UPTR", hbmColor)

	if captureTo=bitmap_handle
		return hBM
	If captureTo=clipboard
		SetClipboardData(hBM)
	else
		SaveHBITMAPToFile(hBM, captureTo)
	DllCall("DeleteObject", "UPTR", hBM)
	return 1
}

;compare cursor bmp file to current mouse cursor.
; 1 : cursor image match
; 0 : cursor image unmatch
; ""; hide mouse cursor or can't get cursor handle.
IsMatchCursor(bmpCursorFile)
{
	if !hCursorBmp := CaptureCursor("bitmap_handle", bmpSize:=32)
		return ""
	hSourceBmp := LoadBMP(bmpCursorFile)
	return !CompareBitmap(hSourceBmp, hCursorBmp, bmpSize)
}


;---------------------------------------------------------------
;	Sub function
;---------------------------------------------------------------
;this function takes two bitmaps and compares the first 32x32 pixel square on them
;hBM1 and hBM2: bitmap handle
;return: 0=match, 1=unmatch
CompareBitmap(hBM1, hBM2, size=32)
{
	x=0
	mDC1 := DllCall("CreateCompatibleDC", "Uint", 0)			;create DC compatible with screen
	mDC2 := DllCall("CreateCompatibleDC", "Uint", 0)
	oBM1 := DllCall("SelectObject", "UPTR", mDC1, "UPTR", hBM1)	;put the object in the device context
	oBM2 := DllCall("SelectObject", "UPTR", mDC2, "UPTR", hBM2)
	while x < size
	{
		y=0
		while y < size
		{
			color1 := DllCall("GetPixel", "UPTR", mDC1, "int", x, "int",y)	;get the RGB of pixel (x, y)
			color2 := DllCall("GetPixel", "UPTR", mDC2, "int", x, "int",y)
			if color1 <> %color2%	;if colors are different, didn't match
				return 1
			y+=1
		}
		x+=1
	}
	DllCall("SelectObject", "UPTR", mDC1, "UPTR", oBM1)	;put the original contents back in DC
	DllCall("SelectObject", "UPTR", mDC2, "UPTR", oBM2)
	DllCall("DeleteDC", "UPTR", mDC1)					;delete DC (prevent memory leak)
	DllCall("DeleteDC", "UPTR", mDC2)
	DllCall("DeleteObject", "UPTR", hBM1)				;delete the images in memory
	DllCall("DeleteObject", "UPTR", hBM2)
	return 0	;0 return if match
}

CreateDIBSection(hDC, nW, nH, bpp = 32, ByRef pBits = "")
{
	VarSetCapacity(BITMAPINFO, 44, 0)
	NumPut(44, BITMAPINFO, 0,"UInt")
	NumPut(nW, BITMAPINFO, 4,"Int")
	NumPut(nH, BITMAPINFO, 8,"Int")
	NumPut(1, BITMAPINFO, 12,"UShort")
	NumPut(bpp, BITMAPINFO, 14,"UShort")
	Return	DllCall("gdi32\CreateDIBSection", "UPTR", hDC, "UPTR", &BITMAPINFO, "Uint", 0, "UPTR", pBits, "Uint", 0, "Uint", 0)
}

SetClipboardData(hBitmap)
{
	VarSetCapacity(DIBSECTION, A_PtrSize=8? 104:84, 0)
	NumPut(40, DIBSECTION, A_PtrSize=8? 32:24,"UInt")	;dsBmih.biSize
	DllCall("GetObject", "UPTR", hBitmap, "int", A_PtrSize=8? 104:84, "UPTR", &DIBSECTION)
	biSizeImage := NumGet(DIBSECTION, A_PtrSize=8? 52:44, "UInt")
	hDIB :=	DllCall("GlobalAlloc", "Uint", 2, "Uint", 40+biSizeImage)
	pDIB :=	DllCall("GlobalLock", "UPTR", hDIB)
	DllCall("RtlMoveMemory", "UPTR", pDIB, "UPTR", &DIBSECTION + (A_PtrSize=8? 32:24), "Uint", 40)
	DllCall("RtlMoveMemory", "UPTR", pDIB+40, "Uint", NumGet(DIBSECTION, A_PtrSize=8? 24:20, "UPtr"), "Uint", biSizeImage)
	DllCall("GlobalUnlock", "UPTR", hDIB)
	DllCall("DeleteObject", "UPTR", hBitmap)
	DllCall("OpenClipboard", "Uint", 0)
	DllCall("EmptyClipboard")
	DllCall("SetClipboardData", "Uint", 8, "UPTR", hDIB)
	DllCall("CloseClipboard")
}

LoadBMP(bmpFile)
{
	bmpFile := GetValidFilePath(bmpFile)
	hBmp := DllCall("LoadImage","Uint", 0, "str", bmpFile, "Uint", 0, "int", 32, "int",32, "Uint", 0x00000010) ;load the image from file
	return hBmp
}

SaveHBITMAPToFile(hBitmap, sFile)
{
	sFile := GetValidFilePath(sFile)
	VarSetCapacity(DIBSECTION, A_PtrSize=8? 104:84, 0)
	NumPut(40, DIBSECTION, A_PtrSize=8? 32:24,"UInt")	;dsBmih.biSize
	DllCall("GetObject", "UPTR", hBitmap, "int", A_PtrSize=8? 104:84, "UPTR", &DIBSECTION)
	hFile:=	DllCall("CreateFile", "UPTR", &sFile, "Uint", 0x40000000, "Uint", 0, "Uint", 0, "Uint", 2, "Uint", 0, "Uint", 0)
	DllCall("WriteFile", "UPTR", hFile, "int64P", 0x4D42|14+40+(biSizeImage:=NumGet(DIBSECTION, A_PtrSize=8? 52:44, "UInt"))<<16, "Uint", 6, "UintP", 0, "Uint", 0)
	DllCall("WriteFile", "UPTR", hFile, "int64P", 54<<32, "Uint", 8, "UintP", 0, "Uint", 0)
	DllCall("WriteFile", "UPTR", hFile, "UPTR", &DIBSECTION + (A_PtrSize=8? 32:24), "Uint", 40, "UintP", 0, "Uint", 0)
	DllCall("WriteFile", "UPTR", hFile, "Uint", NumGet(DIBSECTION, A_PtrSize=8? 24:20, "UPtr"), "Uint", biSizeImage, "UintP", 0, "Uint", 0)
	DllCall("CloseHandle", "UPTR", hFile)
}

GetValidFilePath(filename)
{
	SplitPath, filename, , sDir, sExt, sName
	IfNotInString, sDir, :
		sDir = %A_ScriptDir%\%sDir%
	filename = %sDir%\%sName%.%sExt%
	StringReplace, filename, filename, \\, \, All
	return filename
}

;---------------------------------------------------------------
;	Struct List
;---------------------------------------------------------------
/*

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

typedef struct _ICONINFO {
  BOOL    fIcon;
  DWORD   xHotspot;
  DWORD   yHotspot;
  HBITMAP hbmMask;
  HBITMAP hbmColor;
} ICONINFO, *PICONINFO;

typedef struct tagDIBSECTION {
  BITMAP           dsBm;
  BITMAPINFOHEADER dsBmih;
  DWORD            dsBitfields[3];
  HANDLE           dshSection;
  DWORD            dsOffset;
} DIBSECTION, *PDIBSECTION;

typedef struct tagBITMAPINFOHEADER {
  DWORD biSize;
  LONG  biWidth;
  LONG  biHeight;
  WORD  biPlanes;
  WORD  biBitCount;
  DWORD biCompression;
  DWORD biSizeImage;
  LONG  biXPelsPerMeter;
  LONG  biYPelsPerMeter;
  DWORD biClrUsed;
  DWORD biClrImportant;
} BITMAPINFOHEADER;

typedef struct tagBITMAP {
  LONG   bmType;
  LONG   bmWidth;
  LONG   bmHeight;
  LONG   bmWidthBytes;
  WORD   bmPlanes;
  WORD   bmBitsPixel;
  LPVOID bmBits;
} BITMAP, *PBITMAP;

typedef struct tagBITMAPINFO {
  BITMAPINFOHEADER bmiHeader;
  RGBQUAD          bmiColors[1];
} BITMAPINFO, *PBITMAPINFO;

typedef struct tagRGBQUAD {
  BYTE rgbBlue;
  BYTE rgbGreen;
  BYTE rgbRed;
  BYTE rgbReserved;
} RGBQUAD;

*/