Skip to content

Commit c6faea1

Browse files
added new spec for a Non Client Area Hit Testing API
1 parent e7d21f8 commit c6faea1

File tree

1 file changed

+212
-0
lines changed

1 file changed

+212
-0
lines changed

specs/NonClientHitTestKind.md

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
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

Comments
 (0)