I noticed this in my game when I took the Custom Cursors example and implemented it, in general everything worked fine. But when I opened a view with progress-bars, which require Click and Drag action, and in this case custom cursor(on-top castleUserInterface) is staying on the same spot, but real (system, even invisible) cursor is moving (for example it could hover other controls)
I opened the example itself, I observed the same behavior, I tried to comment inherited+exit lines in Motion event, nothing has changed.
So I assume in this case this on-top element is not receiving event at all, bc it was somehow (pre)“captured” by other control when clicked, and this is in engine code somewhere.
So the question is, could we from user code make overrides to control capture and make this custom cursor receive event with priority. Or maybe some code in engine could be adjusted, maybe Pressed state of mouseButtons is not tracked when event is passed thru hierarchy.
Thanks !
P.S. one more small issue with cursors (maybe MSWindows only) - when Cursor is set to mcForceNone (for showing only custom one), then window borders(and also window buttons to close/maximize/minimize/ and caption areas) obviously not showing any cursor, even a bit further then actual window border (with approx 5-10 pixel gap on other window), maybe there is a way to track non-rendering area of window and return the system cursor ?
Seems that I found a solution for main issue (with non-moving cursor):
procedure TCustomCursor.InternalSetContainer(const Value: TCastleContainer);
begin
inherited;
if Value <> nil then
begin
// show cursor at proper place before even it is moved
UpdateCursorPosition(Value.MousePosition);
Container.ForceCaptureInput := Self; // this line added
end;
end;
The question is, is it enough ? Should be also VisibleChange also be adjusted (in case custom cursor is hidden and system is restored) ?
procedure TCustomCursor.UpdateCursorPosition(const V: TVector2);
begin
FCursorUi.Anchor(hpLeft, V.X / UIScale);
FCursorUi.Anchor(vpBottom, V.Y / UIScale);
// lines added
if not Assigned(Container) or not Assigned(Container.FrontView) then Exit;
if (V.X < 2) or (V.Y < 2) or (V.X > Container.PixelsWidth - 2) or (V.Y > Container.PixelsHeight - 2) then
Container.FrontView.Cursor := mcDefault
else
Container.FrontView.Cursor := mcForceNone;
end;
I didn’t find exactly how Castle intercepts such cases (I lurked mostly around castlewindow_winapi.inc>TCastleWindow.OpenBackend and friends, but winapi is not so clear to me), I just see maybe this block is to be adjusted:
WM_SETCURSOR:
begin
if (WParm = h_Wnd) and
( (InternalCursor in [mcNone, mcForceNone]) or
(Application.CursorHandles[InternalCursor].Handle <> 0) ) then
begin
Windows.SetCursor(Application.CursorHandles[InternalCursor].Handle);
Exit(1);
end;
{ Otherwise we fall back on DefWindowProcW.
It will install our window class cursor (or parent cursor)
if in client area, or just do the right thing if outside client area.
So it's suitable when wParm <> h_Wnd,
or we want mcDefault. }
end;