Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Cursor when hovering over View on Desktop #4552

Open
Redth opened this issue Feb 8, 2022 · 16 comments
Open

Custom Cursor when hovering over View on Desktop #4552

Redth opened this issue Feb 8, 2022 · 16 comments
Assignees
Labels
area-controls-general General issues that span multiple controls, or common base classes such as View or Element legacy-area-desktop Windows / WinUI / Project Reunion & Mac Catalyst / macOS specifics (Menus & other Controls)) partner/cat 😻 this is an issue that impacts one of our partners or a customer our advisory team is engaged with proposal/open t/desktop The issue relates to desktop scenarios (MacOS/MacCatalyst/Windows/WinUI/WinAppSDK) t/enhancement ☀️ New feature or request
Milestone

Comments

@Redth
Copy link
Member

Redth commented Feb 8, 2022

On Desktop platforms, when hovering over a view, provide the ability to change the mouse cursor.

Could we provide this via an attached property, or perhaps provide an out of the box behaviour for this?

The API should provide a way to select and set one of the available system cursor types when the mouse/pointer is over a view. This could be an enum of cursor values.

Notes:

@Redth Redth added legacy-area-desktop Windows / WinUI / Project Reunion & Mac Catalyst / macOS specifics (Menus & other Controls)) partner/cat 😻 this is an issue that impacts one of our partners or a customer our advisory team is engaged with labels Feb 8, 2022
@mattleibow
Copy link
Member

We can probably use NSTrackingArea for macOS to avoid affecting the gestures:

https://developer.apple.com/documentation/appkit/nstrackingarea
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/EventOverview/TrackingAreaObjects/TrackingAreaObjects.html#//apple_ref/doc/uid/10000060i-CH8-SW1

@Redth Redth self-assigned this Mar 8, 2022
@Redth Redth added this to the 6.0.300-servicing milestone Apr 18, 2022
@Redth Redth added the t/enhancement ☀️ New feature or request label Aug 2, 2022
@Redth Redth modified the milestones: 6.0-servicing, Backlog Aug 2, 2022
@nCastle1
Copy link

I encourage the MAUI team to think beyond desktop for this. iPadOS also supports customizing cursors, albeit in a more focused way. E.g. https://developer.apple.com/documentation/uikit/uipointershape/roundedrect_radius Android also has a cursor API https://developer.android.com/reference/android/view/PointerIcon

@valimaties
Copy link

I think MAUI must cover all things, desktop and mobiles/tablets environments. I saw a lot of "tutorials" on youtube with MAUI, but most of them are for android environment! Why they (we) have to think of MAUI only to mobile devices as long as it was made for desktop, mobile and now TV OSes?
So, what I want to tell here is MAUI must cover the MouseHover events for desktop environments, Cursor property, and all it needs to be able to cover the desktop application and Mouse events as well.

@gbelicka
Copy link

Assuming for the moment the app developer knows the pointer has entered or exited the area occupied by a specific control, can the mouse cursor actually be changed in Maui? For example, SkiaSharp does provide enough information to know when you want to change the cursor, but how do you actually change the cursor?

@nor0x
Copy link
Contributor

nor0x commented Dec 22, 2022

for Windows i currently use the following Extension method to change the cursor

public static void ChangeCursor(this UIElement uiElement, InputCursor cursor)
{
    Type type = typeof(UIElement);
    type.InvokeMember("ProtectedCursor", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance, null, uiElement, new object[] { cursor });
}

it can be called like this (for example in the EventHandler of a PointerGestureRecognizer)

myUIElement.ChangeCursor(InputSystemCursor.Create(InputSystemCursorShape.Hand));

on macOS it's even easier - i'm using

NSCursor.PointingHandCursor.Set();

@Redth
Copy link
Member Author

Redth commented Jan 16, 2023

Cursors are relatively easy to set on MacCatalyst as well:

AppKit.NSCursor.ResizeDownCursor.Push(); // .Pop() to remove

However the problem is, the selection of cursor types is limited on MacCatalyst compared to AppKit. For example, there is no ResizeNorthWestCursor (or NorthEast, SouthWest, SouthEast - so none of the 'corner' resize cursors).

It's trivial to access these 'unsupported' API's via C# code:

