@@ -17,63 +17,58 @@ the CoreWebView2 via visual hosting and for UI framework WebView2 controls that
17
17
hosting, like the WinUI2 and WinUI3 WebView2 control.If your app uses windowed hosting,
18
18
draggable regions are supported by default, no need to follow this guide.
19
19
20
- NOTE: Your app may already be forwarding mouse messages to WebView2, 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
20
+ NOTE: This API is not currently supported for environments that use a CoreWindow like UWP.
28
21
29
22
#### Win32 C++
30
23
``` cpp
31
24
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
32
25
{
33
26
....
34
- // The following code forwards mouse messages to the WebView2 - Start
27
+ // We need to forward relevant mouse messages to the webview
35
28
36
- // handle the range of mouse messages & WM_NCRBUTTONDOWN
37
- if (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST
38
- || message == WM_NCRBUTTONDOWN || message == WM_NCRBUTTONUP)
39
- {
40
- POINT point {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
41
- // IsPointInWebview is an example of a function which your app can implement that checks if
42
- // the mouse message point lies inside the rect of the visual that hosts the WebView2
43
- if (IsPointInWebView(point) || message == WM_MOUSELEAVE)
29
+ // handle the range of mouse messages & WM_NCRBUTTONDOWN
30
+ if (message == WM_NCRBUTTONDOWN || message == WM_NCRBUTTONUP)
44
31
{
45
- // forward mouse messages to WebView2
46
- CHECK_FAILURE(m_compositionController->SendMouseInput(
47
- static_cast<COREWEBVIEW2_MOUSE_EVENT_KIND>(message),
48
- static_cast<COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS>(GET_KEYSTATE_WPARAM(wParam)),
49
- mouseData, point));
50
- return 0;
51
- }
52
-
53
- }
54
- // The following code forwards mouse messages to the WebView2 - End
55
-
56
- switch(message)
57
- {
58
- ....
59
- // Handling this message is important for enabling dragging
60
- case WM_NCHITTEST:
61
32
POINT point {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
62
- COREWEBVIEW2_HIT_TEST_RESULT result = NULL;
63
- CHECK_FAILURE(m_compositionController->GetHitTestResultAtPoint(&point, &result));
64
-
65
- if (result == COREWEBVIEW2_HIT_TEST_RESULT_HTCAPTION)
33
+ // WM_NCRBUTTONDOWN/UP have poitns in screen coordinates we need
34
+ // to convert the point to client coordinates to match the others
35
+ ScreenToClient(hwnd, &point);
36
+
37
+ // IsPointInWebview is an example of a function which your app can implement that checks if
38
+ // the mouse message point lies inside the rect of the visual that hosts the WebView2
39
+ if (IsPointInWebView(point))
66
40
{
67
- return HTCAPTION;
41
+ // Adjust the point from app client coordinates to webview client coordinates.
42
+ // m_webViewBounds is a rect that represents the bounds that you app has set for
43
+ // the webveiw
44
+ point.x -= m_webViewBounds.left;
45
+ point.y -= m_webViewBounds.top;
46
+
47
+ // forward mouse messages to WebView2
48
+ CHECK_FAILURE(m_compositionController->SendMouseInput(
49
+ static_cast<COREWEBVIEW2_MOUSE_EVENT_KIND>(message),
50
+ static_cast<COREWEBVIEW2_MOUSE_EVENT_VIRTUAL_KEYS>(GET_KEYSTATE_WPARAM(wParam)),
51
+ 0, point));
52
+ return 0;
68
53
}
54
+
55
+ }
69
56
70
- break;
71
- ....
72
- }
57
+ switch(message)
58
+ {
59
+ ....
60
+ // Handling this message is important for enabling dragging
61
+ case WM_NCHITTEST:
62
+ POINT point {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
63
+ COREWEBVIEW2_NON_CLIENT_REGION_KIND result = COREWEBVIEW2_NON_CLIENT_REGION_KIND_NOWHERE;
64
+ CHECK_FAILURE(m_compositionController->GetNonClientRegionAtPoint(&point, &result));
65
+ return result;
66
+ ....
67
+ }
73
68
....
74
69
}
75
70
```
76
- #### C#/WinRT
71
+ #### C#
77
72
```c#
78
73
protected override void WndProc(ref Message m)
79
74
{
@@ -82,32 +77,41 @@ protected override void WndProc(ref Message m)
82
77
if (m.Msg == WM_NCHITTEST)
83
78
{
84
79
Point point = new Point(GET_X_LPARAM(m.lParam), GET_Y_LPARAM(m.lParam));
85
- if (m_compositionController.GetHitTestResultAtPoint (point) ==
86
- CoreWebView2HitTestResult.Htcaption )
80
+ if (m_compositionController.GetNonClientRegionAtPoint (point) ==
81
+ CoreWebView2NonClientRegionKind.Caption )
87
82
{
88
83
m.Result = (IntPtr)HTCAPTION;
89
84
}
90
85
}
91
- // The following code forwards mouse messages to the WebView2 - Start
92
- else if (m.msg >= WM_MOUSEFIRST && m.msg <= WM_MOUSELAST
93
- || m.msg == WM_NCRBUTTONDOWN || m.msg == WM_NCRBUTTONUP)
86
+ else if (m.msg == WM_NCRBUTTONDOWN || m.msg == WM_NCRBUTTONUP)
94
87
{
95
88
96
89
Point point = new Point(GET_X_LPARAM(m.lParam), GET_Y_LPARAM(m.lParam));
90
+
91
+ // WM_NCRBUTTONDOWN/UP have poitns in screen coordinates we need
92
+ // to convert the point to client coordinates to match the others
93
+ ScreenToClient(m.hwnd, ref point);
94
+
95
+
97
96
// IsPointInWebview is an example of a function which your app can implement that
98
97
// checks if the mouse message point lies inside the rect of the visual that hosts
99
98
// the WebView.
100
- if (IsPointInWebView(point) || m.msg == WM_MOUSELEAVE )
99
+ if (IsPointInWebView(point))
101
100
{
101
+ // Adjust the point from app client coordinates to webview client coordinates.
102
+ // m_webViewBounds is a rect that represents the bounds that you app has set for
103
+ // the webveiw
104
+ point.x -= m_webViewBounds.left;
105
+ point.y -= m_webViewBounds.top;
102
106
103
107
// forward mouse messages to WebView2
104
108
m_compositionController.SendMouseInput(
105
- (CoreWebView2MouseEventKind)message ,
109
+ (CoreWebView2MouseEventKind)m.msg ,
106
110
(CoreWebView2MouseEventVirtualKeys)GET_KEYSTATE_WPARAM(wParam),
107
- mouseData ,
111
+ 0 ,
108
112
point);
109
113
110
- m.Result = 0
114
+ m.Result = 0;
111
115
return;
112
116
}
113
117
@@ -116,6 +120,19 @@ else if (m.msg >= WM_MOUSEFIRST && m.msg <= WM_MOUSELAST
116
120
....
117
121
}
118
122
```
123
+ #### C#/WinRT
124
+
125
+ ``` c#
126
+ void DraggableRegionSample () {
127
+
128
+ m_compositionController .NonClientRegionChanged += (object sender , CoreWebView2NonClientRegionChangedEventArgs arg ) => {
129
+ CoreWebView2NonClientRegionKind kind = arg .Region ;
130
+ IVector < Windows .Foundation .Rect > region_rects = m_compositionController .QueryNonClientRegion (kind );
131
+ // use kind & region_rects to ConfigureRegion on the InputNonClientPointerSource
132
+ }
133
+
134
+ }
135
+ ```
119
136
# API Notes
120
137
## Marking regions In Your App
121
138
Draggable regions in WebView2 are HTML elements marked with the CSS style
@@ -129,44 +146,83 @@ See Documentation [here](https://learn.microsoft.com/en-us/microsoft-edge/progre
129
146
``` cpp
130
147
// / This enum contains values representing possible regions a given
131
148
// / point lies within
132
- typedef enum COREWEBVIEW2_HIT_TEST_RESULT {
149
+ typedef enum COREWEBVIEW2_NON_CLIENT_REGION_KIND {
133
150
/// A hit test region in the WebView2 which has the CSS style
134
151
/// `-webkit-app-region: drag` set. Web content should use this CSS
135
152
/// style to identify regions that should be treated like the app
136
153
/// window's title bar. This has the same value as the Win32 HTCAPTION
137
154
/// constant.
138
- COREWEBVIEW2_HIT_TEST_RESULT_CAPTION = 2,
155
+ COREWEBVIEW2_NON_CLIENT_REGION_KIND_CAPTION = 2,
139
156
/// A hit test region in the WebView2 which does not have the CSS style
140
157
/// `-webkit-app-region: drag` set. This is normal web content that should not be
141
158
/// considered part of the app window's title bar. This has the same value
142
159
/// as the Win32 HTCLIENT constant.
143
- COREWEBVIEW2_HIT_TEST_RESULT_CLIENT = 1,
160
+ COREWEBVIEW2_NON_CLIENT_REGION_KIND_CLIENT = 1,
144
161
/// A hit test region out of bounds of the WebView2.
145
162
/// This has the same value as the Win32 HTNOWHERE
146
- COREWEBVIEW2_HIT_TEST_RESULT_NOWHERE = 0
147
- } COREWEBVIEW2_HIT_TEST_RESULT;
163
+ COREWEBVIEW2_NON_CLIENT_REGION_KIND_NOWHERE = 0
164
+ } COREWEBVIEW2_NON_CLIENT_REGION_KIND;
165
+
166
+ [uuid(0BEA1283-39DC-48D1-9893 -16275505CBBC), object, pointer_default(unique)]
167
+ interface ICoreWebView2NonClientRegionChangedEventHandler : IUnknown {
168
+ /// Called to provide the implementer with the event args for the
169
+ /// corresponding event.
170
+ HRESULT Invoke(
171
+ [ in] ICoreWebView2StagingCompositionController* sender,
172
+ [ in] ICoreWebView2NonClientRegionChangedEventArgs* args);
173
+ }
174
+
175
+ // / Interface for status bar text change event args
176
+ [uuid(E404B00C-669E-43EC-BE43-FB8CD7DBB480), object, pointer_default(unique)]
177
+ interface ICoreWebView2NonClientRegionChangedEventArgs : IUnknown {
178
+ [propget] HRESULT Region(
179
+ [out, retval] COREWEBVIEW2_NON_CLIENT_REGION_KIND* value);
180
+ }
181
+ // Interface that Represents a Collection of Regoin Rects
182
+ [uuid(A990DA9D-4243 -4FCD-B895-2E7E87EAAB14), object, pointer_default(unique)]
183
+ interface ICoreWebView2RegionRectCollection : IUnknown {
184
+ /// Gets the number of ` RegionRect ` objects contained in the ` RegionRectCollection ` .
185
+ [ propget] HRESULT Count([ out, retval] UINT32* value);
186
+
187
+ /// Gets the ` RegionRect ` at the specified index.
188
+ HRESULT GetValueAtIndex([ in] UINT32 index,
189
+ [ out, retval] RECT* value);
190
+
191
+ }
148
192
149
193
// / This interface includes the new API for enabling WebView2 support for hit-testing regions
150
194
[uuid(42BF7BA5-917A-4C27-ADA1-EA6969854C16), object, pointer_default(unique)]
151
195
interface ICoreWebView2CompositionController4 : ICoreWebView2CompositionController3 {
152
- /// If you are hosting a WebView2 using CoreWebView2CompositionController, you can call
153
- /// this method in your Win32 WndProc to determine if the mouse is moving over or
154
- /// clicking on WebView2 web content that should be considered part of the app window's
155
- /// title bar.
156
-
157
- /// [in] Point is expected to be in the client coordinate space of WebView2.
158
- /// [out, retval] The method returns:
159
- /// - COREWEBVIEW2_HIT_TEST_RESULT_CAPTION when point corresponds to
160
- /// a region (HTML element) within the WebView2 with
161
- /// `-webkit-app-region: drag` CSS style set
162
- /// - COREWEBVIEW2_HIT_TEST_RESULT_CLIENT when point corresponds to
163
- /// a region (HTML element) within the WebView2 without
164
- /// `-webkit-app-region: drag` CSS style set
165
- /// - COREWEBVIEW2_HIT_TEST_RESULT_NOWHERE when point is not within the WebView2
166
-
167
- HRESULT GetHitTestResultAtPoint(
168
- [in] POINT point,
169
- [out, retval] COREWEBVIEW2_HIT_TEST_RESULT* val);
196
+ /// If you are hosting a WebView2 using CoreWebView2CompositionController, you can call
197
+ /// this method in your Win32 WndProc to determine if the mouse is moving over or
198
+ /// clicking on WebView2 web content that should be considered part of the app window's
199
+ /// title bar.
200
+
201
+ /// The point parameter is expected to be in the client coordinate space of WebView2.
202
+ /// The method sets the out parameter value as follows:
203
+ /// - COREWEBVIEW2_NON_CLIENT_REGION_KIND_CAPTION when point corresponds to
204
+ /// a region (HTML element) within the WebView2 with
205
+ /// ` -webkit-app-region: drag ` CSS style set
206
+ /// - COREWEBVIEW2_NON_CLIENT_REGION_KIND_CLIENT when point corresponds to
207
+ /// a region (HTML element) within the WebView2 without
208
+ /// ` -webkit-app-region: drag ` CSS style set
209
+ /// - COREWEBVIEW2_NON_CLIENT_REGION_KIND_NOWHERE when point is not within the WebView2
210
+ HRESULT GetNonClientRegionAtPoint(
211
+ [ in] POINT point,
212
+ [ out, retval] COREWEBVIEW2_NON_CLIENT_REGION_KIND* value);
213
+
214
+ HRESULT QueryNonClientRegion(
215
+ [ in] COREWEBVIEW2_NON_CLIENT_REGION_KIND kind,
216
+ [ out, retval] ICoreWebView2RegionRectCollection** rects);
217
+
218
+ /// Use to add a listener to be notified when NonClientRegion change
219
+ HRESULT add_NonClientRegionChanged(
220
+ [ in] ICoreWebView2NonClientRegionChangedEventHandler* eventHandler,
221
+ [ out] EventRegistrationToken* token);
222
+
223
+ /// Removing an event handler for ` NonClientRegionChanged ` event
224
+ HRESULT remove_NonClientRegionChanged(
225
+ [ in] EventRegistrationToken token);
170
226
}
171
227
172
228
// / Mouse event type used by SendMouseInput to convey the type of mouse event
@@ -176,7 +232,6 @@ typedef enum COREWEBVIEW2_MOUSE_EVENT_KIND {
176
232
....
177
233
/// Mouse Right Button Down event over a nonclient area, WM_NCRBUTTONDOWN.
178
234
COREWEBVIEW2_MOUSE_EVENT_KIND_NON_CLIENT_RIGHT_BUTTON_DOWN = 0x00A4,
179
- ....
180
235
/// Mouse Right Button up event over a nonclient area, WM_NCRBUTTONUP.
181
236
COREWEBVIEW2_MOUSE_EVENT_KIND_NON_CLIENT_RIGHT_BUTTON_UP = 0x00A5,
182
237
....
@@ -185,7 +240,7 @@ typedef enum COREWEBVIEW2_MOUSE_EVENT_KIND {
185
240
## .Net/ WinRT
186
241
``` c#
187
242
namespace Microsoft .Web .WebView2 .Core {
188
- enum CoreWebView2HitTestResult
243
+ enum CoreWebView2NonClientRegionKind
189
244
{
190
245
Caption = 2 ,
191
246
Client = 1 ,
@@ -198,11 +253,20 @@ namespace Microsoft.Web.WebView2.Core {
198
253
NonClientRightButtonUp = 0x 00A5 ,
199
254
...
200
255
}
256
+ runtimeclass CoreWebView2NonClientRegionChangedEventArgs
257
+ {
258
+ // ICoreWebView2NonClientRegionChangedEventArgs members
259
+ CoreWebView2NonClientRegionKind Region { get; };
260
+
261
+ }
201
262
runtimeclass CoreWebView2CompositionController {
202
263
203
264
[interface_name (" Microsoft.Web.WebView2.Core.ICoreWebView2CompositionController4" )]
204
265
{
205
- CoreWebView2HitTestResult GetHitTestResultAtPoint(Windows.Foundation.Point point);
266
+ /// ICoreWebView2CompositionController4 members
267
+ event Windows .Foundation .TypedEventHandler < CoreWebView2CompositionController , CoreWebView2NonClientRegionChangedEventArgs > NonClientRegionChanged ;
268
+ CoreWebView2NonClientRegionKind GetNonClientRegionAtPoint (Windows .Foundation .Point point );
269
+ IVector < Windows .Foundation .Rect > QueryNonClientRegion (CoreWebView2NonClientRegionKind Kind );
206
270
}
207
271
}
208
272
}
0 commit comments