identify cursor pointers

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
javierdals
Posts: 3
Joined: 18 May 2017, 15:35

identify cursor pointers

18 May 2017, 17:29

Hi, I´m new in AutoHotKey. :wave:
I need to identify some cursor pointers, for example the differents pointers in Excel.
A_cursor lists only a few pointers.
Is there a way, with a number, to identify a specific pointer that is not listed in A_cursor values?
A_cursor only gives the value "unknown".

I hope soon I´ll be able to help someone, now I´m just a learner.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: identify cursor pointers

18 May 2017, 17:51

This might be useful, I haven't tested it myself yet though. An old script, so it might be worth testing it with AHK x32, if you use AHK x64 and it doesn't work.

Compare current cursor to saved image - Scripts and Functions - AutoHotkey Community
https://autohotkey.com/board/topic/7368 ... ved-image/

Btw do mention what you might like to use it for, in case there may be any other methods, like getting text from the status bar.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: identify cursor pointers

18 May 2017, 19:22

On that link, there is a post at the bottom which works in both AHK x32 and AHK x64.

I've created a modified version of it, what it does is this:
- If you press q it grabs the current cursor as an hBitmap, and if it's a cursor it hasn't seen before, it saves it to a file on Desktop.
- If you press w it grabs the current cursor as an hBitmap, it messages you to say which cursor it matches or that it didn't match a cursor.

So what I would do is this:
- Move your cursor around in Excel and generate lot of cursor image files.
- Create a script that creates hBitmaps from those 'haystack' images when it starts up.
- When you run your hotkey, create an hBitmap for the current cursor and compare that 'needle' hBitmap against the 'haystack' hBitmaps to find a match.

Hope that helps. I'd been meaning to investigate this precise issue, so thanks for reminding me. Cheers to glucos and chaidy for the code.

[EDIT:] You could use the Gdip library to save/load the images as other filetypes such as a png, to save space. Also, you could potentially store the image data inside a script as hex for example or base64.

Btw it's kind of cool having all the Excel cursors (and MS Paint Windows XP version and the Internet Explorer hand icon) as image files now. Another possibility is you may be able to get hBitmaps direct from an Excel exe or dll file.

[EDIT:] I use Excel 2007, and the cursors were in the main exe file, I was able to check it using Resource Hacker.
C:\Program Files (x86)\Microsoft Office\Office12\EXCEL.EXE
The same was true for MS Paint Windows XP version, the main exe file (mspaint.exe).

Code: Select all

#SingleInstance Force
vNow := A_Now
^\::ExitApp

;capturing current mouse cursor and save to "testCursor.bmp"
;F11::
q::
	Loop, % vIndex
	{
		vPath = %A_Desktop%\z cursor %vNow% %A_Index%.bmp
		if (vIsMatch := IsMatchCursor(vPath))
			return
	}
	if !vIsMatch
	{
		vIndex++
		vPath = %A_Desktop%\z cursor %vNow% %vIndex%.bmp
		CaptureCursor(vPath)
	}
return

;compare to testCursor.bmp and current mouse cursor
;F12::
w::
	Loop, % vIndex
	{
		vPath = %A_Desktop%\z cursor %vNow% %A_Index%.bmp
		if (vIsMatch := IsMatchCursor(vPath))
		{
			MsgBox, % "is match: " A_Index
			break
		}
	}
	if !vIsMatch
		MsgBox, % "no match"
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;

*/
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
javierdals
Posts: 3
Joined: 18 May 2017, 15:35

Re: identify cursor pointers

18 May 2017, 19:54

Thanks, jeeswg, I like second option. I´ll try it
fiendhunter
Posts: 140
Joined: 24 Jul 2019, 15:27

Re: identify cursor pointers

15 Feb 2021, 05:01

Spoiler
I m trying to use compare methot with hbitmap. but I coundnt get it right. where did I wrong? Can you help me? I had the cursor info as .bmp file, but I cannot compare with the current cursor.

Code: Select all

F5::
HT3_Cursor_Mode3 := LoadPicture("C:\files\T3_Cursor_Mode3.bmp")
		if (vIsMatch := IsMatchCursor(%HT3_Cursor_Mode3%))
		{
			MsgBox, % "is match: " 
			
		}
	if !vIsMatch
		MsgBox, % "no match"
		
GetOwnModuleHandle()
{
	static h := DllCall("GetModuleHandle", "ptr", 0, "ptr")
	return h
}

LoadBitmapResource(resName, shared := true)
{
	resNameType := "str"
	if resName is integer
		if resName between 0 and 0xFFFF
			resNameType := "ptr"
	if not ret := DllCall("LoadImage", "ptr", GetOwnModuleHandle(), resNameType, resName, "uint", 0, "int", 0, "int", 0, "uint", shared ? 0x8000 : 0, "ptr")
		throw Exception("Could not load bitmap!", -1, "resName: " resName " - ErrLvl: " ErrorLevel " - LastErr: " A_LastError)
	return ret
}

SetBitmap(hPicCtrl, hBitmap, guiName := "")
{
	prefix := guiName ? guiName ":" : ""
	GuiControlGet, temp, %prefix%Pos, %hPicCtrl%
	SendMessage, 0x172, 0, hBitmap,, ahk_id %hPicCtrl% ; 0x172=STM_SETIMAGE, 0=IMAGE_BITMAP
	GuiControl, %prefix%Move, %hPicCtrl%, w%tempW% h%tempH% ; Make sure the bitmap is resized to fit the control
	return
}	
		
return

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Bing [Bot], Google [Bot], Rohwedder and 110 guests