cefsharp / CefSharp

.NET (WPF and Windows Forms) bindings for the Chromium Embedded Framework
http://cefsharp.github.io/
Other
9.87k stars 2.92k forks source link

Feature Request - Add WPF TouchScroll/Multitouch Support #228

Closed dinoc closed 4 years ago

dinoc commented 10 years ago

I guess this is more of a feature request than an issue but it would be nice to have multitouch support:

-Scrolling with one finger -Zooming with pinch zoom gesture

cztomczak commented 10 years ago

There is the --touch-events=enabled|disabled flag that enables multitouch events in javascript.

In CefBrowser there are methods like: SendMouseClickEvent(), SendMouseMoveEvent(). You can use these to send the touch-up, touch-down, touch-move events to CEF.

See also these issues/topics in CEF:

"Windows touch scroll acting as mouse click event" http://www.magpcss.org/ceforum/viewtopic.php?f=6&t=10321

"Touch support in CEF1 and CEF3 does not match Chromium browser" https://code.google.com/p/chromiumembedded/issues/detail?id=786

"Touch-screen generated MouseEvent(s) do not have the same XY coords as actual mouse clicks" https://code.google.com/p/chromiumembedded/issues/detail?id=959

"Multi-touch screen : No virtual screen displayed on focus in an input" https://code.google.com/p/chromiumembedded/issues/detail?id=985

"Cef3: Multi-touch support with offscreen rendering." https://code.google.com/p/chromiumembedded/issues/detail?id=1059

amaitland commented 7 years ago

https://bitbucket.org/chromiumembedded/cef/issues/1059/cef3-multi-touch-support-with-offscreen

Until the upstream issue has been resolved it's not possible to implement MultiTouch in the WPF version. If you require it now then you will have to use the the WinForms version hosted in a WindowsFormsHost control.

Please no further comments asking when it will be ready, it's out of our control.

amaitland commented 7 years ago

Just as a status update, there are two PR's currently being reviewed, neither is complete. You can view them both at

https://bitbucket.org/chromiumembedded/cef/pull-requests/104 https://bitbucket.org/chromiumembedded/cef/pull-requests/100

If this is a feature you require and you have a C++ background then you should contribute to one or both.

This is just a status update, no further comments required.

dhpanteon commented 7 years ago

Only for Touch Scrolling Bellow code works for me

1) Add the Following line in CefSharp.Example => Init() settings.CefCommandLineArgs.Add("touch-events", "1");

2) Open the Browser Window's Code, Define bellow variables at class level bool IsMouseDown = false; Point? LastSavedPoint = null; IBrowserHost host;

3) Add Touch events for the Web Browser

    #region Touch Events

    private void browser_TouchMove(object sender, TouchEventArgs e)
    {
        if (host != null && IsMouseDown)
        {
            TouchPoint t = e.GetTouchPoint(this);
            Point p = t.Position;

            if (!LastSavedPoint.HasValue)
                LastSavedPoint = p;

            int x = (int)p.X;
            int y = (int)p.Y;
            int oldX = (int)LastSavedPoint.Value.X;
            int oldy = (int)LastSavedPoint.Value.Y;

            host.SendMouseWheelEvent(x, y, 0, y - oldy, CefEventFlags.MiddleMouseButton);

            LastSavedPoint = p; //Store the last Point for reference
        }
    }

    void browser_TouchDown(object sender, TouchEventArgs e)
    {
        if (host == null)
        {
            IWebBrowser host2 = browser; // **your Browser's  Instance** 
            IBrowser bworser = host2.GetBrowser();
            host = bworser.GetHost(); // Get host from Browser
        }
        IsMouseDown = true;
       // this.Cursor = System.Windows.Input.Cursors.None;
    }

    private void browser_TouchLeave(object sender, TouchEventArgs e)
    {
        IsMouseDown = false;
        LastSavedPoint = null;
    }

    void browser_TouchUp(object sender, TouchEventArgs e)
    {
        IsMouseDown = false;
        LastSavedPoint = null;
    }
    #endregion
Clemani commented 7 years ago

Other implementations, one with touch events and one with manipulation events. Just copied it from my project, you need to translate to c# i guess. No need to set "touch-events=1", it has no effect in WPF.

Common for both methods:

