Windows cursor size bigger than maximum available

2.2k views Asked by At

I'm working with an application where one of the options which I have to develop is to change Windows 10 cursor size. In my case it its important to change cursor size for the whole windows, not only for a specific java application window. Currently I'm able to change size of specific cursor type by modifying Windows registry attributes under HKEY_CURRENT_USER → Control Panel → Cursors directory.

Unfortunately, I need to set cursor size bigger than 32x32px. Somewhere I've found a solution where there was a possibility to cover existing mouse cursor by a bitmap and just follow the position of a cursor, but I don't know how to start with the implementation. I searched on the Internet and I've found some applications that allow user to modify size of cursor for whole Windows 10—for example, this was CursorFX.

Do you know how to increase cursor size programmatically?

1

There are 1 answers

0
Cody Gray - on strike On

You can set any size cursor you want using the SetSystemCursor API. You are not limited to the SM_CXCURSOR/SM_CYCURSOR metrics (cf. GetSystemMetrics function)—those just tell you the system's default cursor size, which is typically 32×32 (or 48×48 on high-DPI systems). I know for a fact that this works as far back as Windows XP; I'm pretty sure it works further back than that.

The key lies in how you load the cursor resource. As you probably already know, you need an HCURSOR object to pass to SetSystemCursor. This is a handle-to-cursor, in Windows API speak. The obvious way to load a cursor is by calling the LoadCursor API function, but that is a very old function, introduced with 16-bit Windows and it is limited to loading cursors of size SM_CXCURSOR×SM_CYCURSOR. So you don't want that; you want to call LoadImage, which as the documentation indicates is the modern replacement function. It takes an enumerated integer parameter indicating which type of image to load: IMAGE_BITMAP (0), IMAGE_ICON (1), IMAGE_CURSOR (2), or IMAGE_ENHMETAFILE (3). Obviously, IMAGE_CURSOR is what you want to use here.

You can either load from a cursor resource embedded into your application's binary (as a Win32 resource), or you can load from a *.CUR/*.ANI file from the disk. To do the latter, pass the LR_LOADFROMFILE flag to the LoadImage function.

I don't know Java, so I can't translate this to Java with whatever syntax is required there to make native Windows API calls, but here is the code in C:

 // Load from a CUR file, at C:\LargeCursor.cur, with a size of 64x64 pixels
HCURSOR hCursor = (HCURSOR)LoadImage(NULL,
                                     "C:\\LargeCursor.cur"),
                                     IMAGE_CURSOR,
                                     64, 64,
                                     LR_DEFAULTCOLOR | LR_LOADFROMFILE);
assert(hCursor != NULL);  // verify that load was successful
BOOL result = SetSystemCursor(hCursor, OCR_NORMAL);
assert(result != FALSE);  // verify that the change was successful
// Load from an embedded resource, IDC_CURSOR, with a size of 64x64 pixels
HCURSOR hCursor = (HCURSOR)LoadImage(GetModuleHandle(NULL),
                                     IDC_CURSOR),
                                     IMAGE_CURSOR,
                                     64, 64,
                                     LR_DEFAULTCOLOR);
assert(hCursor != NULL);  // verify that load was successful
BOOL result = SetSystemCursor(hCursor, OCR_NORMAL);
assert(result != FALSE);  // verify that the change was successful

Note that the SetSystemCursor requires one of the OCR_* constants to identify which system cursor type to change. These aren't included by default when you include Windows.h; you have to define OEMRESOURCE before including Windows.h. I'm assuming, though, that with Java, you're just defining the constants yourself as enumerated values. In that case, they're all available in the MSDN documentation for SetSystemCursor. For example, OCR_NORMAL is 32512.

Notice, though, that what we're doing here is loading a new cursor (i.e., image) of the desired size, and then setting that. That works fine. What you can't easily do is just expand the size of the existing cursor glyph. To do that, you'd have to retrieve the current cursor glyph, draw it onto a bitmap, scale that bitmap to the desired size, convert that bitmap to an HCURSOR, and then set that HCURSOR using SetSystemCursor. And, naturally, the problem with that is Windows cursor glyphs are just bitmaps, so they're not infinitely scalable. You will start losing resolution quickly, so this is not recommended. If you need a large-size cursor, you will need to provide your own image.

By "CursorFX", I believe you're thinking of AniFX (by the same fellow, Attila Kovrig, who wrote IcoFX). This is a cursor image editor and would be a great way to create the *.CUR/*.ANI file(s) you need. But you could just as easily use some other piece of software designed for creating cursors; there are myriad to choose from.

__
Not that you wanted that function with SetSystemCursor anyway, since SetSystemCursor destroys the specified cursor by calling DestroyCursor. You would need to do LoadCursor and then CopyCursor before calling SetSystemCursor. This is all spelled out in the documentation for SetSystemCursor, but as I said, you don't need to worry about this anymore because you just use LoadImage (without the LR_SHARED flag).