|
| 1 | +Hit Test Kind |
| 2 | +=== |
| 3 | + |
| 4 | +# Background |
| 5 | +The ability to ask the Webview for information on a hit test is an important feature for |
| 6 | +visually hosted apps. It can be used to support features related to mouse activity in |
| 7 | +regions that are traditionally Non-Client areas. Features like Draggable Regions, |
| 8 | +Resize, Minimize/Maximize functionality, and more. |
| 9 | + |
| 10 | + |
| 11 | +# Examples |
| 12 | +## Draggable regions (HWND) |
| 13 | +Draggable regions are marked regions on a webpage that will move the app window when the |
| 14 | +user clicks and drags on them. It also opens up the system menu if right-clicked. This |
| 15 | +API is designed to provide draggable regions support for apps that are directly hosting |
| 16 | +the CoreWebView2 via visual hosting and for UI framework WebView2 controls that use visual |
| 17 | +hosting, like the WinUI2 and WinUI3 WebView2 control.If your app uses windowed hosting, |
| 18 | +draggable regions are supported by default, no need to follow this guide. |
| 19 | + |
| 20 | +NOTE: Your app may already be forwarding mouse messages to the WebView, if so the bulk |
| 21 | +of the code below is likely already in your app. One thing you need to do specifically |
| 22 | +for this feature is to add the check for w_param == HTCAPTION as a clause for capturing |
| 23 | +the mouse and forwarding messages. It is necessary for the system menu to show. If you |
| 24 | +choose not to include this you would have to handle the logic for showing the system menu |
| 25 | +yourself. |
| 26 | + |
| 27 | +NOTE: This API is not currently supported for environments that use a CoreWindow like UWP |
| 28 | + |
| 29 | +#### Win32 C++ |
| 30 | +```cpp |
| 31 | +LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) |
| 32 | +{ |
| 33 | +.... |
| 34 | +// The following code forwards mouse messages to the WebView2 - Start |
| 35 | + |
| 36 | +// used to control when messages are forwarded to WebView |
| 37 | +static bool isCapturingMouse = false; |
| 38 | + |
| 39 | +// handle the range of mouse messages & WM_NCRBUTTONDOWN |
| 40 | +if (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST || message == WM_NCRBUTTONDOWN) |
| 41 | +{ |
| 42 | + POINT point {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; |
| 43 | + // IsPointInWebview is an example of a function which your app can implement that checks if |
| 44 | + // the mouse message point lies inside the rect of the visual that hosts the WebView |
| 45 | + if (IsPointInWebView(point) || message == WM_MOUSELEAVE || isCapturingMouse) |
| 46 | + { |
| 47 | + if (message == WM_NCRBUTTONDOWN && w_param == HTCAPTION) |
| 48 | + { |
| 49 | + // capturing the mouse will allow us to begin forwarding messages to |
| 50 | + // webview |
| 51 | + isCapturingMouse = true; |
| 52 | + SetCapture(mainWindowHwnd); |
| 53 | + } |
| 54 | + if (message == WM_RBUTTONUP && GetCapture() == mainWindowHwnd) |
| 55 | + { |
| 56 | + // no longer need to capture the mouse or forward subsequent messages |
| 57 | + // to webview |
| 58 | + isCapturingMouse = false |
| 59 | + ReleaseCapture(); |
| 60 | + } |
| 61 | + |
| 62 | + // forward mouse messages to WV |
| 63 | + CHECK_FAILURE(CompositionController->SendMouseInput( |
| 64 | + static_cast<COREWEBVIEW2_MOUSE_EVENT_KIND>(message), |
| 65 | + static_cast<COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS>(GET_KEYSTATE_WPARAM(wParam)), |
| 66 | + mouseData, point)); |
| 67 | + return 0; |
| 68 | + } |
| 69 | + |
| 70 | +} |
| 71 | +// The following code forwards mouse messages to the WebView2 - End |
| 72 | + |
| 73 | +switch(message) |
| 74 | +{ |
| 75 | + .... |
| 76 | + // Handling this message is important for enabling dragging |
| 77 | + case WM_NCHITTEST: |
| 78 | + POINT point {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; |
| 79 | + COREWEBVIEW2_HIT_TEST_KIND result = NULL; |
| 80 | + CHECK_FAILURE(CompositionController->GetHitTestResultAtPoint(&point, &result)); |
| 81 | + |
| 82 | + if (result == COREWEBVIEW2_HIT_TEST_RESULT_HTCAPTION) |
| 83 | + { |
| 84 | + return HTCAPTION; |
| 85 | + } |
| 86 | + |
| 87 | + break; |
| 88 | + .... |
| 89 | +} |
| 90 | +.... |
| 91 | +} |
| 92 | +``` |
| 93 | +#### C#/WinRT |
| 94 | +```c# |
| 95 | +.... |
| 96 | +private bool isCapturingMouse = false; |
| 97 | +.... |
| 98 | +
|
| 99 | +protected override void WndProc(ref Message m) |
| 100 | +{ |
| 101 | +.... |
| 102 | +
|
| 103 | +if (m.Msg == WM_NCHITTEST) |
| 104 | +{ |
| 105 | + Point point = new Point(GET_X_LPARAM(m.lParam), GET_Y_LPARAM(m.lParam)); |
| 106 | + if (CompositionController.GetHitTestResultAtPoint(point) == |
| 107 | + CoreWebView2HitTestResult.Htcaption) |
| 108 | + { |
| 109 | + m.Result = (IntPtr)HTCAPTION; |
| 110 | + } |
| 111 | +} |
| 112 | +// The following code forwards mouse messages to the WebView2 - Start |
| 113 | +else if (m.msg >= WM_MOUSEFIRST && m.msg <= WM_MOUSELAST || m.msg == WM_NCRBUTTONDOWN) |
| 114 | +{ |
| 115 | + |
| 116 | + Point point = new Point(GET_X_LPARAM(m.lParam), GET_Y_LPARAM(m.lParam)); |
| 117 | + // IsPointInWebview is an example of a function which your app can implement that checks if |
| 118 | + // the mouse message point lies inside the rect of the visual that hosts the WebView |
| 119 | + if (IsPointInWebView(point) || m.msg == WM_MOUSELEAVE || isCapturingMouse) |
| 120 | + { |
| 121 | +
|
| 122 | + if (m.msg == WM_NCRBUTTONDOWN && m.w_param == HTCAPTION) |
| 123 | + { |
| 124 | + // capturing the mouse will allow us to begin forwarding messages |
| 125 | + // to webview |
| 126 | + isCapturingMouse = true; |
| 127 | + SetCapture(mainWindowHwnd); |
| 128 | + } |
| 129 | + else if (message == WM_RBUTTONUP && GetCapture() == mainWindowHwnd) |
| 130 | + { |
| 131 | + // no longer need to capture the mouse for draggbale regions support |
| 132 | + // after this |
| 133 | + isCapturingMouse = false; |
| 134 | + ReleaseCapture(); |
| 135 | + } |
| 136 | + |
| 137 | + // forward mouse messages to WV |
| 138 | + CompositionController.SendMouseInput( |
| 139 | + (CoreWebView2MouseEventKind)message, |
| 140 | + (CoreWebView2MouseEventVirtualKeys)GET_KEYSTATE_WPARAM(wParam), |
| 141 | + mouseData, |
| 142 | + point); |
| 143 | +
|
| 144 | + m.Result = 0 |
| 145 | + return; |
| 146 | + } |
| 147 | + |
| 148 | +} |
| 149 | +// The following code forwards mouse messages to the WebView2 - Start |
| 150 | + .... |
| 151 | +} |
| 152 | + |
| 153 | +``` |
| 154 | +# API Details |
| 155 | +## Win32 C++ |
| 156 | +```cpp |
| 157 | +/// This enum contains values representing possible regions a given |
| 158 | +/// point lies within |
| 159 | +typedef enum COREWEBVIEW2_HIT_TEST_RESULT { |
| 160 | + /// For regions in the WV which have the CSS style 'app-region: drag' set |
| 161 | + COREWEBVIEW2_HIT_TEST_RESULT_CAPTION = 2, |
| 162 | + /// For regions in the WV which don't have the CSS style 'app-region: drag' set |
| 163 | + COREWEBVIEW2_HIT_TEST_RESULT_CLIENT, |
| 164 | + /// Out of bounds of the app window |
| 165 | + COREWEBVIEW2_HIT_TEST_RESULT_NONE = 0 |
| 166 | +} COREWEBVIEW2_HIT_TEST_RESULT; |
| 167 | + |
| 168 | +/// This interface includes the new API for enabling Webview support for hit-testing regions |
| 169 | +[uuid(42BF7BA5-917A-4C27-ADA1-EA6969854C16), object, pointer_default(unique)] |
| 170 | +interface ICoreWebView2CompositionController4 : ICoreWebView2CompositionController3 { |
| 171 | + /// Takes in a point and returns a Hit-test result value as an out parameter |
| 172 | + /// Point is expected to be in the client coordinate space of the WebView. |
| 173 | + |
| 174 | + /// The method returns: |
| 175 | + /// -COREWEBVIEW2_HIT_TEST_RESULT_CAPTION: when point corresponds to |
| 176 | + /// a region (HTML element) within the WV with |
| 177 | + /// 'app-region: drag' CSS style set |
| 178 | + /// -COREWEBVIEW2_HIT_TEST_RESULT_CLIENT: when point corresponds to |
| 179 | + /// a region (HTML element) within the WV without |
| 180 | + /// 'app-region: drag' CSS style set |
| 181 | + /// -COREWEBVIEW2_HIT_TEST_RESULT_NONE: when point is not within the WV |
| 182 | + HRESULT GetHitTestResultAtPoint( |
| 183 | + [in] POINT point, |
| 184 | + [out, retval] COREWEBVIEW2_HIT_TEST_RESULT* val); |
| 185 | +} |
| 186 | +``` |
| 187 | +## .Net/ WinRT |
| 188 | +```c# |
| 189 | +namespace Microsoft.Web.WebView2.Core { |
| 190 | + /// This enum contains values representing possible regions that Webview |
| 191 | + /// can support |
| 192 | + enum CoreWebView2HitTestResult |
| 193 | + { |
| 194 | + /// Caption region |
| 195 | + Caption = 2, |
| 196 | + /// Client region |
| 197 | + Client = 1, |
| 198 | + /// Out of bounds of the app window |
| 199 | + None = 0, |
| 200 | + } |
| 201 | + /// This runtime class includes more than just the new API for enabling Webview support for hit-testing regions |
| 202 | + runtimeclass CoreWebView2CompositionController { |
| 203 | + |
| 204 | + [interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2CompositionController4")] |
| 205 | + { |
| 206 | + /// Takes in a point and returns a Hit-test result value |
| 207 | + /// Point is expected to be in the client coordinate space of the WebView |
| 208 | + CoreWebView2HitTestResult GetHitTestResultAtPoint(Windows.Foundation.Point point); |
| 209 | + } |
| 210 | + } |
| 211 | +} |
| 212 | +``` |
0 commit comments