`   Private TouchMoveState As Integer = 0
    Private Const cTouchMoveFactor As Double = 1.2
    Private LastMouseButtonDown As Long = Now.Ticks - TimeSpan.TicksPerMinute
    Private FirstTouchPoint As Point = New Point(-1, -1)
    Private LastTouchPoint As Point = New Point(-1, -1)

    Private Sub Scroll(ByVal intX As Integer, ByVal intY As Integer)

        Dim blnSendMouseWheelEvent As Boolean = False

        blnSendMouseWheelEvent = True
        'If Not String.IsNullOrEmpty(Me.Address) Then
        '    If Me.Address.EndsWith(".pdf", StringComparison.InvariantCultureIgnoreCase) Then
        '        blnSendMouseWheelEvent = True
        '    End If
        'End If

        'SendMouseWheelEvent:
        '- for PDF's only scroll down works
        '- can stop working, see https://github.com/cefsharp/CefSharp/issues/2064
        If blnSendMouseWheelEvent Then
            Dim browser As CefSharp.IBrowser = Nothing
            Dim host As CefSharp.IBrowserHost = Nothing
            Try
                Dim intMouseX As Integer = 50
                Dim intMouseY As Integer = 50
                browser = GetBrowser()
                If browser IsNot Nothing Then
                        host = browser.GetHost()
                        If host IsNot Nothing Then
                            host.SendMouseWheelEvent(intMouseX, intMouseY, intX, intY, 0)
                        End If
                End If
            Catch ex As Exception
                LogManager.LogMessage(LogType.Errors, ex)
            Finally
            End Try
            Exit Sub
        End If

        'window.scrollBy
        '- does not work with PDF
        '- does not work with all websites
        ''window.scrollBy(xnum, ynum)
        ''xnum:     Required. How many pixels to scroll by, along the x-axis (horizontal). 
        ''           Positive values will scroll to the right, while negative values will scroll to the left

        ''ynum:     Required. How many pixels to scroll by, along the y-axis (vertical).
        ''           Positive values will scroll down, while negative values scroll up

        Dim frame As CefSharp.IFrame = Nothing
        Try
            Dim browser As CefSharp.IBrowser = GetBrowser()
            If browser IsNot Nothing Then
                frame = browser.MainFrame
                If frame IsNot Nothing Then
                    Dim script As String = "window.scrollBy(" & (intX * -1).ToString & "," & (intY * -1).ToString & ");"
                    frame.ExecuteJavaScriptAsync(script)
                End If
            End If
        Catch ex As Exception
            LogManager.LogMessage(LogType.Errors, ex)
        Finally
            Try
                If frame IsNot Nothing Then
                    If Not frame.IsDisposed Then
                        frame.Dispose()
                        frame = Nothing
                    End If
                End If
            Catch ex As Exception
                LogManager.LogMessage(LogType.Errors, ex)
            End Try
        End Try

    End Sub`

With touch events:

`    Private Sub CefSharpBrowserControl_StylusSystemGesture_TouchScroll(sender As Object, e As StylusSystemGestureEventArgs)
        Try
            Select Case e.SystemGesture
                Case SystemGesture.HoldEnter, SystemGesture.Drag
                    'to prevent jumpy scrolling on finger clicks, dont use TouchDown for scrolling start

                    'Remember where this contact took place.
                    FirstTouchPoint = e.GetPosition(Me)
                    LastTouchPoint = FirstTouchPoint

                    Me.TouchMoveState = 1 'scrolling can start now
            End Select
        Catch ex As Exception
            Me.TouchMoveState = 0
            FirstTouchPoint.X = -1
            LastTouchPoint.X = -1
            LogManager.LogMessage(LogType.Errors, ex)
        End Try
    End Sub

    Private Sub CefSharpBrowserControl_TouchMove(sender As Object, e As TouchEventArgs)
        Try
            If (Me.TouchMoveState = 0) Or (LastTouchPoint.X = -1) Then
                Exit Sub
            End If

            Me.TouchMoveState = 2 'scrolling actually happend now

            'Get the current position of the contact. 
            Dim tp As TouchPoint = e.GetTouchPoint(Me)
            Dim currentTouchPoint As Point = tp.Position

            'Get the change between the controlling contact point and the changed contact point.
            'scroll either horizontally or vertically, scrolling in both directions at the same time does not work well
            Dim dblCumulativeX As Double = Math.Abs(currentTouchPoint.X - FirstTouchPoint.X)
            Dim dblCumulativeY As Double = Math.Abs(currentTouchPoint.Y - FirstTouchPoint.Y)

            Dim intDeltaX = 0
            Dim intDeltaY = 0

            If dblCumulativeX > dblCumulativeY Then
                Dim dblDeltaX As Double = currentTouchPoint.X - LastTouchPoint.X
                If dblDeltaX <> 0 Then
                    dblDeltaX *= cTouchMoveFactor
                    'round the change up
                    If dblDeltaX > 0 Then
                        dblDeltaX += 0.99
                    ElseIf dblDeltaX < 0 Then
                        dblDeltaX -= 0.99
                    End If
                    intDeltaX = Math.Truncate(dblDeltaX)
                End If
            Else
                Dim dblDeltaY As Double = currentTouchPoint.Y - LastTouchPoint.Y
                If dblDeltaY <> 0 Then
                    dblDeltaY *= cTouchMoveFactor
                    'round the change up
                    If dblDeltaY > 0 Then
                        dblDeltaY += 0.99
                    ElseIf dblDeltaY < 0 Then
                        dblDeltaY -= 0.99
                    End If
                    intDeltaY = Math.Truncate(dblDeltaY)
                End If
            End If

            If (intDeltaX <> 0) Or (intDeltaY <> 0) Then
                Scroll(intDeltaX, intDeltaY)
            End If

            'Forget the old contact point, and remember the new contact point.
            LastTouchPoint = currentTouchPoint

        Catch ex As Exception
            Me.TouchMoveState = 0
            FirstTouchPoint.X = -1
            LastTouchPoint.X = -1
            LogManager.LogMessage(LogType.Errors, ex)
        End Try
    End Sub

    Private Sub CefSharpBrowserControl_TouchUp(sender As Object, e As TouchEventArgs)
        Try
            'Forget about this contact.
            Me.TouchMoveState = 0
            FirstTouchPoint.X = -1
            LastTouchPoint.X = -1
        Catch ex As Exception
            LogManager.LogMessage(LogType.Errors, ex)
        End Try
    End Sub

    Private Sub CefSharpBrowserControl_PreviewMouseMove(sender As Object, e As MouseEventArgs)
        'MouseMove event is triggered even when e.Handled = True in all Touch events
        'e.StylusDevice.Name = "Stylus" no matter if pen or fingers are used!
        Try
            If e.StylusDevice IsNot Nothing Then
                If Me.TouchMoveState = 2 Then
                    e.Handled = True
                End If
            End If
        Catch ex As Exception
            Me.TouchMoveState = 0
            FirstTouchPoint.X = -1
            LastTouchPoint.X = -1
            LogManager.LogMessage(LogType.Errors, ex)
        End Try
    End Sub

With manipulation events `(need to set IsManipulationEnabled = True):

