7

is there a way how to determine if the current mouse cursor is animated ?

I was looking for a way how to save the current cursor some time ago. I found the DrawIconEx function which perfectly suits to my purpose. Unfortunately I don't know how do I determine if the current cursor is animated. I was hoping that if I set the istepIfAniCur parameter to 1 in case of static cursor DrawIconEx returns False but it really ignores that parameter and returns True what disallows me to use it in the loop for getting the static cursor as well as all the frames from the animated one. In case of animated one works as expected so when you get out of range with istepIfAniCur it returns False.

So how do I find out that HICON (HCURSOR) is the animated cursor ? How the DrawIconEx determine that the cursor is animated ?

Thanks a lot

Community
  • 1
  • 1
  • It sounds like you are writing remote desktop software. If so shouldn't you use the cursors of the local machine? – David Heffernan Aug 07 '11 at 08:03
  • @David - yeah, something similar. But my last two questions arised mainly because of my curiosity. Of course I have to display the cursor set which is on the viewer side, I can't let the user grope _what the hell is the jumping rabbit cursor on his side_. I've only get stucked on this primitive thing and wonder how the [DrawIconEx](http://tinyurl.com/DrawIconEx) recognize that you're passing it the animated cursor handle, there's no practical usage of it in my case. –  Aug 07 '11 at 08:34
  • @David - now when I'm thinking about it; what about the case of custom cursor ? In that case would be nice to let the viewer see for instance brush if the user on the other side is drawing. In case of OEM cursors I will use the viewer's set of course. –  Aug 07 '11 at 10:00
  • 1
    Perhaps you can use `GetIconInfo` to retrieve the dimensions of the bitmap associated with the cursor (using `GetObject`) and get `numFrames = width_of_bitmap / `height_of_bitmap` assuming all cursors are square. – user786653 Aug 07 '11 at 11:51
  • @user786653 - I've tried that but it always returns me the width of one frame. See the temporary answer with Delphi example below. –  Aug 07 '11 at 14:24

3 Answers3

7

I've found one workaround - pass to the istepIfAniCur parameter of the DrawIconEx function max value of UINT. It's impossible that someone would create animated cursor with 4,294,967,295 frames (possible maybe for some cursor movie :)

With this fact you can pass this value to the DrawIconEx function which will return False in case when the cursor is animated (because of exceeding the frame range) and True in case of static one, because it ignores the istepIfAniCur parameter. You should pass 0 to the diFlags parameter because there's no need to draw anything.

Here's the Delphi example:

if not DrawIconEx(Canvas.Handle, 0, 0, hCursor, 0, 0, High(Cardinal), 0, 0) then
  Caption := 'Cursor is animated ...'
else
  Caption := 'Cursor is not animated ...';

And because I promised C++ tag here's my translation attempt

if (!DrawIconEx(this->Canvas->Handle, 0, 0, hCursor, 0, 0, UINT_MAX, NULL, 0))
  this->Caption = "Cursor is animated ...";
else
  this->Caption = "Cursor is not animated ...";


Exceeding the frame range is also indicated by the OS error ERROR_INVALID_PARAMETER what you may inspect using GetLastError function when the DrawIconEx fails.

Cyril Gandon
  • 16,830
  • 14
  • 78
  • 122
3

Best way:

typedef HCURSOR(WINAPI* GET_CURSOR_FRAME_INFO)(HCURSOR, LPCWSTR, DWORD, DWORD*, DWORD*);
GET_CURSOR_FRAME_INFO fnGetCursorFrameInfo = 0;

HMODULE libUser32 = LoadLibraryA("user32.dll");
if (!libUser32)
{
  return false;
}

fnGetCursorFrameInfo = reinterpret_cast<GET_CURSOR_FRAME_INFO>(GetProcAddress(libUser32, "GetCursorFrameInfo"));
if (!fnGetCursorFrameInfo)
{
  return false;
}

DWORD displayRate, totalFrames;
fnGetCursorFrameInfo(hcursor, L"", 0, &displayRate, &totalFrames);
user3840170
  • 26,597
  • 4
  • 30
  • 62
  • Is this the whole code? Something feels missing at the end – Aleks G Mar 02 '17 at 22:14
  • As far as I can tell, GetCursorFrameInfo is an undocumented API, but I believe it should give you the information you the display rate and total number of frames. If the cursor is static, I'd expect the total number of frames to be 1 (or maybe 0). If it's animation, it should tell you how many frames are in a cycle of the animation. – Adrian McCarthy Mar 02 '17 at 23:03
0

Here's the example in Delphi (and attempt to translation to C++) how I was trying to get the cursor dimensions using GetIconInfo function, but it doesn't work as I've expected. It always returns the width of one frame in case of animated cursor so it seems that GetIconInfo doesn't take care of the frames at all. Or am I wrong ?

procedure TForm1.Timer1Timer(Sender: TObject);
var
  IconInfo: TIconInfo;
  CursorInfo: TCursorInfo;
  Bitmap: Windows.TBitmap;
begin
  CursorInfo.cbSize := SizeOf(CursorInfo);
  GetCursorInfo(CursorInfo);
  GetIconInfo(CursorInfo.hCursor, IconInfo);

  if GetObject(IconInfo.hbmColor, SizeOf(Bitmap), @Bitmap) <> 0 then
  begin
    Caption := 'Cursor size: ' +
               IntToStr(Bitmap.bmWidth) + ' x ' +
               IntToStr(Bitmap.bmHeight) + ' px';
  end;

  DeleteObject(IconInfo.hbmColor);
  DeleteObject(IconInfo.hbmMask);
end;

My Visual C++ attempt (note that I don't know C++ and have no compiler :)

CString txt;
ICONINFO ii;
CURSORINFO ci;
BITMAP bitmap;

ci.cbSize = SizeOf(CURSORINFO);
GetCursorInfo(ci);
GetIconInfo(ci.hCursor, ii);
GetObject(ii.hbmColor, sizeof(BITMAP), &bitmap);
txt.Format("Cursor width: %d px", bitmap.bmWidth);
MessageBox(txt);
Cyril Gandon
  • 16,830
  • 14
  • 78
  • 122
  • How about the `bmWidthBytes` member of `Bitmap`? It might have the "real" width. – user786653 Aug 08 '11 at 11:15
  • That returns me 128, but I think that's not what we need: `The number of bytes in each scan line. This value must be divisible by 2, because the system assumes that the bit values of a bitmap form an array that is word aligned.` so I would say that this might work in case we know B/px what is I presume another function call. –  Aug 08 '11 at 11:30
  • Assuming your cursor is 32-bit and 32x32 then that's no good either. It was just a shot in the dark hoping that it would return the combined width of the animated cursor frames. – user786653 Aug 08 '11 at 11:43
  • @user786653 - I was hoping in the same. Such easy thing and such complicated to do. If MS don't ignore the istepIfAniCur parameter then we would be able to paint static cursor or all frames of animated in one loop. –  Aug 08 '11 at 12:21
  • A 32x32px, 1 bit per pixel image will use 128 bytes. – Nicke Manarin Jan 02 '22 at 18:11