From 03f5a4d0f97e2a383ae57c0f5c0e8c28aab2aaa8 Mon Sep 17 00:00:00 2001 From: Elias Holzer Date: Thu, 11 Apr 2024 17:35:27 +0200 Subject: [PATCH] Adds `SendNotification` operation and forwards VL.CEF from sub packages --- Directory.Build.props | 2 +- VL.CEF.Skia/VL.CEF.Skia.vl | 2 +- VL.CEF.Stride/VL.CEF.Stride.vl | 2 +- VL.CEF/src/WebBrowser.InputHandling.cs | 213 +++++++++++++++++++++++++ 4 files changed, 216 insertions(+), 3 deletions(-) create mode 100644 VL.CEF/src/WebBrowser.InputHandling.cs diff --git a/Directory.Build.props b/Directory.Build.props index 26b8f48..13ee287 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -11,7 +11,7 @@ $([System.DateTime]::Now.ToString('yyyy')) - 0.5.5 + 0.5.6 vvvv group diff --git a/VL.CEF.Skia/VL.CEF.Skia.vl b/VL.CEF.Skia/VL.CEF.Skia.vl index a6c9d55..52ecbea 100644 --- a/VL.CEF.Skia/VL.CEF.Skia.vl +++ b/VL.CEF.Skia/VL.CEF.Skia.vl @@ -114,5 +114,5 @@ - + \ No newline at end of file diff --git a/VL.CEF.Stride/VL.CEF.Stride.vl b/VL.CEF.Stride/VL.CEF.Stride.vl index a621ccb..95c58ae 100644 --- a/VL.CEF.Stride/VL.CEF.Stride.vl +++ b/VL.CEF.Stride/VL.CEF.Stride.vl @@ -115,5 +115,5 @@ - + \ No newline at end of file diff --git a/VL.CEF/src/WebBrowser.InputHandling.cs b/VL.CEF/src/WebBrowser.InputHandling.cs new file mode 100644 index 0000000..ca6cc2d --- /dev/null +++ b/VL.CEF/src/WebBrowser.InputHandling.cs @@ -0,0 +1,213 @@ +using Stride.Core.Mathematics; +using System; +using System.Diagnostics; +using VL.Lib.IO; +using VL.Lib.IO.Notifications; +using Xilium.CefGlue; + +namespace VL.CEF +{ + partial class WebBrowser + { + CefEventFlags mouseModifiers; + + public bool SendNotification(INotification notification) + { + if (notification is MouseNotification mouseNotification) + { + HandleMouseNotification(mouseNotification); + return true; + } + else if (notification is KeyNotification keyNotification) + { + HandleKeyNotification(keyNotification); + return true; + } + else if (notification is TouchNotification touchNotification) + { + HandleTouchNotification(touchNotification); + return true; + } + return false; + } + + private void HandleTouchNotification(TouchNotification n) + { + var position = n.Position.DeviceToLogical(ScaleFactor); + var touchEvent = new CefTouchEvent() + { + Id = n.Id, + Modifiers = GetModifiers(n), + PointerType = CefPointerType.Touch, + Pressure = 1f, + RadiusX = n.ContactArea.X, + RadiusY = n.ContactArea.Y, + RotationAngle = 0, + Type = GetTouchType(n.Kind), + X = position.X, + Y = position.Y + }; + BrowserHost.SendTouchEvent(touchEvent); + + CefTouchEventType GetTouchType(TouchNotificationKind kind) + { + switch (kind) + { + case TouchNotificationKind.TouchDown: + return CefTouchEventType.Pressed; + case TouchNotificationKind.TouchUp: + return CefTouchEventType.Released; + case TouchNotificationKind.TouchMove: + return CefTouchEventType.Moved; + default: + return CefTouchEventType.Cancelled; + } + } + } + + private void HandleKeyNotification(KeyNotification n) + { + var keyEvent = new CefKeyEvent() + { + Modifiers = GetModifiers(n) + }; + switch (n.Kind) + { + case KeyNotificationKind.KeyDown: + var keyDown = n as KeyDownNotification; + keyEvent.EventType = CefKeyEventType.KeyDown; + keyEvent.WindowsKeyCode = (int)keyDown.KeyCode; + keyEvent.NativeKeyCode = (int)keyDown.KeyCode; + break; + case KeyNotificationKind.KeyPress: + var keyPress = n as KeyPressNotification; + keyEvent.EventType = CefKeyEventType.Char; + keyEvent.Character = keyPress.KeyChar; + keyEvent.UnmodifiedCharacter = keyPress.KeyChar; + keyEvent.WindowsKeyCode = (int)keyPress.KeyChar; + keyEvent.NativeKeyCode = (int)keyPress.KeyChar; + break; + case KeyNotificationKind.KeyUp: + var keyUp = n as KeyUpNotification; + keyEvent.EventType = CefKeyEventType.KeyUp; + keyEvent.WindowsKeyCode = (int)keyUp.KeyCode; + keyEvent.NativeKeyCode = (int)keyUp.KeyCode; + break; + default: + break; + } + BrowserHost.SendKeyEvent(keyEvent); + } + + int clickCount = 1; + MouseButtons? lastButton; + Vector2 lastPosition; + Stopwatch stopwatch = Stopwatch.StartNew(); + + private void HandleMouseNotification(MouseNotification n) + { + if (n is MouseButtonNotification buttonNotification) + { + var position = n.Position; + var delta = lastPosition - position; + var deltaTime = stopwatch.ElapsedMilliseconds; + stopwatch.Restart(); + + if (n is MouseDownNotification) + { + if (buttonNotification.Buttons == lastButton && + Math.Abs(delta.X) < Mouse.DoubleClickSize.Width / 2 && + Math.Abs(delta.Y) < Mouse.DoubleClickSize.Height / 2 && + deltaTime < Mouse.DoubleClickTime) + { + clickCount++; + } + else + { + clickCount = 1; + } + } + else if (buttonNotification.Buttons != lastButton) + { + clickCount = 1; + } + + lastButton = buttonNotification.Buttons; + lastPosition = position; + + if (n is MouseDownNotification mouseDown) + mouseModifiers |= ToCefEventFlags(mouseDown.Buttons); + else if (n is MouseUpNotification mouseUp) + mouseModifiers &= ~ToCefEventFlags(mouseUp.Buttons); + } + + { + var position = n.Position.DeviceToLogical(ScaleFactor); + var mouseEvent = new CefMouseEvent((int)position.X, (int)position.Y, GetModifiers(n)); + var browserHost = BrowserHost; + switch (n.Kind) + { + case MouseNotificationKind.MouseDown: + var mouseDown = n as MouseDownNotification; + browserHost.SendMouseClickEvent(mouseEvent, GetMouseButtonType(mouseDown.Buttons), mouseUp: false, clickCount: clickCount); + break; + case MouseNotificationKind.MouseUp: + var mouseUp = n as MouseUpNotification; + browserHost.SendMouseClickEvent(mouseEvent, GetMouseButtonType(mouseUp.Buttons), mouseUp: true, clickCount: clickCount); + break; + case MouseNotificationKind.MouseMove: + browserHost.SendMouseMoveEvent(mouseEvent, mouseLeave: false); + break; + case MouseNotificationKind.MouseWheel: + var mouseWheel = n as MouseWheelNotification; + browserHost.SendMouseWheelEvent(mouseEvent, 0, mouseWheel.WheelDelta); + break; + case MouseNotificationKind.MouseHorizontalWheel: + var mouseHWheel = n as MouseHorizontalWheelNotification; + browserHost.SendMouseWheelEvent(mouseEvent, mouseHWheel.WheelDelta, 0); + break; + case MouseNotificationKind.DeviceLost: + browserHost.SendMouseMoveEvent(mouseEvent, mouseLeave: true); + break; + } + } + + CefMouseButtonType GetMouseButtonType(MouseButtons buttons) + { + if ((buttons & MouseButtons.Left) != 0) + return CefMouseButtonType.Left; + if ((buttons & MouseButtons.Middle) != 0) + return CefMouseButtonType.Middle; + if ((buttons & MouseButtons.Right) != 0) + return CefMouseButtonType.Right; + return default; + } + + static CefEventFlags ToCefEventFlags(MouseButtons buttons) + { + switch (buttons) + { + case MouseButtons.Left: + return CefEventFlags.LeftMouseButton; + case MouseButtons.Middle: + return CefEventFlags.MiddleMouseButton; + case MouseButtons.Right: + return CefEventFlags.RightMouseButton; + } + return default; + } + } + + CefEventFlags GetModifiers(NotificationBase n) + { + var result = CefEventFlags.None; + if (n.AltKey) + result |= CefEventFlags.AltDown | CefEventFlags.IsLeft; + if (n.ShiftKey) + result |= CefEventFlags.ShiftDown | CefEventFlags.IsLeft; + if (n.CtrlKey) + result |= CefEventFlags.ControlDown | CefEventFlags.IsLeft; + return result | mouseModifiers; + } + } +}