`    Private Sub CefSharpBrowserControl_PreviewMouseButtonDown(sender As Object, e As MouseButtonEventArgs)
        'if IsManipulationEnabled = True then
        '- click by finger does not trigger Mouse events
        '- click by pen triggers Mouse events
        '--> save the last click time to determine later in StylusSystemGesture if it was triggered by pen or finger
        Me.LastMouseButtonDown = Now.Ticks
    End Sub

    Private Sub CefSharpBrowserControl_StylusSystemGesture_ManipulationScroll(sender As Object, e As StylusSystemGestureEventArgs)
        Try
            Select Case e.SystemGesture
                Case SystemGesture.HoldEnter, SystemGesture.Drag
                    'to prevent jumpy scrolling on finger clicks

                    Dim diffTime As Long = Now.Ticks - Me.LastMouseButtonDown
                    If (diffTime >= -3000000) And (diffTime <= 3000000) Then
                        'MouseButtonDown happened shortly before
                        '--> event triggered by Pen
                        Exit Sub
                    End If

                    Me.TouchMoveState = 1 'scrolling can start now

                Case SystemGesture.Tap
                    'click by finger does not work anymore if IsManipulationEnabled=True
                    'TimeSpan.TicksPerSecond = 10.000.000
                    Dim diffTime As Long = Now.Ticks - Me.LastMouseButtonDown
                    If (diffTime >= -3000000) And (diffTime <= 3000000) Then
                        'MouseButtonDown happened shortly before
                        '--> event triggered by Pen, click gets normally processed, sending a click event would lead to a double-click
                    Else
                        '--> event triggered by finger
                        Dim host As CefSharp.IBrowserHost = Nothing
                        Try
                            Dim browser As CefSharp.IBrowser = Nothing
                            If browser IsNot Nothing Then
                                host = browser.GetHost()
                                If host IsNot Nothing Then
                                    Dim pt As Point = e.GetPosition(Me)
                                    host.SendMouseClickEvent(pt.X, pt.Y, CefSharp.MouseButtonType.Left, False, 1, CefSharp.CefEventFlags.None)
                                    System.Threading.Thread.Sleep(100)
                                    host.SendMouseClickEvent(pt.X, pt.Y, CefSharp.MouseButtonType.Left, True, 1, CefSharp.CefEventFlags.None)
                                End If
                            End If
                        Catch ex As Exception
                            LogManager.LogMessage(LogType.Errors, ex)
                        Finally
                        End Try
                    End If
                    'e.StylusDevice.Name is always "Stylus" no matter if triggered by pen or finger

                Case SystemGesture.RightTap
                    'click by finger does not work anymore if IsManipulationEnabled=True
                    'TimeSpan.TicksPerSecond = 10.000.000
                    Dim diffTime As Long = Now.Ticks - Me.LastMouseButtonDown
                    If (diffTime >= -3000000) And (diffTime <= 3000000) Then
                        'MouseButtonDown happened shortly before
                        '--> event triggered by Pen, click gets normally processed, sending a click event would lead to a double-click
                    Else
                        '--> event triggered by finger
                        Dim host As CefSharp.IBrowserHost = Nothing
                        Try
                            Dim browser As CefSharp.IBrowser = Nothing
                            If browser IsNot Nothing Then
                                host = browser.GetHost()
                                If host IsNot Nothing Then
                                    Dim pt As Point = e.GetPosition(Me)
                                    host.SendMouseClickEvent(pt.X, pt.Y, CefSharp.MouseButtonType.Right, False, 1, CefSharp.CefEventFlags.None)
                                    System.Threading.Thread.Sleep(100)
                                    host.SendMouseClickEvent(pt.X, pt.Y, CefSharp.MouseButtonType.Right, True, 1, CefSharp.CefEventFlags.None)
                                End If
                            End If
                        Catch ex As Exception
                            LogManager.LogMessage(LogType.Errors, ex)
                        Finally
                        End Try
                    End If

            End Select
        Catch ex As Exception
            LogManager.LogMessage(LogType.Errors, ex)
        End Try
    End Sub

    Private Sub CefSharpBrowserControl_ManipulationStarting(sender As Object, e As ManipulationStartingEventArgs)
        'The ContainerElement is the UI element to which all manipulation calculations and events are relative.
        'If you do not set a ContainerElement, the UI element that is firing the event will be used.
        'This works well for Zoom/Scale, but for all Translate or Rotate manipulations you should set a ContainerElement,
        'or else the UI will flicker and be jumpy.
        'This is not a UI glitch, it happens because a single manipulation will fire multiple deltas,
        'so you are recording movements relative to the UI element that is being moved. Not cool! 
        e.ManipulationContainer = Me

        'In ManipulationStarting, you can also set your ManipulationMode to control the manipulations you are allowing.
        'You can select from All | None | Rotate | Translate | Scale | TranslateX | TranslateY.
        'If you don’t override it, the default is All. 
        e.Mode = ManipulationModes.Translate
    End Sub

    Private Sub CefSharpBrowserControl_ManipulationDelta(sender As Object, e As ManipulationDeltaEventArgs)
        Try
            If e.Source Is Nothing Then
                GoTo done
            End If

            If Me.TouchMoveState = 0 Then
                GoTo done
            End If

            'e.DeltaManipulation has the changes 
            'Scale is a delta multiplier; 1.0 is last size,  (so 1.1 == scale 10%, 0.8 = shrink 20%) 
            'Rotate = Rotation, in degrees
            'Pan = Translation, == Translate offset, in Device Independent Pixels 

            'scroll either horizontally or vertically, scrolling in both directions at the same time does not work well
            Dim dblCumulativeX As Double = Math.Abs(e.CumulativeManipulation.Translation.X)
            Dim dblCumulativeY As Double = Math.Abs(e.CumulativeManipulation.Translation.Y)

            Dim intDeltaX = 0
            Dim intDeltaY = 0

            If dblCumulativeX > dblCumulativeY Then
                Dim dblDeltaX As Double = e.DeltaManipulation.Translation.X
                If dblDeltaX <> 0 Then
                    dblDeltaX *= cTouchMoveFactor
                    'round the change up
                    If dblDeltaX > 0 Then
                        dblDeltaX += 0.99
                    ElseIf dblDeltaX < 0 Then
                        dblDeltaX -= 0.99
                    End If
                    intDeltaX = Math.Truncate(dblDeltaX)
                End If
            Else
                Dim dblDeltaY As Double = e.DeltaManipulation.Translation.Y
                If dblDeltaY <> 0 Then
                    dblDeltaY *= cTouchMoveFactor
                    'round the change up
                    If dblDeltaY > 0 Then
                        dblDeltaY += 0.99
                    ElseIf dblDeltaY < 0 Then
                        dblDeltaY -= 0.99
                    End If
                    intDeltaY = Math.Truncate(dblDeltaY)
                End If
            End If

            If (intDeltaX <> 0) Or (intDeltaY <> 0) Then
                Scroll(intDeltaX, intDeltaY)
            End If

            ''we could add code at our ManipulationDelta event handler for inertia.
            ''This is optional, if you run the code at this point, inertia is already working, but you will notice there is no boundaries (the images fly off the screen). 
            ''So, just as an example, I will add code to handle the boundaries and stop the inertia when we reach the boundaries. 
            'If e.IsInertial Then
            '    'check if further scrolling is not possible anymore, if yes:
            '    '/Report that we have gone over our boundary 
            '    e.ReportBoundaryFeedback(e.DeltaManipulation)
            '    'comment out this line to see the Window 'shake' or 'bounce' 
            '    'similar to Win32 Windows when they reach a boundary; this comes for free in .NET 4
            '    e.Complete()
            'End If

        Catch ex As Exception
            LogManager.LogMessage(LogType.Errors, ex)
        End Try
done:
        e.Handled = True
    End Sub

    Private Sub CefSharpBrowserControl_ManipulationInertiaStarting(sender As Object, e As ManipulationInertiaStartingEventArgs)
        Try
            'Decrease the velocity of the Rectangle's movement by 20 inches per second every second.
            '(20 inches * 96 DIPS per inch / 1000ms^2)
            e.TranslationBehavior.DesiredDeceleration = 20.0 * 96.0 / (1000.0 * 1000.0)
        Catch ex As Exception
            LogManager.LogMessage(LogType.Errors, ex)
        End Try
        e.Handled = True
    End Sub

    Private Sub CefSharpBrowserControl_ManipulationCompleted(sender As Object, e As ManipulationCompletedEventArgs)
        Try
            Me.TouchMoveState = 0
        Catch ex As Exception
            LogManager.LogMessage(LogType.Errors, ex)
        End Try
        e.Handled = True
    End Sub`
