diff --git a/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs b/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs index d8da8eca14f4..a59a8e3a2346 100644 --- a/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs +++ b/src/Uno.UI/Runtime/BrowserPointerInputSource.wasm.cs @@ -349,7 +349,7 @@ private enum HtmlPointerEvent : byte } [Flags] - private enum HtmlPointerButtonsState + internal enum HtmlPointerButtonsState { // https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#Determining_button_states diff --git a/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.wasm.cs b/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.wasm.cs index 61eae35043e1..a77c7e999089 100644 --- a/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.wasm.cs +++ b/src/Uno.UI/UI/Xaml/DragDrop/DragDropExtension.wasm.cs @@ -33,6 +33,7 @@ using NativeMethods = __Windows.ApplicationModel.DataTransfer.DragDrop.Core.DragDropExtension.NativeMethods; using System.Runtime.InteropServices.JavaScript; using Uno.UI.Runtime; +using _HtmlPointerButtonsState = Uno.UI.Runtime.BrowserPointerInputSource.HtmlPointerButtonsState; // As IDragDropExtension is internal, the generated registration cannot be used. // [assembly: ApiExtension(typeof(Windows.ApplicationModel.DataTransfer.DragDrop.Core.IDragDropExtension), typeof(Windows.ApplicationModel.DataTransfer.DragDrop.Core.DragDropExtension))] @@ -390,16 +391,16 @@ public NativeDrop(DragDropExtensionEventArgs args) var position = new Point(_args.x, _args.y); var modifier = DragDropModifiers.None; - var buttons = (WindowManagerInterop.HtmlPointerButtonsState)_args.buttons; - if (buttons.HasFlag(WindowManagerInterop.HtmlPointerButtonsState.Left)) + var buttons = (_HtmlPointerButtonsState)_args.buttons; + if (buttons.HasFlag(_HtmlPointerButtonsState.Left)) { modifier |= DragDropModifiers.LeftButton; } - if (buttons.HasFlag(WindowManagerInterop.HtmlPointerButtonsState.Middle)) + if (buttons.HasFlag(_HtmlPointerButtonsState.Middle)) { modifier |= DragDropModifiers.MiddleButton; } - if (buttons.HasFlag(WindowManagerInterop.HtmlPointerButtonsState.Right)) + if (buttons.HasFlag(_HtmlPointerButtonsState.Right)) { modifier |= DragDropModifiers.RightButton; } @@ -466,7 +467,7 @@ private struct DragDropExtensionEventArgs public override string ToString() { return $"[{eventName}] {timestamp:F0} @({x:F2},{y:F2})" - + $" | buttons: {(WindowManagerInterop.HtmlPointerButtonsState)buttons}" + + $" | buttons: {(_HtmlPointerButtonsState)buttons}" + $" | modifiers: {string.Join(", ", GetModifiers(this))}" + $" | allowed: {allowedOperations} ({ToDataPackageOperation(allowedOperations)})" + $" | accepted: {acceptedOperation}" diff --git a/src/Uno.UI/UI/Xaml/Window/WindowManagerInterop.wasm.cs b/src/Uno.UI/UI/Xaml/Window/WindowManagerInterop.wasm.cs index b8a8938d5f74..440be9a4bae4 100644 --- a/src/Uno.UI/UI/Xaml/Window/WindowManagerInterop.wasm.cs +++ b/src/Uno.UI/UI/Xaml/Window/WindowManagerInterop.wasm.cs @@ -140,27 +140,8 @@ internal static void SetPointerEvents(IntPtr htmlId, bool enabled) NativeMethods.SetPointerEvents(htmlId, enabled); } - [TSInteropMessage] - [StructLayout(LayoutKind.Sequential, Pack = 4)] - private struct WindowManagerSetPointerEventsParams - { - public IntPtr HtmlId; - - public bool Enabled; - } - #endregion - internal static void SetPointerCapture(IntPtr htmlId, uint pointerId) - { - NativeMethods.SetPointerCapture(htmlId, pointerId); - } - - internal static void ReleasePointerCapture(IntPtr htmlId, uint pointerId) - { - NativeMethods.ReleasePointerCapture(htmlId, pointerId); - } - #region MeasureView internal static Size MeasureView(IntPtr htmlId, Size availableSize, bool measureContent) { @@ -771,25 +752,6 @@ private struct WindowManagerRegisterEventOnViewParams } #endregion - #region registerPointerEventsOnView - internal static void RegisterPointerEventsOnView(IntPtr htmlId) - { - var parms = new WindowManagerRegisterPointerEventsOnViewParams() - { - HtmlId = htmlId, - }; - - TSInteropMarshaller.InvokeJS("Uno:registerPointerEventsOnView", parms); - } - - [TSInteropMessage] - [StructLayout(LayoutKind.Sequential, Pack = 4)] - private struct WindowManagerRegisterPointerEventsOnViewParams - { - public IntPtr HtmlId; - } - #endregion - #region GetBBox internal static Rect GetBBox(IntPtr htmlId) @@ -1057,33 +1019,6 @@ internal static bool GetIsOverflowing(IntPtr htmlId) internal static void SetIsFocusable(IntPtr htmlId, bool isFocusable) => NativeMethods.SetIsFocusable(htmlId, isFocusable); - #region Pointers - [Flags] - internal enum HtmlPointerButtonsState - { - // https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events#Determining_button_states - - None = 0, - Left = 1, - Middle = 4, - Right = 2, - X1 = 8, - X2 = 16, - Eraser = 32, - } - - internal enum HtmlPointerButtonUpdate - { - None = -1, - Left = 0, - Middle = 1, - Right = 2, - X1 = 3, - X2 = 4, - Eraser = 5 - } - #endregion - internal static partial class NativeMethods { [JSImport("globalThis.Uno.UI.WindowManager.current.arrangeElementNativeFast")] @@ -1138,9 +1073,6 @@ internal static partial void ArrangeElement( [JSImport("globalThis.Uno.UI.WindowManager.current.rawPixelsToBase64EncodeImage")] internal static partial string RawPixelsToBase64EncodeImage(IntPtr data, int width, int height); - [JSImport("globalThis.Uno.UI.WindowManager.current.releasePointerCapture")] - internal static partial void ReleasePointerCapture(IntPtr htmlId, double pointerId); - [JSImport("globalThis.Uno.UI.WindowManager.current.selectInputRange")] internal static partial void SelectInputRange(IntPtr htmlId, int start, int length); @@ -1156,10 +1088,7 @@ internal static partial void ArrangeElement( [JSImport("globalThis.Uno.UI.WindowManager.current.setCornerRadius")] internal static partial void SetCornerRadius(IntPtr htmlId, float topLeftX, float topLeftY, float topRightX, float topRightY, float bottomRightX, float bottomRightY, float bottomLeftX, float bottomLeftY); - [JSImport("globalThis.Uno.UI.WindowManager.current.setPointerCapture")] - internal static partial void SetPointerCapture(IntPtr htmlId, double pointerId); - - [JSImport("globalThis.Uno.UI.WindowManager.current.setPointerEventsNativeFast")] + [JSImport("globalThis.Uno.UI.WindowManager.current.setPointerEvents")] internal static partial void SetPointerEvents(IntPtr htmlId, bool enabled); [JSImport("globalThis.Uno.UI.WindowManager.current.setPropertyNativeFast")] diff --git a/src/Uno.UI/ts/MonoSupport.ts b/src/Uno.UI/ts/MonoSupport.ts index e532ae224dc7..faa7ad6c07bd 100644 --- a/src/Uno.UI/ts/MonoSupport.ts +++ b/src/Uno.UI/ts/MonoSupport.ts @@ -32,7 +32,6 @@ namespace MonoSupport { jsCallDispatcher.registerScope("UnoStatic_Windows_Storage_StorageFolder", Windows.Storage.StorageFolder); jsCallDispatcher.registerScope("UnoStatic_Windows_Storage_ApplicationDataContainer", Windows.Storage.ApplicationDataContainer); jsCallDispatcher.registerScope("UnoStatic_Windows_ApplicationModel_DataTransfer_DragDrop_Core_DragDropExtension", Windows.ApplicationModel.DataTransfer.DragDrop.Core.DragDropExtension); - jsCallDispatcher.registerScope("UnoStatic_Windows_UI_Xaml_UIElement", Microsoft.UI.Xaml.UIElement); jsCallDispatcher._isUnoRegistered = true; } diff --git a/src/Uno.UI/ts/WindowManager.ts b/src/Uno.UI/ts/WindowManager.ts index 0108954e83df..f91713d1a16c 100644 --- a/src/Uno.UI/ts/WindowManager.ts +++ b/src/Uno.UI/ts/WindowManager.ts @@ -821,19 +821,7 @@ namespace Uno.UI { this.setAsArranged(element); } - private setPointerEvents(htmlId: number, enabled: boolean) { - const element = this.getView(htmlId); - element.style.pointerEvents = enabled ? "auto" : "none"; - } - - public setPointerEventsNative(pParams: number): boolean { - const params = WindowManagerSetPointerEventsParams.unmarshal(pParams); - this.setPointerEvents(params.HtmlId, params.Enabled); - - return true; - } - - public setPointerEventsNativeFast(htmlId: number, enabled: boolean) { + public setPointerEvents(htmlId: number, enabled: boolean) { this.getView(htmlId).style.pointerEvents = enabled ? "auto" : "none"; } @@ -1454,14 +1442,6 @@ namespace Uno.UI { element.style.overflow = "hidden"; // overflow: hidden is required here because the clipping can't do its job when it's non-rectangular. } - public setPointerCapture(viewId: number, pointerId: number): void { - this.getView(viewId).setPointerCapture(pointerId); - } - - public releasePointerCapture(viewId: number, pointerId: number): void { - this.getView(viewId).releasePointerCapture(pointerId); - } - public focusView(elementId: number): void { const element = this.getView(elementId); diff --git a/src/Uno.UI/ts/Windows/UI/Xaml/UIElement.Pointers.ts b/src/Uno.UI/ts/Windows/UI/Xaml/UIElement.Pointers.ts deleted file mode 100644 index 5e6fe81d25da..000000000000 --- a/src/Uno.UI/ts/Windows/UI/Xaml/UIElement.Pointers.ts +++ /dev/null @@ -1,351 +0,0 @@ -namespace Microsoft.UI.Xaml { - import WindowManager = Uno.UI.WindowManager; - import HtmlEventDispatchResult = Uno.UI.HtmlEventDispatchResult; - import PointerDeviceType = Windows.Devices.Input.PointerDeviceType; - - export enum NativePointerEvent { - pointerover = 1, - pointerout = 1 << 1, - pointerdown = 1 << 2, - pointerup = 1 << 3, - pointercancel = 1 << 4, - - // Optional pointer events - pointermove = 1 << 5, - wheel = 1 << 6, - } - - export class UIElement_Pointers { - - private static _dispatchPointerEventMethod: any; - private static _dispatchPointerEventArgs: number; - private static _dispatchPointerEventResult: number; - private static _isManualyDispatchingOut: boolean = false; - - private static ensurePointersInit(): void { - if (!UIElement._dispatchPointerEventMethod) { - if ((globalThis).DotnetExports !== undefined) { - UIElement._dispatchPointerEventMethod = (globalThis).DotnetExports.UnoUI.Microsoft.UI.Xaml.UIElement.OnNativePointerEvent; - } else { - UIElement._dispatchPointerEventMethod = (Module).mono_bind_static_method("[Uno.UI] Microsoft.UI.Xaml.UIElement:OnNativePointerEvent"); - } - - document.getRootNode().addEventListener("pointerover", UIElement_Pointers.onRootPointerOverDispatching, { capture: true, passive: true }); - } - } - - public static setPointerEventArgs(pArgs: number): void { - UIElement_Pointers.ensurePointersInit(); - UIElement._dispatchPointerEventArgs = pArgs; - } - - public static setPointerEventResult(pArgs: number): void { - UIElement_Pointers.ensurePointersInit(); - UIElement._dispatchPointerEventResult = pArgs; - } - - public static subscribePointerEvents(pParams: number): void { - const params = Microsoft.UI.Xaml.NativePointerSubscriptionParams.unmarshal(pParams); - const element = WindowManager.current.getView(params.HtmlId); - - if (params.Events & NativePointerEvent.pointerover) { - element.addEventListener("pointerover", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointerout) { - element.addEventListener("pointerout", UIElement.onPointerOutReceived); - } - if (params.Events & NativePointerEvent.pointerdown) { - element.addEventListener("pointerdown", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointerup) { - element.addEventListener("pointerup", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointercancel) { - element.addEventListener("pointercancel", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointermove) { - element.addEventListener("pointermove", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.wheel) { - element.addEventListener("wheel", UIElement.onPointerEventReceived); - } - } - - public static unSubscribePointerEvents(pParams: number): void { - const params = Microsoft.UI.Xaml.NativePointerSubscriptionParams.unmarshal(pParams); - const element = WindowManager.current.getView(params.HtmlId); - - if (!element) { - return; - } - - if (params.Events & NativePointerEvent.pointerover) { - element.removeEventListener("pointerover", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointerout) { - element.removeEventListener("pointerout", UIElement.onPointerOutReceived); - } - if (params.Events & NativePointerEvent.pointerdown) { - element.removeEventListener("pointerdown", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointerup) { - element.removeEventListener("pointerup", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointercancel) { - element.removeEventListener("pointercancel", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.pointermove) { - element.removeEventListener("pointermove", UIElement.onPointerEventReceived); - } - if (params.Events & NativePointerEvent.wheel) { - element.removeEventListener("wheel", UIElement.onPointerEventReceived); - } - } - - private static onPointerEventReceived(evt: PointerEvent): void { - UIElement.dispatchPointerEvent(evt.currentTarget as HTMLElement | SVGElement, evt); - } - - private static onRootPointerOverDispatching(evt: PointerEvent): void { - const target = evt.target as HTMLElement | SVGElement; - if (!target) { - return; - } - - if (target.hasPointerCapture(evt.pointerId)) { - return; - } - - let prevElt: Element = null; - for (let elt of document.elementsFromPoint(evt.clientX, evt.clientY)) { - if (!elt.contains(target) // The elt is under the target (not a parent!) - && !elt.contains(prevElt) // The elt is not a parent of the previous element (so it has already been processed!) - ) { - // The element is under the target (not a parent!), with chromium browsers, if the target just popped up, - // it happens that the pointerout event is not raised on those elemnts under. - // Here we ensure to raise it manually before the pointerover event is being dispatched. - try { - UIElement._isManualyDispatchingOut = true; - elt.dispatchEvent(new PointerEvent("pointerout", evt)); - } - finally { - UIElement._isManualyDispatchingOut = false; - } - } - prevElt = elt; - } - } - - private static onPointerOutReceived(evt: PointerEvent): void { - if (UIElement._isManualyDispatchingOut) { - UIElement.onPointerEventReceived(evt); - return; - } - - const element = evt.currentTarget as HTMLElement | SVGElement; - - // When we capture the pointer, browser will raise an "out" event on nested elements - // and then an "over" on the element that captured the pointer. - // But those events will be raise right BEFORE the NEXT pointer event (e.g. a move). - // Note: We don't filter out the "over" event because it's handled in managed by tracking the IsOver state. - - // Here we filter the "out" event that is being raised after capture or release - // If the relatedTarget (the element that capture or release the pointer) is a child of (or is) the current element, - // it means pointer might not leaving the current element! - let elt = evt.relatedTarget as HTMLElement | SVGElement; - if (elt - && element.contains(elt) - && ( - // on capture, we just check if it has the the capture - elt.hasPointerCapture(evt.pointerId) - // on release, the target is the element itself - || evt.target == element) - ) - { - evt.stopPropagation(); - return; - } - - // Finally, here we filter out the events that are being raised when the pointer is leaving a nested element (which is bubbling in browser) - const targetBounds = (evt.target as HTMLElement | SVGElement).getBoundingClientRect(); - elt = evt.target as HTMLElement | SVGElement; - while (elt && elt != element) { - if (elt.style.pointerEvents != "none") { - const bounds = elt.getBoundingClientRect(); - if ( - (evt.clientY > bounds.top && (Math.abs(targetBounds.top - bounds.top) > 1)) - && (evt.clientY < bounds.bottom && (Math.abs(targetBounds.bottom - bounds.bottom) > 1)) - && (evt.clientX > bounds.left && (Math.abs(targetBounds.left - bounds.left) > 1)) - && (evt.clientX < bounds.right && (Math.abs(targetBounds.right - bounds.right) > 1)) - ) { - // There is child that is still under the pointer (and which will raise pointer events), so we should not propagate the event. - // Note: If the child is sharing the bounds with the target, we consider that the pointer is also leaving the intermediate child. - evt.stopPropagation(); - return; - } - } - elt = elt.parentElement; - } - - UIElement.onPointerEventReceived(evt); - } - - private static dispatchPointerEvent(element: HTMLElement | SVGElement, evt: PointerEvent): void { - if (!evt) { - return; - } - - const args = UIElement.toNativePointerEventArgs(evt); - args.HtmlId = Number(element.getAttribute("XamlHandle")); - - args.marshal(UIElement._dispatchPointerEventArgs); - UIElement._dispatchPointerEventMethod(); - const response = Microsoft.UI.Xaml.NativePointerEventResult.unmarshal(UIElement._dispatchPointerEventResult); - - if (response.Result & HtmlEventDispatchResult.StopPropagation) { - evt.stopPropagation(); - } - if (response.Result & HtmlEventDispatchResult.PreventDefault) { - evt.preventDefault(); - } - } - - //#region WheelLineSize - private static _wheelLineSize: number = undefined; - private static get wheelLineSize(): number { - // In web browsers, scroll might happen by pixels, line or page. - // But WinUI works only with pixels, so we have to convert it before send the value to the managed code. - // The issue is that there is no easy way get the "size of a line", instead we have to determine the CSS "line-height" - // defined in the browser settings. - // https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line - if (this._wheelLineSize == undefined) { - const el = document.createElement("div"); - el.style.fontSize = "initial"; - el.style.display = "none"; - document.body.appendChild(el); - const fontSize = window.getComputedStyle(el).fontSize; - document.body.removeChild(el); - - this._wheelLineSize = fontSize ? parseInt(fontSize) : 16; /* 16 = The current common default font size */ - - // Based on observations, even if the event reports 3 lines (the settings of windows), - // the browser will actually scroll of about 6 lines of text. - this._wheelLineSize *= 2.0; - } - - return this._wheelLineSize; - } - //#endregion - - //#region Helpers - private static toNativePointerEventArgs(evt: PointerEvent | WheelEvent): Microsoft.UI.Xaml.NativePointerEventArgs { - let src = evt.target as HTMLElement | SVGElement; - if (src instanceof SVGElement) { - // The XAML SvgElement are UIElement in Uno (so they have a XamlHandle), - // but as on WinUI they are not part of the visual tree, they should not be used as OriginalElement. - // Instead we should use the actual parent which is the XAML Shape. - const shape = (src as any).ownerSVGElement; - if (shape) { - src = shape; - } - } else if (src instanceof HTMLImageElement) { - // Same as above for images ( == HtmlImage, we use the parent
which is the XAML Image). - src = src.parentElement; - } - - let srcHandle = "0"; - while (src) { - const handle = src.getAttribute("XamlHandle"); - if (handle) { - srcHandle = handle; - break; - } - - src = src.parentElement; - } - - let pointerId: number, pointerType: PointerDeviceType, pressure: number; - let wheelDeltaX: number, wheelDeltaY: number; - if (evt instanceof WheelEvent) { - pointerId = (evt as any).mozInputSource ? 0 : 1; // Try to match the mouse pointer ID 0 for FF, 1 for others - pointerType = PointerDeviceType.Mouse; - pressure = 0.5; // like WinUI - wheelDeltaX = evt.deltaX; - wheelDeltaY = evt.deltaY; - - switch (evt.deltaMode) { - case WheelEvent.DOM_DELTA_LINE: // Actually this is supported only by FF - const lineSize = UIElement.wheelLineSize; - wheelDeltaX *= lineSize; - wheelDeltaY *= lineSize; - break; - case WheelEvent.DOM_DELTA_PAGE: - wheelDeltaX *= document.documentElement.clientWidth; - wheelDeltaY *= document.documentElement.clientHeight; - break; - } - } else { - pointerId = evt.pointerId; - pointerType = UIElement.toPointerDeviceType(evt.pointerType); - pressure = evt.pressure; - wheelDeltaX = 0; - wheelDeltaY = 0; - } - - const args = new Microsoft.UI.Xaml.NativePointerEventArgs(); - args.Event = UIElement.toNativeEvent(evt.type); - args.pointerId = pointerId; - args.x = evt.clientX; - args.y = evt.clientY; - args.ctrl = evt.ctrlKey; - args.shift = evt.shiftKey; - args.hasRelatedTarget = evt.relatedTarget !== null; - args.buttons = evt.buttons; - args.buttonUpdate = evt.button; - args.deviceType = pointerType; - args.srcHandle = Number(srcHandle); - args.timestamp = evt.timeStamp; - args.pressure = pressure; - args.wheelDeltaX = wheelDeltaX; - args.wheelDeltaY = wheelDeltaY; - - return args; - } - - private static toNativeEvent(eventName: string): NativePointerEvent { - switch (eventName) { - case "pointerover": - return NativePointerEvent.pointerover; - case "pointerout": - return NativePointerEvent.pointerout; - case "pointerdown" : - return NativePointerEvent.pointerdown; - case "pointerup" : - return NativePointerEvent.pointerup; - case "pointercancel" : - return NativePointerEvent.pointercancel; - case "pointermove" : - return NativePointerEvent.pointermove; - case "wheel": - return NativePointerEvent.wheel; - default: - return undefined; - } - } - - private static toPointerDeviceType(type: string): PointerDeviceType { - switch (type) { - case "touch": - return PointerDeviceType.Touch; - case "pen": - // Note: As of 2019-11-28, once pen pressed events pressed/move/released are reported as TOUCH on Firefox - // https://bugzilla.mozilla.org/show_bug.cgi?id=1449660 - return PointerDeviceType.Pen; - case "mouse": - default: - return PointerDeviceType.Mouse; - } - } - //#endregion - } -} diff --git a/src/Uno.UI/ts/Windows/UI/Xaml/UIElement.ts b/src/Uno.UI/ts/Windows/UI/Xaml/UIElement.ts deleted file mode 100644 index 0b14b6bf5125..000000000000 --- a/src/Uno.UI/ts/Windows/UI/Xaml/UIElement.ts +++ /dev/null @@ -1,7 +0,0 @@ -/// - -namespace Microsoft.UI.Xaml { - export class UIElement extends Microsoft.UI.Xaml.UIElement_Pointers { - - } -}