Skip to content

Commit 14d50ef

Browse files
Merge pull request #3278 from MicrosoftEdge/api-NCHitTestPoint-draft
added new spec for a Non Client Area Hit Testing API
2 parents 5c0c310 + da5acfc commit 14d50ef

File tree

1 file changed

+209
-0
lines changed

1 file changed

+209
-0
lines changed

specs/NonClientHitTestKind.md

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
Hit Test Kind
2+
===
3+
4+
# Background
5+
The ability to ask WebView2 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 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
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+
// 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)
44+
{
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+
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)
66+
{
67+
return HTCAPTION;
68+
}
69+
70+
break;
71+
....
72+
}
73+
....
74+
}
75+
```
76+
#### C#/WinRT
77+
```c#
78+
protected override void WndProc(ref Message m)
79+
{
80+
....
81+
82+
if (m.Msg == WM_NCHITTEST)
83+
{
84+
Point point = new Point(GET_X_LPARAM(m.lParam), GET_Y_LPARAM(m.lParam));
85+
if (m_compositionController.GetHitTestResultAtPoint(point) ==
86+
CoreWebView2HitTestResult.Htcaption)
87+
{
88+
m.Result = (IntPtr)HTCAPTION;
89+
}
90+
}
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)
94+
{
95+
96+
Point point = new Point(GET_X_LPARAM(m.lParam), GET_Y_LPARAM(m.lParam));
97+
// IsPointInWebview is an example of a function which your app can implement that
98+
// checks if the mouse message point lies inside the rect of the visual that hosts
99+
// the WebView.
100+
if (IsPointInWebView(point) || m.msg == WM_MOUSELEAVE)
101+
{
102+
103+
// forward mouse messages to WebView2
104+
m_compositionController.SendMouseInput(
105+
(CoreWebView2MouseEventKind)message,
106+
(CoreWebView2MouseEventVirtualKeys)GET_KEYSTATE_WPARAM(wParam),
107+
mouseData,
108+
point);
109+
110+
m.Result = 0
111+
return;
112+
}
113+
114+
}
115+
// The following code forwards mouse messages to the WebView2 - Start
116+
....
117+
}
118+
```
119+
# API Notes
120+
## Marking regions In Your App
121+
Draggable regions in WebView2 are HTML elements marked with the CSS style
122+
`-webkit-app-region: drag`. WebView2 will treat any element with this style as a
123+
drag handle for the window.
124+
125+
See Documentation [here](https://learn.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/window-controls-overlay#make-regions-of-your-app-drag-handlers-for-the-window)
126+
127+
# API Details
128+
## Win32 C++
129+
```cpp
130+
/// This enum contains values representing possible regions a given
131+
/// point lies within
132+
typedef enum COREWEBVIEW2_HIT_TEST_RESULT {
133+
/// A hit test region in the WebView2 which has the CSS style
134+
/// `-webkit-app-region: drag` set. Web content should use this CSS
135+
/// style to identify regions that should be treated like the app
136+
/// window's title bar. This has the same value as the Win32 HTCAPTION
137+
/// constant.
138+
COREWEBVIEW2_HIT_TEST_RESULT_CAPTION = 2,
139+
/// A hit test region in the WebView2 which does not have the CSS style
140+
/// `-webkit-app-region: drag` set. This is normal web content that should not be
141+
/// considered part of the app window's title bar. This has the same value
142+
/// as the Win32 HTCLIENT constant.
143+
COREWEBVIEW2_HIT_TEST_RESULT_CLIENT = 1,
144+
/// A hit test region out of bounds of the WebView2.
145+
/// This has the same value as the Win32 HTNOWHERE
146+
COREWEBVIEW2_HIT_TEST_RESULT_NOWHERE = 0
147+
} COREWEBVIEW2_HIT_TEST_RESULT;
148+
149+
/// This interface includes the new API for enabling WebView2 support for hit-testing regions
150+
[uuid(42BF7BA5-917A-4C27-ADA1-EA6969854C16), object, pointer_default(unique)]
151+
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);
170+
}
171+
172+
/// Mouse event type used by SendMouseInput to convey the type of mouse event
173+
/// being sent to WebView. The values of this enum align with the matching
174+
/// WM_* window messages.
175+
typedef enum COREWEBVIEW2_MOUSE_EVENT_KIND {
176+
....
177+
/// Mouse Right Button Down event over a nonclient area, WM_NCRBUTTONDOWN.
178+
COREWEBVIEW2_MOUSE_EVENT_KIND_NON_CLIENT_RIGHT_BUTTON_DOWN = 0x00A4,
179+
....
180+
/// Mouse Right Button up event over a nonclient area, WM_NCRBUTTONUP.
181+
COREWEBVIEW2_MOUSE_EVENT_KIND_NON_CLIENT_RIGHT_BUTTON_UP = 0x00A5,
182+
....
183+
} COREWEBVIEW2_MOUSE_EVENT_KIND;
184+
```
185+
## .Net/ WinRT
186+
```c#
187+
namespace Microsoft.Web.WebView2.Core {
188+
enum CoreWebView2HitTestResult
189+
{
190+
Caption = 2,
191+
Client = 1,
192+
Nowhere = 0,
193+
}
194+
enum CoreWebView2MouseEventKind
195+
{
196+
...
197+
NonClientRightButtonDown = 0x00A4,
198+
NonClientRightButtonUp = 0x00A5,
199+
...
200+
}
201+
runtimeclass CoreWebView2CompositionController {
202+
203+
[interface_name("Microsoft.Web.WebView2.Core.ICoreWebView2CompositionController4")]
204+
{
205+
CoreWebView2HitTestResult GetHitTestResultAtPoint(Windows.Foundation.Point point);
206+
}
207+
}
208+
}
209+
```

0 commit comments

Comments
 (0)