perlun commented 6 years ago

Would anyone be kind enough to add a PR that provides an example on how to set this up easily? (You an also refer to this issue if you like, to give people more info on what's needed for it.)

That way, we should be able to close this issue.

Clemani commented 6 years ago

I would need to figure out how this works, clone the project, make changes, check in changed project and hope that my spent time was not useless (you merge the changes into CefSharp) ?

My posted implementation with manipulation events works pretty well for me in "competitor" project. Not as smoothly as in WinForms, but good. The posted code is not up to date, i made a few changes. To make it working here, it would require to: 1) Change the Popup to overlay image, otherwise touch scroll does not work in dropdowns. The CEF "popup" is not a normal Windows popup, not in the offscreen version. CEF knows the position and size of the "popup" and handles all sent mouse and keyboard events properly. I don't spend time if you disagree on this point. 2) Try to resolve an issue with broken SendMouseWheelEvent, seems to happen when CefSharp tries to handle Drag&Drop

equimal commented 6 years ago

2018... My solution...

Change "Emulation.setEmitTouchEventsForMouse"

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using CefSharp;
using WebSocket4Net;

namespace YourNamespace {

    public static class CefMobile {

        public const int RemoteDebuggingPort = 8087;

        private static Dictionary<string, WebSocket> _prevList = new Dictionary<string, WebSocket>();

