Skip to content

Commit 1d4e2a8

Browse files
committed
WPF - Add Experimental ChromiumWebBrowserWithTouchSupport
Based on #2745 Original author https://github.com/GSonofNun
1 parent 060d76e commit 1d4e2a8

File tree

4 files changed

+203
-1
lines changed

4 files changed

+203
-1
lines changed

CefSharp.Wpf/CefSharp.Wpf.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
</ItemGroup>
8080
<ItemGroup>
8181
<Compile Include="CefSettings.cs" />
82+
<Compile Include="Experimental\ChromiumWebBrowserWithTouchSupport.cs" />
8283
<Compile Include="Internals\DragOperationMaskExtensions.cs" />
8384
<Compile Include="Internals\MonitorInfo.cs" />
8485
<Compile Include="Internals\MonitorInfoEx.cs" />

CefSharp.Wpf/ChromiumWebBrowser.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2189,7 +2189,7 @@ protected override void OnMouseLeave(MouseEventArgs e)
21892189
/// Handles the <see cref="E:MouseButton" /> event.
21902190
/// </summary>
21912191
/// <param name="e">The <see cref="MouseButtonEventArgs"/> instance containing the event data.</param>
2192-
private void OnMouseButton(MouseButtonEventArgs e)
2192+
protected internal virtual void OnMouseButton(MouseButtonEventArgs e)
21932193
{
21942194
if (!e.Handled && browser != null)
21952195
{
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
// Copyright © 2019 The CefSharp Authors. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4+
5+
using System.Windows.Input;
6+
using CefSharp.Enums;
7+
using CefSharp.Structs;
8+
using CefSharp.Wpf.Internals;
9+
10+
namespace CefSharp.Wpf.Experimental
11+
{
12+
/// <summary>
13+
/// An Experimental ChromiumWebBrowser implementation that includes support for Touch/Stylus
14+
/// using the default WPF touch implementation. There are known performance problems with
15+
/// this default implementation, workarounds such as https://github.com/jaytwo/WmTouchDevice
16+
/// may need to be considered. .Net 4.7 supports the newer WM_Pointer implementation which
17+
/// should resolve the issue see https://github.com/dotnet/docs/blob/master/docs/framework/migration-guide/mitigation-pointer-based-touch-and-stylus-support.md
18+
/// Original PR https://github.com/cefsharp/CefSharp/pull/2745
19+
/// Original Author https://github.com/GSonofNun
20+
/// </summary>
21+
public class ChromiumWebBrowserWithTouchSupport : ChromiumWebBrowser
22+
{
23+
protected internal override void OnMouseButton(MouseButtonEventArgs e)
24+
{
25+
// For mouse events from an actual mouse, e.StylusDevice will be null.
26+
//For mouse events from touch and stylus, e.StylusDevice will not be null.
27+
// If we don't check if e.StylusDevice == null, touch scrolls will also select text.
28+
if (e.StylusDevice == null)
29+
{
30+
base.OnMouseButton(e);
31+
}
32+
}
33+
/// <summary>
34+
/// Provides class handling for the <see cref="E:System.Windows.TouchDown" /> routed event that occurs when a touch presses inside this element.
35+
/// </summary>
36+
/// <param name="e">The <see cref="T:System.Windows.Input.TouchEventArgs" /> that contains the event data.
37+
protected override void OnTouchDown(TouchEventArgs e)
38+
{
39+
Focus();
40+
// Capture touch so touch events are still pushed to CEF even if the touch leaves the control before a TouchUp.
41+
// This behavior is similar to how other browsers handle touch input.
42+
CaptureTouch(e.TouchDevice);
43+
OnTouch(e);
44+
base.OnTouchDown(e);
45+
}
46+
47+
/// <summary>
48+
/// Provides class handling for the <see cref="E:System.Windows.TouchMove" /> routed event that occurs when a touch moves while inside this element.
49+
/// </summary>
50+
/// <param name="e">The <see cref="T:System.Windows.Input.TouchEventArgs" /> that contains the event data.
51+
protected override void OnTouchMove(TouchEventArgs e)
52+
{
53+
OnTouch(e);
54+
base.OnTouchMove(e);
55+
}
56+
57+
/// <summary>
58+
/// Provides class handling for the <see cref="E:System.Windows.TouchUp" /> routed event that occurs when a touch is released inside this element.
59+
/// </summary>
60+
/// <param name="e">The <see cref="T:System.Windows.Input.TouchEventArgs" /> that contains the event data.
61+
protected override void OnTouchUp(TouchEventArgs e)
62+
{
63+
ReleaseTouchCapture(e.TouchDevice);
64+
OnTouch(e);
65+
base.OnTouchUp(e);
66+
}
67+
68+
/// <summary>
69+
/// Handles a <see cref="E:Touch" /> event.
70+
/// </summary>
71+
/// <param name="e">The <see cref="TouchEventArgs"/> instance containing the event data.</param>
72+
private void OnTouch(TouchEventArgs e)
73+
{
74+
var browser = GetBrowser();
75+
76+
if (!e.Handled && browser != null)
77+
{
78+
var modifiers = WpfExtensions.GetModifierKeys();
79+
var touchPoint = e.GetTouchPoint(this);
80+
var touchEventType = TouchEventType.Cancelled;
81+
switch (touchPoint.Action)
82+
{
83+
case TouchAction.Down:
84+
{
85+
touchEventType = TouchEventType.Pressed;
86+
break;
87+
}
88+
case TouchAction.Move:
89+
{
90+
touchEventType = TouchEventType.Moved;
91+
break;
92+
}
93+
case TouchAction.Up:
94+
{
95+
touchEventType = TouchEventType.Released;
96+
break;
97+
}
98+
default:
99+
{
100+
touchEventType = TouchEventType.Cancelled;
101+
break;
102+
}
103+
}
104+
105+
var touchEvent = new TouchEvent()
106+
{
107+
Id = e.TouchDevice.Id,
108+
X = (float)touchPoint.Position.X,
109+
Y = (float)touchPoint.Position.Y,
110+
PointerType = PointerType.Touch,
111+
Type = touchEventType,
112+
Modifiers = modifiers,
113+
};
114+
115+
browser.GetHost().SendTouchEvent(touchEvent);
116+
117+
e.Handled = true;
118+
}
119+
}
120+
121+
/// <summary>
122+
/// Invoked when an unhandled <see cref="E:System.Windows.Input.StylusDown" /> attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
123+
/// </summary>
124+
/// <param name="e">The <see cref="T:System.Windows.Input.StylusDownEventArgs" /> that contains the event data.
125+
protected override void OnStylusDown(StylusDownEventArgs e)
126+
{
127+
Focus();
128+
// Capture stylus so stylus events are still pushed to CEF even if the stylus leaves the control before a StylusUp.
129+
// This behavior is similar to how other browsers handle stylus input.
130+
CaptureStylus();
131+
OnStylus(e, TouchEventType.Pressed);
132+
base.OnStylusDown(e);
133+
}
134+
135+
/// <summary>
136+
/// Invoked when an unhandled <see cref="E:System.Windows.Input.StylusMove" /> attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
137+
/// </summary>
138+
/// <param name="e">The <see cref="T:System.Windows.Input.StylusDownEventArgs" /> that contains the event data.
139+
protected override void OnStylusMove(StylusEventArgs e)
140+
{
141+
OnStylus(e, TouchEventType.Moved);
142+
base.OnStylusMove(e);
143+
}
144+
145+
/// <summary>
146+
/// Invoked when an unhandled <see cref="E:System.Windows.Input.StylusUp" /> attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event.
147+
/// </summary>
148+
/// <param name="e">The <see cref="T:System.Windows.Input.StylusDownEventArgs" /> that contains the event data.
149+
protected override void OnStylusUp(StylusEventArgs e)
150+
{
151+
ReleaseStylusCapture();
152+
OnStylus(e, TouchEventType.Released);
153+
base.OnStylusUp(e);
154+
}
155+
156+
/// <summary>
157+
/// Handles a <see cref="E:Stylus" /> event.
158+
/// </summary>
159+
/// <param name="e">The <see cref="StylusEventArgs"/> instance containing the event data.</param>
160+
/// <param name="touchEventType">The <see cref="TouchEventType"/> event type</param>
161+
private void OnStylus(StylusEventArgs e, TouchEventType touchEventType)
162+
{
163+
var browser = GetBrowser();
164+
165+
var stylusPoints = e.GetStylusPoints(this);
166+
167+
if (!e.Handled && browser != null && e.StylusDevice != null && e.StylusDevice.TabletDevice.Type == TabletDeviceType.Stylus && stylusPoints.Count > 0)
168+
{
169+
var modifiers = WpfExtensions.GetModifierKeys();
170+
var pressure = stylusPoints[0].PressureFactor;
171+
var pointerType = e.StylusDevice.Inverted ? PointerType.Eraser : PointerType.Pen;
172+
173+
var touchEvent = new TouchEvent()
174+
{
175+
Id = e.StylusDevice.Id,
176+
X = (float)stylusPoints[0].X,
177+
Y = (float)stylusPoints[0].Y,
178+
PointerType = pointerType,
179+
Pressure = pressure,
180+
Type = touchEventType,
181+
Modifiers = modifiers,
182+
};
183+
184+
browser.GetHost().SendTouchEvent(touchEvent);
185+
186+
e.Handled = true;
187+
}
188+
}
189+
}
190+
}

CefSharp.Wpf/Internals/WpfExtensions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@ public static CefEventFlags GetModifiers(this MouseEventArgs e)
3939
modifiers |= CefEventFlags.RightMouseButton;
4040
}
4141

42+
modifiers |= GetModifierKeys(modifiers);
43+
44+
return modifiers;
45+
}
46+
47+
/// <summary>
48+
/// Gets keyboard modifiers.
49+
/// </summary>
50+
/// <returns>CefEventFlags.</returns>
51+
public static CefEventFlags GetModifierKeys(CefEventFlags modifiers = 0)
52+
{
4253
if (Keyboard.IsKeyDown(Key.LeftCtrl))
4354
{
4455
modifiers |= CefEventFlags.ControlDown | CefEventFlags.IsLeft;

0 commit comments

Comments
 (0)