void setCursor(bool push, string cursorType = "_windowResizeNorthEastCursor")
{
  var nsCursor = Runtime.GetNSObject(Class.GetHandle(nameof(NSCursor)));
  var cursor = nsCursor.PerformSelector(new Selector(cursorType));

  cursor.PerformSelector(new Selector(push ? "push" : "pop"));
}

// Unsupported cursors:
//[NSCursor _windowResizeEastCursor]
//[NSCursor _windowResizeWestCursor]
//[NSCursor _windowResizeEastWestCursor]
//[NSCursor _windowResizeNorthCursor]
//[NSCursor _windowResizeSouthCursor]
//[NSCursor _windowResizeNorthSouthCursor]
//[NSCursor _windowResizeNorthEastCursor]
//[NSCursor _windowResizeNorthWestCursor]
//[NSCursor _windowResizeSouthEastCursor]
//[NSCursor _windowResizeSouthWestCursor]
//[NSCursor _windowResizeNorthEastSouthWestCursor]
//[NSCursor _windowResizeNorthWestSouthEastCursor]
//[NSCursor _zoomInCursor]
//[NSCursor _zoomOutCursor]
//[NSCursor _helpCursor]
//[NSCursor _copyDragCursor]
//[NSCursor _genericDragCursor]
//[NSCursor _handCursor]
//[NSCursor _closedHandCursor]
//[NSCursor _moveCursor]
//[NSCursor _waitCursor]
//[NSCursor _crosshairCursor]
//[NSCursor _horizontalResizeCursor]
//[NSCursor _verticalResizeCursor]
//[NSCursor _bottomLeftResizeCursor]
//[NSCursor _topLeftResizeCursor]
//[NSCursor _bottomRightResizeCursor]
//[NSCursor _topRightResizeCursor]
//[NSCursor _resizeLeftCursor]
//[NSCursor _resizeRightCursor]
//[NSCursor _resizeLeftRightCursor]

But this is not something we are currently comfortable adding to the core MAUI product. We have no reason to believe Apple will reject MacCatalyst app store submissions which use API's officially supported on AppKit, but not officially supported on MacCatalyst, and there is reasonable evidence if you search, to suggest many apps are shipping to the store with these types of API usages. But we also don't want to add implicitly agreed to risk to our customers by adding this code to MAUI.

For now, I'd suggest writing a simple service that can handle mouse cursors on each of the platforms you're interested in, and deciding if you want to leverage these unsupported API's on MacCatalyst or not yourself so that you are in control if something changes with Apple's decisions around appstore submissions in this area.

@mobycorp
Copy link

I think MAUI must cover all things, desktop and mobiles/tablets environments. I saw a lot of "tutorials" on youtube with MAUI, but most of them are for android environment! Why they (we) have to think of MAUI only to mobile devices as long as it was made for desktop, mobile and now TV OSes? So, what I want to tell here is MAUI must cover the MouseHover events for desktop environments, Cursor property, and all it needs to be able to cover the desktop application and Mouse events as well.

@jamesmontemagno, @jfversluis, and @davidortinau, I see I'm not the only one who feels that the MAUI team has relegated Desktop to the back burner...

@shv07
Copy link

shv07 commented Feb 20, 2023

for Windows i currently use the following Extension method to change the cursor

public static void ChangeCursor(this UIElement uiElement, InputCursor cursor)
{
    Type type = typeof(UIElement);
    type.InvokeMember("ProtectedCursor", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance, null, uiElement, new object[] { cursor });
}

it can be called like this (for example in the EventHandler of a PointerGestureRecognizer)

myUIElement.ChangeCursor(InputSystemCursor.Create(InputSystemCursorShape.Hand));

on macOS it's even easier - i'm using

NSCursor.PointingHandCursor.Set();

Thanks for this @nor0x !! It was really helpful! (P.S. Mentioning how you convert the MAUI elements to UIElement could have been a plus but figured that out anyways :)

@mobycorp
Copy link

mobycorp commented Feb 21, 2023 via email

@nor0x
Copy link
Contributor

nor0x commented Feb 22, 2023

for Windows i currently use the following Extension method to change the cursor