        static CefMobile() {
            Cef.Initialize(new CefSettings {
                CefCommandLineArgs = { },
                UserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A356 Safari/604.1",
                RemoteDebuggingPort = CefMobile.RemoteDebuggingPort
            });
            Task.Run(async () => {
                while (true) {
                    try {
                        using (var client = new HttpClient()) {
                            var response = client.GetAsync($"http://localhost:{CefMobile.RemoteDebuggingPort}/json").Result.Content.ReadAsStringAsync().Result;
                            var json = NetJSON.NetJSON.Deserialize<List<IDictionary<string, string>>>(response);
                            var newList = new Dictionary<string, string>();
                            foreach (var o in json) {
                                o.TryGetValue("id", out var id);
                                o.TryGetValue("webSocketDebuggerUrl", out var webSocketDebuggerUrl);
                                newList.Add(id, webSocketDebuggerUrl);
                            }
                            foreach (var id in newList.Keys.Except(CefMobile._prevList.Keys)) {
                                newList.TryGetValue(id, out var webSocketDebuggerUrl);
                                var ws = new WebSocket(webSocketDebuggerUrl);
                                CefMobile._prevList.Add(id, ws);
                                ws.Closed += (sender, args) => ws.Dispose();
                                ws.Opened += (sender, args) => ws.Send(@"{""id"":0,""method"":""Emulation.setEmitTouchEventsForMouse"",""params"":{""enabled"":true,""configuration"":""mobile""}}");
                                ws.Open();
                            }
                            foreach (var id in CefMobile._prevList.Keys.Except(newList.Keys)) {
                                CefMobile._prevList.TryGetValue(id, out var webSocket);
                                webSocket.Close();
                                CefMobile._prevList.Remove(id);
                            }
                        }
                    } catch (Exception) {
                        // ignored
                    }

                    await Task.Delay(100);
                }
            });
        }

        public static void Init() { }

    }
 }

U need to call CefMobile.Init(); before creating ChromiumWebBrowser

perlun commented 6 years ago

@equimal, thanks for the workaround. A few comments:

equimal commented 6 years ago

@perlun you are right, now I will change something

equimal commented 6 years ago

Update 1.0.0.0.0.1 XD

  1. Disabled auto ping (WebSocket4Net feature, but chrome close connection on "ping")
  2. Reconnect to disconnected socket
  3. Emulation.setDeviceMetricsOverride with mobile: true - hide scrollbars
  4. Other features....
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

using CefSharp;

using WebSocket4Net;

namespace YourNamespace {

    public static class CefMobile {

        public static int RemoteDebuggingPort = 8087;

        private static readonly Dictionary<string, WebSocket> PrevDict = new Dictionary<string, WebSocket>();

