Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve triggering of touch event and introduce Eraser device #1293

Open
wants to merge 9 commits into
base: release/2.x
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
Expand All @@ -51,60 +53,132 @@ 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;
}

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;
Expand All @@ -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;
}
Expand All @@ -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,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -80,7 +85,8 @@ public enum SKTouchDeviceType
{
Touch,
Mouse,
Pen
Pen,
Eraser
}

public enum SKMouseButton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public MomentumHandler(SKTouchHandler h)

public void OnStarted()
{
// TODO: id is always increasing
++currentId;
PostEvent(SKTouchAction.Pressed);
}
Expand All @@ -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));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link

@nshtinkov nshtinkov Apr 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 133 should be ?? 1 because 1 is the default pressure for SKTouchEventArgs. Also this change would fix the compiler error.
pr1239fix.patch


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;
Expand Down
Loading