A customer wanted to know how to find out the size of the mouse cursor. They called GetÂSystemÂMetrics(
, but the value that was returned didn’t seem to be right.
The SM_
system metric gives you the size of “standard” icons, which is loosely correlated with the size of the mouse cursor, in the sense that people who choose bigger icons tend also to choose bigger mouse cursors. This is, however, just a correlation; there is no requirement that the two values be aligned with each other in any way.
We learned last time that the SM_
tells you the size the mouse cursor would have been in some hypothetical universe, which doesn’t really help you find out what the size of the cursor is in the current universe based in reality.
In order to answer the question “What is the size of the mouse cursor?” you first have to specify which mouse cursor you are interested in, in the form of an HCURSOR
. For example, if you are interested in the size of the arrow cursor, you can call LoadCursor(nullptr, IDC_ARROW)
.¹
Once you have your HCURSOR
, you can call GetÂIconÂInfo
² to obtain information about it. The bitmaps that are used to draw the cursor are available as the hbmMask
and hbmCursor
. Interpreting these bitmaps is a bit tricky.
For color cursors, the hbmMask
and hbmColor
bitmaps are the same size, each of which is the size of the cursor.
For monochrome cursors, the hbmMask
is twice the height of the cursor (with the AND mask on top and the XOR mask on the bottom), and there is no hbmColor
.
Now, the sizes of the bitmap tell you the nominal size of the mouse cursor, but that’s not the same as the apparent size. For example, the bitmaps for the I-beam cursor may be 32 × 32, but on the screen, the I-beam cursor is tall and skinny. To identify the pixels that will be drawn, you need to study the mask (color cursors) or top half of the mask (monochrome cursors) and look for the black pixels.
You can also use the xHotspot
and yHotspot
members to tell you how the bitmap is positioned relative to the cursor position.
Don’t forget to delete the hbmMask
and hbmColor
bitmaps when you’re done. Forgetting to clean up these bitmaps is a common source of GDI resource leaks.
¹ If you aren’t interested in any particular cursor, but rather want to know how big the cursors are “in general”, you could make the assumption that the current set of default cursors consists of cursors that are all roughly the same size, and just measure the arrow cursor. This is not too unreasonable an assumption, because users generally prefer consistency among their cursors, and they are unlikely to choose a set of cursors where, say, the arrow cursor is ten times bigger than the I-beam cursor.
² Even though the name of the function says that it gets icon info, the documentation notes that it also works for cursors.
When a cursor is loaded with LR_DEFAULTSIZE the cursor can dynamically switch resolution when moved from a lo-dpi to hi-dpi monitor. (eg: create a cursor with multiple resolutions (eg 32x32 and 64x64) with different markings on each resolution and move it between hi and lo dpi monitors and you'll see the cursor change).
How does that work? And how does it fit in to this topic of working out the icon size? (since GetIconInfo returns...
I wanted to turn the default I-beam cursor back into a .CUR file to be sure that it was the transparency that was somehow confusing Remote Desktop rather than anything else (see my comment on the previous post but one). It turned out to be harder than I anticipated; I ended up hardcoding most of the file, and just copying the bitmap bits from the monochrome bitmap returned from , although upside-down of course. Strictly...
"² Even though the name of the function says that it gets icon info, the documentation notes that it also works for cursors."
Fun Fact of the Day: IIRC this is because icons and cursors* are pretty much exactly the same internally, except cursors have a hotspot (the precise pixel where actual mouse interactions happen) and icons don't. I think the file formats might even be the same. It's been a while though.
* - Static CUR...
The on-disk formats are the same size but not the same, cursors don’t support planes nor fast BPP lookups because that is where the hotspot is stored. The resource formats have more differences and cursors can in theory be larger than 256×256 pixels.
In the beginning (up to Windows 3.11), cursors were limited to 32x32 pixels and 1 bit per pixel (plus anther one for transparency), just the same as a monochrome icon. At that time, the only difference between a monochrome icon and a cursor was the hotspot. Otherwise, the file formats were exactly the same. I remember being able to use a standard icon editor for creating custom cursors back in the day. Of course, the...
Actually monochrome cursors support 4 values, black, white, transparent and inverse. Windows 95-2000 also supported colour XOR masks, although normally cursor editors only allowed black and white (which map to transparent and inverse). You could use colour XOR masks to create interesting effects, of which my favourite was an XOR mask of grey (0x808080) to create a semi-inverse effect which worked on any background (the default inverse effect doesn't work very well on a grey...
> Actually monochrome cursors support 4 values
Black, white, transparent and inverse. Four values. Two bits per pixel in two planes, equivalent to two monochrome (1 bpp) bitmaps. Just what I said. What I called the “image” is, technically, the XOR mask, and what I called the “transparency”, is the AND mask.
NOTE : This doesn’t work if you resize the mouse cursor by using “Change mouse pointer size” in Settings. The bitmap size of the cursor will still be 32.