        public static void Initialize(CefSettings cefSettings = null) {
            if (cefSettings is null) {
                Cef.Initialize(new CefSettings {
                    UserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A356 Safari/604.1",
                    RemoteDebuggingPort = CefMobile.RemoteDebuggingPort
                });
            } else {
                CefMobile.RemoteDebuggingPort = cefSettings.RemoteDebuggingPort;
                Cef.Initialize(cefSettings);
            }
            Task.Run(async () => {
                while (true) {
                    try {
                        using (var client = new HttpClient()) {
                            var response = client.GetAsync($"http://localhost:{CefMobile.RemoteDebuggingPort}/json").Result.Content.ReadAsStringAsync().Result;
                            var json = NetJSON.NetJSON.Deserialize<List<IDictionary<string, string>>>(response);
                            var NewDict = new Dictionary<string, string>();
                            foreach (var o in json) {
                                o.TryGetValue("id", out var id);
                                o.TryGetValue("webSocketDebuggerUrl", out var webSocketDebuggerUrl);
                                NewDict.Add(id, webSocketDebuggerUrl);
                            }
                            foreach (var id in NewDict.Keys.Except(CefMobile.PrevDict.Keys)) {
                                NewDict.TryGetValue(id, out var webSocketDebuggerUrl);
                                var ws = new WebSocket(webSocketDebuggerUrl) {
                                    EnableAutoSendPing = false
                                };
                                var tcs = new TaskCompletionSource<bool>();
                                ws.Opened += (sender, args) => {
                                    ws.Send(@"{""id"":0,""method"":""Emulation.setEmitTouchEventsForMouse"",""params"":{""enabled"":true,""configuration"":""mobile""}}");
                                    ws.Send(@"{""id"":1,""method"":""Emulation.setTouchEmulationEnabled"",""params"":{""enabled"":true,""maxTouchPoints"":1}}");
                                    ws.Send(@"{""id"":2,""method"":""Emulation.setDeviceMetricsOverride"",""params"":{""width"":0,""height"":0,""deviceScaleFactor"":3,""mobile"":true}}");
                                    CefMobile.PrevDict.Add(id, ws);
                                    tcs.SetResult(true);
                                };
                                ws.MessageReceived += (sender, args) => Console.WriteLine($@"WebSocket Message: {args.Message}");
                                ws.Error += (sender, args) => Console.WriteLine($@"WebSocket Error: {args.Exception.Message}");
                                ws.Closed += (sender, args) => {
                                    CefMobile.PrevDict.Remove(CefMobile.PrevDict.FirstOrDefault(x => x.Value == ws).Key);
                                    ws.Dispose();
                                };
                                ws.Open();
                                await tcs.Task;
                            }
                            foreach (var id in CefMobile.PrevDict.Keys.Except(NewDict.Keys)) {
                                CefMobile.PrevDict.TryGetValue(id, out var webSocket);
                                webSocket.Close();
                            }
                        }
                    } catch (Exception) {
                        // ignored
                    }

                    await Task.Delay(1000);
                }
            });
        }

    }

}
equimal commented 6 years ago

U can use any websocket and json-decoding libraries

amaitland commented 5 years ago

https://bitbucket.org/chromiumembedded/cef/pull-requests/201/multi-touch-support-for-osr/diff

amaitland commented 5 years ago

Once #2663 is resolved it will be possible to implement Touch Support in WPF.

Who's interested in actually helping to implement support? By implement I mean actual programming/debugg, not just testing.

MihaMarkic commented 5 years ago

I'm tempted to help, but not sure about the time I can dedicate and the other problem is that I don't have a touch screen on my workstation - would have to use a laptop or something.

amaitland commented 5 years ago

Once #2663 is resolved it will be possible to implement Touch Support in WPF.

The new CEF API has been added.

For reference WPF will be supporting WM_POINTER optionally in .Net 4.7 https://github.com/dotnet/docs/blob/master/docs/framework/migration-guide/mitigation-pointer-based-touch-and-stylus-support.md

amaitland commented 5 years ago

Experimental support has been added thanks to #2745

CefSharp.Wpf.Experimental.ChromiumWebBrowserWithTouchSupport can be used to replace the current ChromiumWebBrowser, remember that by default the WM_TOUCH implementation will be used, this has significant performance problems and it's worth investigating the WM_POINTER option listed above if you have Windows 10.

Code was added in https://github.com/cefsharp/CefSharp/commit/3d14f198674dba6516276897d384c1cc0c996f92

I will leave this open for until the code has been thoroughly tested at which time it will be enabled by default and ChromiumWebBrowserWithTouchSupport will be removed.

amaitland commented 5 years ago

73.1.130 includes CefSharp.Wpf.Experimental.ChromiumWebBrowserWithTouchSupport, anyone interested can test it out.

Clemani commented 5 years ago

Great news! I found a little issue. Report here or create a new issue?

amaitland commented 5 years ago

You can report it here.

Clemani commented 5 years ago

I have tested on MS Surface Pro 4. I changed the CefSharp.Wpf.Example project to use ChromiumWebBrowserWithTouchSupport. Touch scroll and zoom works fine so far. Maybe not 100% as smoothly as in WinForms... but good in my quick tests.

I encountered one issue:
Marking text with stylus does not work. When i move the pen down, press the right-click button and move the pen then no text gets selected. Sometimes one word gets selected but i cannot select a text area.

When i do this another issue happens: o Enter www.google.com into the address box and press enter.
o Try to select a text with with pen and right click button
o Click into the address box with pen
Then a click with pen into the search box has no effect, the input focus remains in the address box. When i click with my finger long time in the search box then the search box gets focused.

The input focus issue happens also in CefSharp.WinForms.Example. There i can reproduce it by: o Enter www.google.com into the address box and press enter.
o Click with pen into the search box.
The search box seems to get focused, the cursor is blinking in the search box... but pressing keys has no effect.
This input focus issue happens also in CefGlue and cefclient.exe, so i guess it's a CEF or Chromium error. My workaround for this is to watch for WM_PARENTNOTIFY: WM_LBUTTONDOWN, WM_MBUTTONDOWN, WM_RBUTTONDOWN, WM_XBUTTONDOWN, WM_POINTERDOWN and focus the CEF browser window when it's not focused.

amaitland commented 5 years ago

Stylus/Pen support has been improved in #2817 the changes will be in version 75, it's still Experimental.

Anyone testing this out please report back here.

mrBarrelNut commented 5 years ago

Awesome. I switched our system to use the experimental browser with touch support and zooming and scrolling works great.

I was just wondering is it possible to use gestures like "two finger panning" with it?

mrBarrelNut commented 5 years ago

