How do you set hotspot co-ordinates on a Windows cursor generated from an icon file?
Asked Answered
I

3

3

I'm setting a custom cursor on my app from an icon file, but the click point is at the wrong co-ordinates. I'm setting the cursor with

SetClassLongPtr(hwnd, GCL_HCURSOR, reinterpret_cast<LONG_PTR>cursor)

where cursor is the result of;

LoadImage(
    NULL,
    "some_path/cursor.ico", 
    IMAGE_ICON, //also tried IMAGE_CURSOR
    0, //width. 0 uses the width of the file provided
    0, //height. 0 uses the height of the file provided
    LR_LOADFROMFILE
); 

The cursor loads fine, but its clicks come from the bottom-left corner of the cursor image, rather than top left.

The wikipedia article on .ico files says the hotspots are only specified on .cur files, not .ico.

Edit: Clarified question


ref: LoadImage() and SetClassLongPtr() on msdn.

Intumescence answered 25/1, 2010 at 14:54 Comment(1)
Creating a .cur file from the .ico (or rather, the same bitmap the .ico was created from) and loading that fixes the problem. I would prefer not to have to fire up another application to do the conversion though. The ico file works as a cursor, just with the wrong co-ordinates. Surely there's a way to fix that.Intumescence
T
5

You can do this with CreateIconFromResourceEx

You pass in a pointer to a CURSOR_RES_HDR as the first parameter. This is one of those structures that you can find buried in the documentation, but it isn't any header file I can find. It's pretty simple though, basically to 16 bit unsigned ints followed by a BITMAPINFOHEADER containing the cursor image data.

typedef struct {
   WORD             xHot;         // x hotspot
   WORD             yHot;         // y hotspot
   BITMAPINFOHEADER bih;
   } CURSOR_RES_HDR;

...

CURSOR_RES_HDR * pImage;

// Fill out pImage

HCURSOR hcur = CreateIconFromREsourceEx((BYTE*)pImage, 
                  cbImage, // size of image data + hotspot (in bytes)
                  FALSE,
                  0x00030000, // version: value mandated by windows
                  0, 0,       // width & height, 0 means use default
                  LR_DEFAULTSIZE | LR_DEFAULTCOLOR);
Tulle answered 25/1, 2010 at 21:57 Comment(0)
P
2

Use this excellent cursor editor for creating cursors and you can set the hotspot, make it animated, etc. I found it quite nifty and neat.

Hope this helps, Best regards, Tom.

Persevere answered 25/1, 2010 at 15:54 Comment(0)
M
2

Yes, the hotspot is determined by the content of the .cur file. The Wikipedia article shows you this, offsets 4 and 6. Windows doesn't have an API to change the hotspot after the cursor is loaded. Simply edit the cursor in Visual Studio or any other cursor editor, specify the hot spot and save the file as a .cur file.

Monaural answered 25/1, 2010 at 15:55 Comment(1)
That's only the case for .cur files. LoadImage() allows cursors generated from bitmaps and icons. How do you specify hotspot then?Intumescence

© 2022 - 2024 — McMap. All rights reserved.