|
| 1 | +# Background |
| 2 | + |
| 3 | +When an app is using composition hosting to host WebView, the current cursor |
| 4 | +image cannot be determined easily by the hosting application. For example, if |
| 5 | +the cursor over the WebView is also over a textbox inside of the WebView, the |
| 6 | +cursor should usually be IDC_IBEAM. And by default, the cursor is IDC_ARROW. |
| 7 | +Currently, the `ICoreWebView2CompositionController.Cursor` property returns what |
| 8 | +the cursor should be as an HCURSOR object, which the hosting application can |
| 9 | +then use the to change the current cursor to the correct image. |
| 10 | + |
| 11 | +However, Office already has a well established way of using cursors internally |
| 12 | +by using IDC_* values and there is no easy way to convert the HCURSOR object we |
| 13 | +are returning into an IDC value after it's been created. |
| 14 | + |
| 15 | +This new API is to enable hosting applications like Office to get the current |
| 16 | +IDC value of the cursor instead of the HCURSOR as an option. |
| 17 | + |
| 18 | +Note that this is a COM and .NET spec as WinRT uses a separate enum structure to |
| 19 | +identify cursor IDs. |
| 20 | + |
| 21 | + |
| 22 | +# Description |
| 23 | + |
| 24 | +The `SystemCursorId` property will return the current system cursor ID reported |
| 25 | +by the underlying rendering engine for WebView2. It is not meant to return a |
| 26 | +value for any custom cursors, such as those defined by CSS. |
| 27 | + |
| 28 | +It can be used at any time but will only change after a `CursorChanged` event. |
| 29 | + |
| 30 | +Note that developers should generally use the `Cursor` property to support cases |
| 31 | +where there may be custom cursors. |
| 32 | + |
| 33 | + |
| 34 | +# Examples |
| 35 | + |
| 36 | +```cpp |
| 37 | +// Handler for WM_SETCURSOR window message. |
| 38 | +bool OnSetCursor() |
| 39 | +{ |
| 40 | + POINT point; |
| 41 | + if (m_compositionController && GetCursorPos(&point)) |
| 42 | + { |
| 43 | + // Calculate if the point lies in the WebView visual for composition hosting |
| 44 | + // as it may not cover the whole HWND it's under. |
| 45 | + if (PtInRect(&m_webViewBounds, point)) |
| 46 | + { |
| 47 | + HCURSOR cursor; |
| 48 | + UINT32 cursorId; |
| 49 | + wil::com_ptr<ICoreWebView2CompositionController2> compositionController2 = |
| 50 | + m_compositionController.query<ICoreWebView2CompositionController2>(); |
| 51 | + CHECK_FAILURE(compositionController2->get_SystemCursorId(&cursorId)); |
| 52 | + cursor = ::LoadCursor(nullptr, MAKEINTRESOURCE(cursorId)); |
| 53 | + |
| 54 | + if (cursor) |
| 55 | + { |
| 56 | + ::SetCursor(cursor); |
| 57 | + return true; |
| 58 | + } |
| 59 | + } |
| 60 | + } |
| 61 | + return false; |
| 62 | +} |
| 63 | + |
| 64 | +CHECK_FAILURE(m_compositionController->add_CursorChanged( |
| 65 | + Callback<ICoreWebView2CursorChangedEventHandler>( |
| 66 | + [this](ICoreWebView2CompositionController* sender, IUnknown* args) |
| 67 | + -> HRESULT { |
| 68 | + // No need to do hit testing here as the WM_SETCURSOR handler will have |
| 69 | + // to calculate if the point is within the WebView anyways. |
| 70 | + SendMessage(m_appWindow->GetMainWindow(), WM_SETCURSOR, |
| 71 | + (WPARAM)m_appWindow->GetMainWindow(), MAKELPARAM(HTCLIENT, WM_MOUSEMOVE)); |
| 72 | + return S_OK; |
| 73 | + }) |
| 74 | + .Get(), |
| 75 | + &m_cursorChangedToken)); |
| 76 | + |
| 77 | + |
| 78 | +# API Notes |
| 79 | + |
| 80 | +See [API Details](#api-details) section below for API reference. |
| 81 | + |
| 82 | + |
| 83 | +# API Details |
| 84 | + |
| 85 | +```cpp |
| 86 | +/// This interface is continuation of the |
| 87 | +/// ICoreWebView2CompositionController interface. |
| 88 | +[uuid(279ae616-b7cb-4946-8da3-dc853645d2ba), object, pointer_default(unique)] |
| 89 | +interface ICoreWebView2CompositionController2 : ICoreWebView2CompositionController { |
| 90 | + /// The current system cursor ID reported by the underlying rendering engine |
| 91 | + /// for WebView. For example, most of the time, when the cursor is over text, |
| 92 | + /// this will return the int value for IDC_IBEAM. The systemCursorId is only |
| 93 | + /// valid if the rendering engine reports a default Windows cursor resource |
| 94 | + /// value. See: |
| 95 | + /// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadcursorw |
| 96 | + /// Otherwise, if custom CSS cursors are being used, this will return 0. |
| 97 | + /// To actually use systemCursorId in LoadCursor or LoadImage, |
| 98 | + /// MAKEINTRESOURCE must be called on it first. |
| 99 | + /// If possible, use the Cursor property rather than the SystemCursorId |
| 100 | + /// property because the Cursor property can express custom CSS cursors. |
| 101 | + /// |
| 102 | + /// \snippet ViewComponent.cpp SystemCursorId |
| 103 | + [propget] HRESULT SystemCursorId([out, retval] UINT32* systemCursorId); |
| 104 | +} |
| 105 | +``` |
| 106 | + |
| 107 | +```c# |
| 108 | +namespace Microsoft.Web.WebView2.Core |
| 109 | +{ |
| 110 | + // |
| 111 | + // Summary: |
| 112 | + // This class is an extension of the CoreWebView2CompositionController class to support composition |
| 113 | + // hosting. |
| 114 | + public class CoreWebView2CompositionController2 |
| 115 | + { |
| 116 | + // |
| 117 | + // Summary: |
| 118 | + // The current system cursor ID that WebView thinks it should be. |
| 119 | + // |
| 120 | + // Remarks: |
| 121 | + // The current system cursor ID reported by the underlying rendering engine |
| 122 | + // for WebView. For example, most of the time, when the cursor is over text, |
| 123 | + // this will return the int value for IDC_IBEAM. The SystemCursorId is only |
| 124 | + // valid if the rendering engine reports a default Windows cursor resource |
| 125 | + // value. See: |
| 126 | + // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadcursorw |
| 127 | + // Otherwise, if custom CSS cursors are being used, this will return 0. |
| 128 | + // To create a Cursor object, create an IntPtr from the returned uint to |
| 129 | + // pass into the constructor |
| 130 | + // If possible, use the Cursor property rather than the SystemCursorId |
| 131 | + // property because the Cursor property can express custom CSS cursors. |
| 132 | + public Uint32 SystemCursorId { get; } |
| 133 | + } |
| 134 | +} |
| 135 | +``` |
| 136 | + |
| 137 | +# Appendix |
| 138 | + |
| 139 | +I expect that most apps will use the get_Cursor API which returns an HCURSOR (Or |
| 140 | +the UWP equivalent that will be implemented in the future that will return a |
| 141 | +CoreCursor) outside of Office as HCURSOR is more comprehensive and covers the |
| 142 | +scenarios in which custom cursors are used. |
0 commit comments