Awesome. I switched our system to use the experimental browser with touch support and zooming and scrolling works great.

I was just wondering is it possible to use gestures like "two finger panning" with it?

Ah, seems to be working fine already. Thanks for great work guys!

andynugent commented 5 years ago

Only for Touch Scrolling Bellow code works for me

  1. Add the Following line in CefSharp.Example => Init() settings.CefCommandLineArgs.Add("touch-events", "1");
  2. Open the Browser Window's Code, Define bellow variables at class level bool IsMouseDown = false; Point? LastSavedPoint = null; IBrowserHost host;
  3. Add Touch events for the Web Browser

    #region Touch Events
    
    private void browser_TouchMove(object sender, TouchEventArgs e)
    {
       if (host != null && IsMouseDown)
       {
           TouchPoint t = e.GetTouchPoint(this);
           Point p = t.Position;
    
           if (!LastSavedPoint.HasValue)
               LastSavedPoint = p;
    
           int x = (int)p.X;
           int y = (int)p.Y;
           int oldX = (int)LastSavedPoint.Value.X;
           int oldy = (int)LastSavedPoint.Value.Y;
    
           host.SendMouseWheelEvent(x, y, 0, y - oldy, CefEventFlags.MiddleMouseButton);
    
           LastSavedPoint = p; //Store the last Point for reference
       }
    }
    
    void browser_TouchDown(object sender, TouchEventArgs e)
    {
       if (host == null)
       {
           IWebBrowser host2 = browser; // **your Browser's  Instance** 
           IBrowser bworser = host2.GetBrowser();
           host = bworser.GetHost(); // Get host from Browser
       }
       IsMouseDown = true;
      // this.Cursor = System.Windows.Input.Cursors.None;
    }
    
    private void browser_TouchLeave(object sender, TouchEventArgs e)
    {
       IsMouseDown = false;
       LastSavedPoint = null;
    }
    
    void browser_TouchUp(object sender, TouchEventArgs e)
    {
       IsMouseDown = false;
       LastSavedPoint = null;
    }
    #endregion

A slightly cutdown / cleaner version of this (thanks @dhpanteon it worked a treat):

private void InitialiseTouchScrolling()
{
    BrowserView.TouchDown += TableBrowserUserControl_TouchDown;
    BrowserView.TouchMove += TableBrowserUserControl_TouchMove;
    BrowserView.TouchLeave += TableBrowserUserControl_TouchUp;
    BrowserView.TouchUp += TableBrowserUserControl_TouchUp;
}

Point? LastSavedPoint = null;

private void TableBrowserUserControl_TouchUp(object sender, System.Windows.Input.TouchEventArgs e)
{
    LastSavedPoint = null;
}

private void TableBrowserUserControl_TouchDown(object sender, System.Windows.Input.TouchEventArgs e)
{
    LastSavedPoint = e.GetTouchPoint(this).Position;
}

private void TableBrowserUserControl_TouchMove(object sender, System.Windows.Input.TouchEventArgs e)
{
    if (null != LastSavedPoint)
    {
        Point p = e.GetTouchPoint(this).Position;
        BrowserView.GetBrowser().GetHost().SendMouseWheelEvent((int)p.X, (int)p.Y, 0, (int)(p.Y - LastSavedPoint.Value.Y), CefEventFlags.MiddleMouseButton);
        LastSavedPoint = p;
    }
}
amaitland commented 5 years ago

Unless there are any further reports of errors between now and the 77 release then the code from CefSharp.Wpf.Experimental.ChromiumWebBrowserWithTouchSupport will be merged into the default ChromiumWebBrowser class.

Anyone who has a few moments please test CefSharp.Wpf.Experimental.ChromiumWebBrowserWithTouchSupport and report back if you experience any problems.

cristiancarli commented 5 years ago

@amaitland can you kindly explain us how to enable ChromiumWebBrowserWithTouchSupport ?

Clemani commented 5 years ago

Sorry amaitland - installing x86 version of Visual C++ runtime helped - i deleted the issue.
I changed namespace from CefSharp.Wpf.Experimental to CefSharp.Wpf in ChromiumWebBrowserWithTouchSupport.cs
Then i replaced ChromiumWebBrowser by ChromiumWebBrowserWithTouchSupport where i thought it makes sense (in XAML and on new statements) in CefSharp.Wpf.Example project.
On my Tablet i cannot scroll or zoom with my fingers. I think in my previous test i did the same and it worked. How can i make it working?

amaitland commented 5 years ago

can you kindly explain us how to enable ChromiumWebBrowserWithTouchSupport ?

@cristiancarli Use ChromiumWebBrowserWithTouchSupport instead of ChromiumWebBrowser in your Xaml or .Net code.

On my Tablet i cannot scroll or zoom with my fingers. I think in my previous test i did the same and it worked. How can i make it working?

