Jump to content

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

Changing the mouse cursor


  • Please log in to reply
9 replies to this topic
antonyb
  • Members
  • 61 posts
  • Last active: Mar 07 2006 09:24 AM
  • Joined: 26 May 2004
Hi

Is it possible to change the mouse cursor? Something like

A_Cursor = Cross

(which doesn't work, I know :)

Any other way of doing it?

Thanks,

Ant.

corrupt
  • Members
  • 2558 posts
  • Last active: Nov 01 2014 03:23 PM
  • Joined: 29 Dec 2004
It is possible using DllCall but I would suggest doing a bit of research first:
http://msdn.microsof... ... cursor.asp

Sorry, I realize it's probably not the answer you were looking for... there are likely other methods... If I remember correctly, the registry path: "HKEY_CURRENT_USER\Control Panel\Cursors" should contain the paths to the current cursors in use if non-standard...

antonyb
  • Members
  • 61 posts
  • Last active: Mar 07 2006 09:24 AM
  • Joined: 26 May 2004
Hey corrupt,

Thanks for the info! Actually, its a great answer - I've been looking for an excuse to get into playing with DllCall for a while!

Will report back if I have any success,

Ant.

antonyb
  • Members
  • 61 posts
  • Last active: Mar 07 2006 09:24 AM
  • Joined: 26 May 2004
Ok, getting stuck already! This is how far I've got so far:

To discover what the (global) cursor currently is I can use:
VarSetCapacity(CurrentCursorStruct, 20, 0)
InsertInteger(20, CurrentCursorStruct, 0)
result := DllCall("GetCursorInfo", "str", CurrentCursorStruct)
hcursor := ExtractInteger(CurrentCursorStruct, 8)
Binding this to a key, I get different results for hcursor depending on the state of the cursor; this was my "calibration" test to check that I was using DllCall and structs ok. The info for the struct came from http://msdn.microsof....asp?frame=true.

So far so good. Googling then told me that in order to change a cursor over a window, I need to replace its class cursor. The pseudo code for this is something like:
hCursor = LoadCursor(NULL, IDC_CROSS);
hPrevCursor = SetCursor(hCursor);
SetClassLong(GetWindowHandle(MyWindow), GCL_HCURSOR, hCursor)
I've attempted to get this to work (changing the cursor to a Crosshair) as follows:
CursorTest:
  NULL=
  GCL_HCURSOR=-12
  IDC_CROSS=65571

  result1 := DllCall("LoadCursor", "Uint", NULL, "Str", IDC_CROSS)
  error1 = %ErrorLevel%
  result2 := DllCall("SetCursor", "Uint", result1)
  error2 = %ErrorLevel%
  result3 := DllCall("SetClassLong", "Uint", timer_id, "Int", GCL_HCURSOR, "Uint", result1)
  error3 = %ErrorLevel%

  ToolTip, %result1%`t%result2%`t%result3%`n%error1%`t%error2%`t%error3%
 
  return

The GCL_HCURSOR value I found by googling; the IDC_CROSS value is MAKEINTRESOURCE(32515) - my value could easily be wrong for this :)

The tooltip tells me that the first call is failing; no error, but no pointer to a cursor resource either.

Any ideas? I'll keep playing around anyway. Thanks,

Ant

corrupt
  • Members
  • 2558 posts
  • Last active: Nov 01 2014 03:23 PM
  • Joined: 29 Dec 2004
Hi Ant,

Any luck yet? I seem to remember that to load the cursor I had had to do something like:
mARROW = CopyCursor(LoadCursor(NULL, IDC_ARROW))


antonyb
  • Members
  • 61 posts
  • Last active: Mar 07 2006 09:24 AM
  • Joined: 26 May 2004
Hey Corrupt,

Nope - no luck :(

I can't seem to get the line
result1 := DllCall("LoadCursor", "Uint", NULL, "Str", IDC_CROSS)
to ever return me a value; result1 is always 0. No error is reported though. According to the MSDN doc, it should return me a handle to the new cursor. I'm wondering if my way of setting NULL is correct.

Any thoughts?

ant.

corrupt
  • Members
  • 2558 posts
  • Last active: Nov 01 2014 03:23 PM
  • Joined: 29 Dec 2004
Ahh, ok, IDC_CROSS is a constant. I currently use APIViewer 2004 to find values to various constants, types, etc... and API Guide for a quick reference with various API calls :) .

According to APIViewer, IDC_CROSS = 32515

The following seems to work ok...
NULL=
IDC_CROSS := 32515
result1 := DllCall("LoadCursor", "UInt", NULL, "Int", IDC_CROSS, "UInt")
MsgBox, %result1%

bbye := DllCall("DestroyCursor", "Uint", result1)
If bbye
  MsgBox, Cursor destroyed
else
  MsgBox, Cursor could not be destroyed


antonyb
  • Members
  • 61 posts
  • Last active: Mar 07 2006 09:24 AM
  • Joined: 26 May 2004
Ok! Now we're getting somewhere! I'm a bit busy with work today (it *always* gets in the way of the important stuff :lol: ), but have just tried this with some success:

WARNING: this will screw up your system cursors - its probably fixable, but I didn't have time this morning, so just rebooted to get them back to normal.
NULL=
  IDC_APPSTARTING := 32650
  IDC_HAND := 32649
  IDC_ARROW := 32512
  IDC_CROSS := 32515
  IDC_IBEAM := 32513
  IDC_ICON := 32641
  IDC_NO := 32648
  IDC_SIZE := 32640
  IDC_SIZEALL := 32646
  IDC_SIZENESW := 32643
  IDC_SIZENS := 32645
  IDC_SIZENWSE := 32642
  IDC_SIZEWE := 32644
  IDC_UPARROW := 32516
  IDC_WAIT := 32514

!0::Gosub, CursorTest

CursorTest:

  ;// Load a cursor. If the 1st arg is NULL, specify one of the Constants above 
  ;// as the second arg to load a system cursor
  result1 := DllCall("LoadCursor", "Uint", NULL, "Int", IDC_CROSS, "Uint")

  ;// Changes a system cursor. 
  result2 := DllCall("SetSystemCursor", "Uint", result1, "Int", IDC_ARROW, "Uint")

  return


This will change the actual cursor rendered by the system; in this case it changes the cursor rendered when the system wants a standard, normal, arrow pointer to be the crosshairs. It only has effect outside of a (non-program manager) window; windows are responsible for setting their own cursors it seems, and this will be harder to alter (maybe not impossible though; although not recommended we can probably use the SetClassLong call to override a Window's class cursor). Another area to look at would be creating a full-screen, invisible window of our own and setting the default cursor on that to be what we want... Will experiment when I have some more time.

Thanks corrupt - can't believe I missed that... The value I had for IDC_CROSS was MAKEINTRESOURCE(32515) which I spent ages figuring out, and never bothered trying 32515 itself... d'oh.

:D

Ant.

BoBo
  • Guests
  • Last active:
  • Joined: --
@ antonyb

this will screw up your system cursors ... so just rebooted to get them back to normal.

I guess "Login as another user" will do it as well !?!

1991
  • Members
  • 29 posts
  • Last active: Jun 04 2007 03:05 AM
  • Joined: 20 Jan 2006
The following should fix the bug where the cross is kept after you close the script.
cursor=0
NULL=
  IDC_APPSTARTING := 32650
  IDC_HAND := 32649
  IDC_ARROW := 32512
  IDC_CROSS := 32515
  IDC_IBEAM := 32513
  IDC_ICON := 32641
  IDC_NO := 32648
  IDC_SIZE := 32640
  IDC_SIZEALL := 32646
  IDC_SIZENESW := 32643
  IDC_SIZENS := 32645
  IDC_SIZENWSE := 32642
  IDC_SIZEWE := 32644
  IDC_UPARROW := 32516
  IDC_WAIT := 32514

OnExit, reset
return

reset:
	if cursor=1
		gosub, change
	exitapp
return

change:
	result1 := DllCall("LoadCursor", "Uint", NULL, "Int", IDC_CROSS, "Uint")
	result2 := DllCall("SetSystemCursor", "Uint", result1, "Int", IDC_ARROW, "Uint")
	if cursor = 0
	{
		cursor=1
	}
	else
	{
		cursor=0
	}
return

!0::
	gosub, change
return