diff --git a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Android/SKTouchHandler.cs b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Android/SKTouchHandler.cs index 074c5ef8c4..0976a89f4f 100644 --- a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Android/SKTouchHandler.cs +++ b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Android/SKTouchHandler.cs @@ -25,9 +25,11 @@ public void SetEnabled(View view, bool enableTouchEvents) if (view != null && view.Handle != IntPtr.Zero) { view.Touch -= OnTouch; + view.GenericMotion -= OnGenericMotion; if (enableTouchEvents) { view.Touch += OnTouch; + view.GenericMotion += OnGenericMotion; } } } @@ -51,43 +53,31 @@ private void OnTouch(object? sender, View.TouchEventArgs e) if (evt == null) return; - var pointer = evt.ActionIndex; - - var id = evt.GetPointerId(pointer); - var coords = scalePixels(evt.GetX(pointer), evt.GetY(pointer)); - - var toolType = evt.GetToolType(pointer); - - var deviceType = GetDeviceType(toolType); - - var pressure = evt.GetPressure(pointer); - - var button = GetButton(evt, toolType); + var count = evt.PointerCount; switch (evt.ActionMasked) { case MotionEventActions.Down: case MotionEventActions.PointerDown: { - var args = new SKTouchEventArgs(id, SKTouchAction.Pressed, button, deviceType, coords, true, 0, pressure); + for (var pointer = 0; pointer < count; pointer++) + { + var args = CreateTouchEventArgs(SKTouchAction.Pressed, true, evt, pointer); - onTouchAction(args); - e.Handled = args.Handled; + onTouchAction(args); + e.Handled |= args.Handled; + } break; } case MotionEventActions.Move: { - var count = evt.PointerCount; - for (pointer = 0; pointer < count; pointer++) + for (var pointer = 0; pointer < count; pointer++) { - id = evt.GetPointerId(pointer); - coords = scalePixels(evt.GetX(pointer), evt.GetY(pointer)); - - var args = new SKTouchEventArgs(id, SKTouchAction.Moved, button, deviceType, coords, true, 0, pressure); + var args = CreateTouchEventArgs(SKTouchAction.Moved, true, evt, pointer); onTouchAction(args); - e.Handled = e.Handled || args.Handled; + e.Handled |= args.Handled; } break; } @@ -95,16 +85,100 @@ private void OnTouch(object? sender, View.TouchEventArgs e) case MotionEventActions.Up: case MotionEventActions.PointerUp: { - var args = new SKTouchEventArgs(id, SKTouchAction.Released, button, deviceType, coords, false, 0, pressure); + for (var pointer = 0; pointer < count; pointer++) + { + var args = CreateTouchEventArgs(SKTouchAction.Released, false, evt, pointer); + + onTouchAction(args); + e.Handled |= args.Handled; + } + break; + } + + case MotionEventActions.Cancel: + { + for (var pointer = 0; pointer < count; pointer++) + { + var args = CreateTouchEventArgs(SKTouchAction.Cancelled, false, evt, pointer); + + onTouchAction(args); + e.Handled |= args.Handled; + } + break; + } + } + } + + private void OnGenericMotion(object sender, View.GenericMotionEventArgs e) + { + if (onTouchAction == null || scalePixels == null) + return; + + var evt = e.Event; + if (evt == null) + return; + + if (!evt.IsFromSource(InputSourceType.Mouse)) + return; + + var pointer = evt.ActionIndex; + + var id = evt.GetPointerId(pointer); + var coords = scalePixels?.Invoke(evt.GetX(pointer), evt.GetY(pointer)) ?? + new SKPoint(evt.GetX(pointer), evt.GetY(pointer)); + + var toolType = evt.GetToolType(pointer); + var deviceType = GetDeviceType(toolType); + var button = GetButton(evt.ActionButton, toolType); + var inContact = button != SKMouseButton.Unknown; + + switch (evt.Action) + { + case MotionEventActions.ButtonPress: + { + var args = new SKTouchEventArgs(id, SKTouchAction.Pressed, button, deviceType, coords, inContact); onTouchAction(args); e.Handled = args.Handled; break; } + case MotionEventActions.ButtonRelease: + { + var args = new SKTouchEventArgs(id, SKTouchAction.Released, button, deviceType, coords, inContact); - case MotionEventActions.Cancel: + onTouchAction(args); + e.Handled = args.Handled; + break; + } + case MotionEventActions.HoverEnter: + { + var args = new SKTouchEventArgs(id, SKTouchAction.Entered, button, deviceType, coords, inContact); + + onTouchAction(args); + e.Handled = args.Handled; + break; + } + case MotionEventActions.HoverExit: + { + var args = new SKTouchEventArgs(id, SKTouchAction.Exited, button, deviceType, coords, inContact); + + onTouchAction(args); + e.Handled = args.Handled; + break; + } + case MotionEventActions.HoverMove: + { + var args = new SKTouchEventArgs(id, SKTouchAction.Moved, button, deviceType, coords, inContact); + + onTouchAction(args); + e.Handled = args.Handled; + break; + } + case MotionEventActions.Scroll: { - var args = new SKTouchEventArgs(id, SKTouchAction.Cancelled, button, deviceType, coords, false, 0, pressure); + var axisValue = evt.GetAxisValue(Axis.Vscroll, pointer); + var wheelDelta = axisValue.Equals(0) ? 0 : axisValue > 0 ? 1 : -1; + var args = new SKTouchEventArgs(id, SKTouchAction.WheelChanged, button, deviceType, coords, inContact, wheelDelta); onTouchAction(args); e.Handled = args.Handled; @@ -113,18 +187,47 @@ private void OnTouch(object? sender, View.TouchEventArgs e) } } - private static SKMouseButton GetButton(MotionEvent evt, MotionEventToolType toolType) + private SKTouchEventArgs CreateTouchEventArgs(SKTouchAction actionType, bool inContact, MotionEvent evt, int pointerIndex) + { + var id = evt.GetPointerId(pointerIndex); + var toolType = evt.GetToolType(pointerIndex); + var button = GetButton(evt.ButtonState, toolType); + var coords = scalePixels?.Invoke(evt.GetX(pointerIndex), evt.GetY(pointerIndex)) ?? + new SKPoint(evt.GetX(pointerIndex), evt.GetY(pointerIndex)); + var deviceType = GetDeviceType(toolType); + var pressure = evt.GetPressure(pointerIndex); + + return new SKTouchEventArgs(id, actionType, button, deviceType, coords, inContact, 0, pressure); + } + + private static SKMouseButton GetButton(MotionEventButtonState buttonState, MotionEventToolType toolType) { var button = SKMouseButton.Left; - if (toolType == MotionEventToolType.Eraser) + if (buttonState.HasFlag(MotionEventButtonState.StylusPrimary)) { - button = SKMouseButton.Middle; + button = SKMouseButton.Left; + } + else if (buttonState.HasFlag(MotionEventButtonState.Primary)) + { + button = SKMouseButton.Left; + } + else if (buttonState.HasFlag(MotionEventButtonState.StylusSecondary)) + { + button = SKMouseButton.Right; } - else if (evt.ButtonState.HasFlag(MotionEventButtonState.StylusSecondary)) + else if (buttonState.HasFlag(MotionEventButtonState.Secondary)) { button = SKMouseButton.Right; } + else if (buttonState.HasFlag(MotionEventButtonState.Tertiary)) + { + button = SKMouseButton.Middle; + } + else if (toolType == MotionEventToolType.Mouse) + { + button = SKMouseButton.Unknown; + } return button; } @@ -135,7 +238,7 @@ toolType switch MotionEventToolType.Unknown => SKTouchDeviceType.Touch, MotionEventToolType.Finger => SKTouchDeviceType.Touch, MotionEventToolType.Stylus => SKTouchDeviceType.Pen, - MotionEventToolType.Eraser => SKTouchDeviceType.Pen, + MotionEventToolType.Eraser => SKTouchDeviceType.Eraser, MotionEventToolType.Mouse => SKTouchDeviceType.Mouse, _ => SKTouchDeviceType.Touch, }; diff --git a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Mac/SKTouchHandler.cs b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Mac/SKTouchHandler.cs index fac7028ec1..d96c6b817b 100644 --- a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Mac/SKTouchHandler.cs +++ b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Mac/SKTouchHandler.cs @@ -116,8 +116,9 @@ private bool FireEvent(SKTouchAction actionType, SKMouseButton mouse, SKTouchDev cgPoint.Y = View.Bounds.Height - cgPoint.Y; var point = scalePixels(cgPoint.X, cgPoint.Y); + var wheelDelta = (int)mouseEvent.ScrollingDeltaY; - var args = new SKTouchEventArgs(id, actionType, mouse, device, point, inContact); + var args = new SKTouchEventArgs(id, actionType, mouse, device, point, inContact, wheelDelta, mouseEvent.Pressure); onTouchAction(args); return args.Handled; } diff --git a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/SKTouchEventArgs.cs b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/SKTouchEventArgs.cs index 8121a42ae6..471e7b8877 100644 --- a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/SKTouchEventArgs.cs +++ b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Shared/SKTouchEventArgs.cs @@ -19,6 +19,11 @@ public SKTouchEventArgs(long id, SKTouchAction type, SKPoint location, bool inCo { } + public SKTouchEventArgs(long id, SKTouchAction type, SKPoint location, bool inContact, float pressure) + : this(id, type, SKMouseButton.Left, SKTouchDeviceType.Touch, location, inContact, 0, pressure) + { + } + public SKTouchEventArgs(long id, SKTouchAction type, SKMouseButton mouseButton, SKTouchDeviceType deviceType, SKPoint location, bool inContact) : this(id, type, mouseButton, deviceType, location, inContact, 0, 1) { @@ -80,7 +85,8 @@ public enum SKTouchDeviceType { Touch, Mouse, - Pen + Pen, + Eraser } public enum SKMouseButton diff --git a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Tizen/SKTouchHandler.cs b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Tizen/SKTouchHandler.cs index 59a27f8d25..ec6cc320c5 100755 --- a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Tizen/SKTouchHandler.cs +++ b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.Tizen/SKTouchHandler.cs @@ -86,6 +86,7 @@ public MomentumHandler(SKTouchHandler h) public void OnStarted() { + // TODO: id is always increasing ++currentId; PostEvent(SKTouchAction.Pressed); } @@ -112,7 +113,7 @@ private void PostEvent(SKTouchAction action) var p = handler.gestureLayer.EvasCanvas.Pointer; var coords = handler.scalePixels(p.X, p.Y); - var inContact = (action == SKTouchAction.Pressed || action == SKTouchAction.Moved) ? true : false; + var inContact = action == SKTouchAction.Pressed || action == SKTouchAction.Moved; handler.onTouchAction(new SKTouchEventArgs(currentId, action, coords, inContact)); } diff --git a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.UWP/SKTouchHandler.cs b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.UWP/SKTouchHandler.cs index a3984f7494..99e158796d 100644 --- a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.UWP/SKTouchHandler.cs +++ b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.UWP/SKTouchHandler.cs @@ -127,22 +127,27 @@ private bool CommonHandler(object sender, SKTouchAction touchActionType, Pointer var skPoint = scalePixels(windowsPoint.X, windowsPoint.Y); var mouse = GetMouseButton(pointerPoint); - var device = GetTouchDevice(evt); + var device = GetTouchDevice(evt, pointerPoint); var wheelDelta = pointerPoint?.Properties?.MouseWheelDelta ?? 0; + var pressure = pointerPoint?.Properties?.Pressure ?? 0.5; - var args = new SKTouchEventArgs(id, touchActionType, mouse, device, skPoint, evt.Pointer.IsInContact, wheelDelta); + var args = new SKTouchEventArgs(id, touchActionType, mouse, device, skPoint, evt.Pointer.IsInContact, wheelDelta, pressure); onTouchAction(args); return args.Handled; } - private static SKTouchDeviceType GetTouchDevice(PointerRoutedEventArgs evt) + private static SKTouchDeviceType GetTouchDevice(PointerRoutedEventArgs evt, PointerPoint pointerPoint) { var device = SKTouchDeviceType.Touch; switch (evt.Pointer.PointerDeviceType) { case PointerDeviceType.Pen: - device = SKTouchDeviceType.Pen; + var isEraser = + pointerPoint?.Properties?.IsInverted == true || + pointerPoint?.Properties?.IsEraser == true; + + device = isEraser ? SKTouchDeviceType.Eraser : SKTouchDeviceType.Pen; break; case PointerDeviceType.Mouse: device = SKTouchDeviceType.Mouse; diff --git a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.WPF/SKTouchHandlerElement.cs b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.WPF/SKTouchHandlerElement.cs index bce1062d7e..3268bacbdd 100644 --- a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.WPF/SKTouchHandlerElement.cs +++ b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.WPF/SKTouchHandlerElement.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Windows; using System.Windows.Input; @@ -18,8 +17,6 @@ public SKTouchHandlerElement(Action onTouchAction, Func b.Name))); - mouse = stylus.InAir ? SKMouseButton.Unknown : SKMouseButton.Left; + var buttonsCount = stylus.StylusDevice.StylusButtons.Count; + var isPrimaryPressed = false; + var isSecondaryPressed = false; + var isTertiaryPressed = false; + if (buttonsCount > 0) + isPrimaryPressed = stylus.StylusDevice.StylusButtons[0].StylusButtonState == StylusButtonState.Down; + if (buttonsCount > 1) + isSecondaryPressed = stylus.StylusDevice.StylusButtons[1].StylusButtonState == StylusButtonState.Down; + if (buttonsCount > 2) + isTertiaryPressed = stylus.StylusDevice.StylusButtons[2].StylusButtonState == StylusButtonState.Down; + + if (isPrimaryPressed) + mouse = SKMouseButton.Left; + else if (isSecondaryPressed) + mouse = SKMouseButton.Right; + else if (isTertiaryPressed) + mouse = SKMouseButton.Middle; } break; } diff --git a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.iOS/SKTouchHandler.cs b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.iOS/SKTouchHandler.cs index 29dd3593da..a1cd32318f 100644 --- a/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.iOS/SKTouchHandler.cs +++ b/source/SkiaSharp.Views.Forms/SkiaSharp.Views.Forms.iOS/SKTouchHandler.cs @@ -108,7 +108,7 @@ private bool FireEvent(SKTouchAction actionType, UITouch touch, bool inContact) var cgPoint = touch.LocationInView(View); var point = scalePixels(cgPoint.X, cgPoint.Y); - var args = new SKTouchEventArgs(id, actionType, point, inContact); + var args = new SKTouchEventArgs(id, actionType, point, inContact, (float)touch.Force); onTouchAction(args); return args.Handled; }