@Clemani If you are using a build of master (which I don't recommend for testing, use https://github.com/cefsharp/CefSharp.MinimalExample instead) then you will need to comment out

System.AppContext.SetSwitch("Switch.System.Windows.Input.Stylus.DisableStylusAndTouchSupport", true);

At line https://github.com/cefsharp/CefSharp/blob/master/CefSharp.Wpf.Example/App.xaml.cs#L16

There's a bug in WPF (https://github.com/dotnet/wpf/issues/1323) that I've temp disabled DisableStylusAndTouchSupport to allow for testing of another feature/improvement.

Clemani commented 5 years ago

Thanks amaitland. I tested today with master branch and CefSharp.Wpf.Example.
Touch scroll and zoom seems to work fine.
But with ChromiumWebBrowserWithTouchSupport selecting text with pen does not work anymore, and there is an issue with keyboard input. Please see my comment from May 28 which fully applies also to current master branch. Not an issue, but i miss the "afterburner" effect when i scroll by finger. In the WinForms version when i move the finger and lift it off while i am moving the browser continues to scroll for a while - this does not happen in ChromiumWebBrowserWithTouchSupport.

DelTaGC commented 5 years ago

@amaitland Hi, will the multitouch feature of CefSharp.Wpf.Experimental.ChromiumWebBrowserWithTouchSupport also be available in 77 for CefSharp.OffScreen.ChromiumWebBrowser? For example by injecting fingers events like currently existing SendMouseClickEvent() and SendMouseWheelEvent()...

amaitland commented 5 years ago

But with ChromiumWebBrowserWithTouchSupport selecting text with pen does not work anymore

@Clemani Thanks for the feedback, based on this I'll leave out the Pen/Stylus methods. I don't have a Pen/Stylus so I cannot test this currently so I was wondering if it might be best left as part of the Experimental implementation. Will merge basic touch support into ChromiumWebBrowser

there is an issue with keyboard input.

Can you please clarify which keyboard issue

Not an issue, but i miss the "afterburner" effect when i scroll by finger. In the WinForms version when i move the finger and lift it off while i am moving the browser continues to scroll for a while - this does not happen in ChromiumWebBrowserWithTouchSupport.

How does the CEF Sample application behave? You can download from http://opensource.spotify.com/cefbuilds/cef_binary_77.1.6%2Bga0ea7e6%2Bchromium-77.0.3865.90_windows32_client.tar.bz2

Please test with the following

cefclient --multi-threaded-message-loop --off-screen-rendering-enabled --enable-gpu

For example by injecting fingers events like currently existing SendMouseClickEvent() and SendMouseWheelEvent()...

@DelTaGC The SendTouchEvent method was added in version 73. Look at the ChromiumWebBrowserWithTouchSupport source if you need an example.

amaitland commented 5 years ago

Touch support has been moved from ChromiumWebBrowserWithTouchSupport to ChromiumWebBrowser in commit https://github.com/cefsharp/CefSharp/commit/b31a365dd41585ba24433dc2655dbfa03ea18e1a

Stylus/Pen support is still in ChromiumWebBrowserWithTouchSupport. I'll likely close this issue and create a new one to track adding Stylus/Pen support.

Clemani commented 5 years ago

Can you please clarify which keyboard issue

o For ex. enter www.google.com into the address box and press enter. o Try to select a text on the web page with with pen and right click button o Click into the address box with pen o Then a click with pen into the search box on the web page has no effect, the input focus remains in the address box.
I cannot reproduce this reliable, sometimes the issue happens and sometimes not. When you have no pen then i think you cannot reproduce this issue.

Off-topic: The WinForms keyboard issue on touch devices is described here: https://bitbucket.org/chromiumembedded/cef/issues/1797/windows-touch-does-not-return-focus-to-the

How does the CEF Sample application behave? ...

How can i inject finger events ? Changing and compiling CEF is out of my scope.

amaitland commented 5 years ago

How can i inject finger events ? Changing and compiling CEF is out of my scope.

@Clemani Just download an run cefclient from the link provided with the command line args referenced. If the fling behaviour works there then we can look at implementing it, if not then it's unlikely something CEF supports.

Clemani commented 5 years ago

With this commandline args i cannot do anything in cefclient on a web page, finger and pen does not work at all.

amaitland commented 5 years ago

It appears that Fling scrolling is currently broken in CEF. Relevant issue is https://bitbucket.org/chromiumembedded/cef/issues/2745/osr-fling-scrolling-doesnt-work-in-without

amaitland commented 4 years ago

It appears that Fling scrolling is currently broken in CEF. Relevant issue is https://bitbucket.org/chromiumembedded/cef/issues/2745/osr-fling-scrolling-doesnt-work-in-without

Fling Scrolling should now be resolved upstream

amaitland commented 4 years ago

Touch Support will be part of version 79, Stylus support is still only in the CefSharp.Wpf.Experimental.ChromiumWebBrowserWithTouchSupport class, I've created

3028 to track progress of resolving the final issues, if you experience problems with Stylus please comment on #3028 instead of here.

Anyone experiencing problems with Touch Support in version 79 or above please open a new issue using the Bug Report Template, please make sure to include a detailed list of steps to reproduce the problem you are seeing.

amaitland commented 4 years ago

There is no default virtual keyboard implementation as WPF doesn't provide an out of the box solution that works on all supported operating systems. If you require a virtual keyboard when using your touch screen please read OnScreen Virtual Keyboard. There's some additional information in #1736