public static void ChangeCursor(this UIElement uiElement, InputCursor cursor)
{
    Type type = typeof(UIElement);
    type.InvokeMember("ProtectedCursor", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance, null, uiElement, new object[] { cursor });
}

it can be called like this (for example in the EventHandler of a PointerGestureRecognizer)

myUIElement.ChangeCursor(InputSystemCursor.Create(InputSystemCursorShape.Hand));

on macOS it's even easier - i'm using
NSCursor.PointingHandCursor.Set();

Thanks for this @nor0x !! It was really helpful! (P.S. Mentioning how you convert the MAUI elements to UIElement could have been a plus but figured that out anyways :)

about getting the UIElement - it could be done as simple as that for Windows and macOS

    void PointerEntered(object sender, Microsoft.Maui.Controls.PointerEventArgs e)
    {
        if (sender is Label label)
        {
#if WINDOWS
        if (label.Handler.PlatformView is Microsoft.UI.Xaml.Controls.TextBlock textBlock)
        {
            textBlock.ChangeCursor(InputSystemCursor.Create(InputSystemCursorShape.Hand));
        }
#endif

#if MACCATALYST
            NSCursor.PointingHandCursor.Set();
#endif
        }
    }

@mouralabank
Copy link

I agree with that, providing the ability to change the mouse cursor when hovering over a view can be a useful feature for desktop apps, as it can help to provide visual feedback to users and guide their interactions with the application.

@MartyIX
Copy link
Contributor

MartyIX commented May 24, 2023

@orosbogdan
Copy link

orosbogdan commented Feb 7, 2024

This is still reproducible on blazor hybrid (maui) with .net 8, "cursor:pointer" css is not taking any effect.

@Eilon
Copy link
Member

Eilon commented Mar 7, 2024

@orosbogdan said:

This is still reproducible on blazor hybrid (maui) with .net 8, "cursor:hand" css is not taking any effect.

For CSS it's up to each platform's native webview whether it supports certain CSS properties. I couldn't find any cursor: hand support on any platform. And it seems that in WebView2 some CSS cursors work, but not all: MicrosoftEdge/WebView2Feedback#2766

From my test just now with WebView2:

  • N/A: auto/default - not very meaningful to test
  • Working: pointer, wait, text, n-resize, e-resize, s-resize, w-resize, ns-resize, ew-resize, ne-resize, nw-resize, se-resize, sw-resize, nesw-resize, nwse-resize
  • Not working: none, context-menu, help, progress, cell, crosshair, vertical-text, alias, copy, move, no-drop, not-allowed, all-scroll, col-resize, row-resize

Interestingly, many of these seem to work fine in Edge itself, but not in Edge WebView2. Not sure why that is. But there's this WebView2 bug filed to track that: MicrosoftEdge/WebView2Feedback#2766. I added some additional info there about my testing and the current status.

So as far as WebView/BlazorWebView is concerned, this issue is up to each platform's own native WebView, and I don't think any further action is requried within .NET MAUI.

But this bug should remain open to track support for native UI (as opposed to web UI).

@mhrastegari
Copy link

This is still reproducible on blazor hybrid (maui) with .net 8, "cursor:hand" css is not taking any effect.

I think by hand you mean cursor: pointer; or cursor: grab;!

@orosbogdan
Copy link

This is still reproducible on blazor hybrid (maui) with .net 8, "cursor:hand" css is not taking any effect.

I think by hand you mean cursor: pointer; or cursor: grab;!

Right, my bad, I meant cursor:pointer.

@Eilon Eilon added the t/desktop The issue relates to desktop scenarios (MacOS/MacCatalyst/Windows/WinUI/WinAppSDK) label May 10, 2024
@PureWeen PureWeen added the area-controls-general General issues that span multiple controls, or common base classes such as View or Element label Jun 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-controls-general General issues that span multiple controls, or common base classes such as View or Element legacy-area-desktop Windows / WinUI / Project Reunion & Mac Catalyst / macOS specifics (Menus & other Controls)) partner/cat 😻 this is an issue that impacts one of our partners or a customer our advisory team is engaged with proposal/open t/desktop The issue relates to desktop scenarios (MacOS/MacCatalyst/Windows/WinUI/WinAppSDK) t/enhancement ☀️ New feature or request
Projects
No open projects
Status: Todo
Development

No branches or pull requests