Browse Source

PenDevice tuning, Add pen properties to the PointerPointProperties

Stylus
Sergey Mikolaytis 5 years ago
parent
commit
4cea62fd13
  1. 2
      src/Avalonia.Input/IKeyboardDevice.cs
  2. 3
      src/Avalonia.Input/IPointer.cs
  3. 134
      src/Avalonia.Input/PenDevice.cs
  4. 30
      src/Avalonia.Input/PointerPoint.cs
  5. 8
      src/Avalonia.Input/Raw/RawPointerEventArgs.cs
  6. 64
      src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs

2
src/Avalonia.Input/IKeyboardDevice.cs

@ -47,6 +47,8 @@ namespace Avalonia.Input
MiddleMouseButton = 64, MiddleMouseButton = 64,
XButton1MouseButton = 128, XButton1MouseButton = 128,
XButton2MouseButton = 256, XButton2MouseButton = 256,
BarrelPenButton = 512,
PenEraser = 1024,
KeyboardMask = Alt | Control | Shift | Meta KeyboardMask = Alt | Control | Shift | Meta
} }

3
src/Avalonia.Input/IPointer.cs

@ -13,6 +13,7 @@ namespace Avalonia.Input
public enum PointerType public enum PointerType
{ {
Mouse, Mouse,
Touch Touch,
Pen
} }
} }

134
src/Avalonia.Input/PenDevice.cs

@ -3,7 +3,6 @@ using System.Linq;
using System.Reactive.Linq; using System.Reactive.Linq;
using Avalonia.Input.Raw; using Avalonia.Input.Raw;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Platform;
using Avalonia.VisualTree; using Avalonia.VisualTree;
namespace Avalonia.Input namespace Avalonia.Input
@ -13,17 +12,13 @@ namespace Avalonia.Input
/// </summary> /// </summary>
public class PenDevice : IPenDevice, IDisposable public class PenDevice : IPenDevice, IDisposable
{ {
private int _clickCount;
private Rect _lastClickRect;
private ulong _lastClickTime;
private readonly Pointer _pointer; private readonly Pointer _pointer;
private bool _disposed; private bool _disposed;
private PixelPoint? _position; private PixelPoint? _position;
public PenDevice(Pointer? pointer = null) public PenDevice(Pointer? pointer = null)
{ {
_pointer = pointer ?? new Pointer(Pointer.GetNextFreeId(), PointerType.Mouse, true); _pointer = pointer ?? new Pointer(Pointer.GetNextFreeId(), PointerType.Pen, true);
} }
/// <summary> /// <summary>
@ -37,16 +32,6 @@ namespace Avalonia.Input
[Obsolete("Use IPointer instead")] [Obsolete("Use IPointer instead")]
public IInputElement? Captured => _pointer.Captured; public IInputElement? Captured => _pointer.Captured;
/// <summary>
/// Gets the mouse position, in screen coordinates.
/// </summary>
[Obsolete("Use events instead")]
public PixelPoint Position
{
get => _position ?? new PixelPoint(-1, -1);
protected set => _position = value;
}
/// <summary> /// <summary>
/// Captures mouse input to the specified control. /// Captures mouse input to the specified control.
/// </summary> /// </summary>
@ -76,7 +61,7 @@ namespace Avalonia.Input
} }
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
var rootPoint = relativeTo.VisualRoot.PointToClient(Position); var rootPoint = relativeTo.VisualRoot.PointToClient(_position ?? new PixelPoint(-1, -1));
#pragma warning restore CS0618 // Type or member is obsolete #pragma warning restore CS0618 // Type or member is obsolete
var transform = relativeTo.VisualRoot.TransformToVisual(relativeTo); var transform = relativeTo.VisualRoot.TransformToVisual(relativeTo);
return rootPoint * transform!.Value; return rootPoint * transform!.Value;
@ -120,29 +105,13 @@ namespace Avalonia.Input
} }
} }
} }
int ButtonCount(PointerPointProperties props)
{
var rv = 0;
if (props.IsLeftButtonPressed)
rv++;
if (props.IsMiddleButtonPressed)
rv++;
if (props.IsRightButtonPressed)
rv++;
if (props.IsXButton1Pressed)
rv++;
if (props.IsXButton2Pressed)
rv++;
return rv;
}
private void ProcessRawEvent(RawPointerEventArgs e) private void ProcessRawEvent(RawPointerEventArgs e)
{ {
e = e ?? throw new ArgumentNullException(nameof(e)); e = e ?? throw new ArgumentNullException(nameof(e));
var mouse = (PenDevice)e.Device; var pen = (PenDevice)e.Device;
if(mouse._disposed) if(pen._disposed)
return; return;
_position = e.Root.PointToScreen(e.Position); _position = e.Root.PointToScreen(e.Position);
@ -151,34 +120,16 @@ namespace Avalonia.Input
switch (e.Type) switch (e.Type)
{ {
case RawPointerEventType.LeaveWindow: case RawPointerEventType.LeaveWindow:
LeaveWindow(mouse, e.Timestamp, e.Root, props, keyModifiers); LeaveWindow(pen, e.Timestamp, e.Root, props, keyModifiers);
break; break;
case RawPointerEventType.LeftButtonDown: case RawPointerEventType.PenBegin:
case RawPointerEventType.RightButtonDown: e.Handled = PenDown(pen, e.Timestamp, e.Root, e.Position, props, keyModifiers);
case RawPointerEventType.MiddleButtonDown:
case RawPointerEventType.XButton1Down:
case RawPointerEventType.XButton2Down:
if (ButtonCount(props) > 1)
e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers);
else
e.Handled = MouseDown(mouse, e.Timestamp, e.Root, e.Position,
props, keyModifiers);
break; break;
case RawPointerEventType.LeftButtonUp: case RawPointerEventType.PenEnd:
case RawPointerEventType.RightButtonUp: e.Handled = PenUp(pen, e.Timestamp, e.Root, e.Position, props, keyModifiers);
case RawPointerEventType.MiddleButtonUp:
case RawPointerEventType.XButton1Up:
case RawPointerEventType.XButton2Up:
if (ButtonCount(props) != 0)
e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers);
else
e.Handled = MouseUp(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers);
break; break;
case RawPointerEventType.Move: case RawPointerEventType.PenUpdate:
e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers); e.Handled = PenMove(pen, e.Timestamp, e.Root, e.Position, props, keyModifiers);
break;
case RawPointerEventType.Wheel:
e.Handled = MouseWheel(mouse, e.Timestamp, e.Root, e.Position, props, ((RawMouseWheelEventArgs)e).Delta, keyModifiers);
break; break;
} }
} }
@ -196,35 +147,18 @@ namespace Avalonia.Input
PointerPointProperties CreateProperties(RawPointerEventArgs args) PointerPointProperties CreateProperties(RawPointerEventArgs args)
{ {
var kind = PointerUpdateKind.Other; var kind = PointerUpdateKind.Other;
if (args.Type == RawPointerEventType.LeftButtonDown) if (args.Type == RawPointerEventType.PenBegin)
kind = PointerUpdateKind.LeftButtonPressed; kind = PointerUpdateKind.LeftButtonPressed;
if (args.Type == RawPointerEventType.MiddleButtonDown) if (args.Type == RawPointerEventType.PenEnd)
kind = PointerUpdateKind.MiddleButtonPressed;
if (args.Type == RawPointerEventType.RightButtonDown)
kind = PointerUpdateKind.RightButtonPressed;
if (args.Type == RawPointerEventType.XButton1Down)
kind = PointerUpdateKind.XButton1Pressed;
if (args.Type == RawPointerEventType.XButton2Down)
kind = PointerUpdateKind.XButton2Pressed;
if (args.Type == RawPointerEventType.LeftButtonUp)
kind = PointerUpdateKind.LeftButtonReleased; kind = PointerUpdateKind.LeftButtonReleased;
if (args.Type == RawPointerEventType.MiddleButtonUp)
kind = PointerUpdateKind.MiddleButtonReleased;
if (args.Type == RawPointerEventType.RightButtonUp)
kind = PointerUpdateKind.RightButtonReleased;
if (args.Type == RawPointerEventType.XButton1Up)
kind = PointerUpdateKind.XButton1Released;
if (args.Type == RawPointerEventType.XButton2Up)
kind = PointerUpdateKind.XButton2Released;
return new PointerPointProperties(args.InputModifiers, kind); return new PointerPointProperties(args.InputModifiers, kind);
} }
private MouseButton _lastMouseDownButton; private MouseButton _lastMouseDownButton;
private bool MouseDown(IPenDevice device, ulong timestamp, IInputElement root, Point p, private bool PenDown(IPenDevice device, ulong timestamp, IInputElement root, Point p,
PointerPointProperties properties, PointerPointProperties properties,
KeyModifiers inputModifiers) KeyModifiers inputModifiers)
{ {
@ -239,21 +173,8 @@ namespace Avalonia.Input
var source = GetSource(hit); var source = GetSource(hit);
if (source != null) if (source != null)
{ {
var settings = AvaloniaLocator.Current.GetService<IPlatformSettings>();
var doubleClickTime = settings?.DoubleClickTime.TotalMilliseconds ?? 500;
var doubleClickSize = settings?.DoubleClickSize ?? new Size(4, 4);
if (!_lastClickRect.Contains(p) || timestamp - _lastClickTime > doubleClickTime)
{
_clickCount = 0;
}
++_clickCount;
_lastClickTime = timestamp;
_lastClickRect = new Rect(p, new Size())
.Inflate(new Thickness(doubleClickSize.Width / 2, doubleClickSize.Height / 2));
_lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton(); _lastMouseDownButton = properties.PointerUpdateKind.GetMouseButton();
var e = new PointerPressedEventArgs(source, _pointer, root, p, timestamp, properties, inputModifiers, _clickCount); var e = new PointerPressedEventArgs(source, _pointer, root, p, timestamp, properties, inputModifiers, 1);
source.RaiseEvent(e); source.RaiseEvent(e);
return e.Handled; return e.Handled;
} }
@ -262,7 +183,7 @@ namespace Avalonia.Input
return false; return false;
} }
private bool MouseMove(IPenDevice device, ulong timestamp, IInputRoot root, Point p, PointerPointProperties properties, private bool PenMove(IPenDevice device, ulong timestamp, IInputRoot root, Point p, PointerPointProperties properties,
KeyModifiers inputModifiers) KeyModifiers inputModifiers)
{ {
device = device ?? throw new ArgumentNullException(nameof(device)); device = device ?? throw new ArgumentNullException(nameof(device));
@ -292,7 +213,7 @@ namespace Avalonia.Input
return false; return false;
} }
private bool MouseUp(IPenDevice device, ulong timestamp, IInputRoot root, Point p, PointerPointProperties props, private bool PenUp(IPenDevice device, ulong timestamp, IInputRoot root, Point p, PointerPointProperties props,
KeyModifiers inputModifiers) KeyModifiers inputModifiers)
{ {
device = device ?? throw new ArgumentNullException(nameof(device)); device = device ?? throw new ArgumentNullException(nameof(device));
@ -314,27 +235,6 @@ namespace Avalonia.Input
return false; return false;
} }
private bool MouseWheel(IPenDevice device, ulong timestamp, IInputRoot root, Point p,
PointerPointProperties props,
Vector delta, KeyModifiers inputModifiers)
{
device = device ?? throw new ArgumentNullException(nameof(device));
root = root ?? throw new ArgumentNullException(nameof(root));
var hit = HitTest(root, p);
var source = GetSource(hit);
if (source is not null)
{
var e = new PointerWheelEventArgs(source, _pointer, root, p, timestamp, props, inputModifiers, delta);
source?.RaiseEvent(e);
return e.Handled;
}
return false;
}
private IInteractive? GetSource(IVisual? hit) private IInteractive? GetSource(IVisual? hit)
{ {
if (hit is null) if (hit is null)

30
src/Avalonia.Input/PointerPoint.cs

@ -20,6 +20,14 @@ namespace Avalonia.Input
public bool IsRightButtonPressed { get; } public bool IsRightButtonPressed { get; }
public bool IsXButton1Pressed { get; } public bool IsXButton1Pressed { get; }
public bool IsXButton2Pressed { get; } public bool IsXButton2Pressed { get; }
public bool IsBarrelButtonPressed { get; }
public bool IsEraser { get; }
public float Twist { get; }
public float Pressure { get; }
public float XTilt { get; }
public float YTilt { get; }
public PointerUpdateKind PointerUpdateKind { get; } public PointerUpdateKind PointerUpdateKind { get; }
@ -36,10 +44,12 @@ namespace Avalonia.Input
IsRightButtonPressed = modifiers.HasAllFlags(RawInputModifiers.RightMouseButton); IsRightButtonPressed = modifiers.HasAllFlags(RawInputModifiers.RightMouseButton);
IsXButton1Pressed = modifiers.HasAllFlags(RawInputModifiers.XButton1MouseButton); IsXButton1Pressed = modifiers.HasAllFlags(RawInputModifiers.XButton1MouseButton);
IsXButton2Pressed = modifiers.HasAllFlags(RawInputModifiers.XButton2MouseButton); IsXButton2Pressed = modifiers.HasAllFlags(RawInputModifiers.XButton2MouseButton);
IsBarrelButtonPressed = modifiers.HasAllFlags(RawInputModifiers.BarrelPenButton);
IsEraser = modifiers.HasAllFlags(RawInputModifiers.PenEraser);
// The underlying input source might be reporting the previous state, // The underlying input source might be reporting the previous state,
// so make sure that we reflect the current state // so make sure that we reflect the current state
if (kind == PointerUpdateKind.LeftButtonPressed) if (kind == PointerUpdateKind.LeftButtonPressed)
IsLeftButtonPressed = true; IsLeftButtonPressed = true;
if (kind == PointerUpdateKind.LeftButtonReleased) if (kind == PointerUpdateKind.LeftButtonReleased)
@ -60,6 +70,20 @@ namespace Avalonia.Input
IsXButton2Pressed = true; IsXButton2Pressed = true;
if (kind == PointerUpdateKind.XButton2Released) if (kind == PointerUpdateKind.XButton2Released)
IsXButton2Pressed = false; IsXButton2Pressed = false;
if (kind == PointerUpdateKind.BarrelButtonPressed)
IsBarrelButtonPressed = true;
if (kind == PointerUpdateKind.BarrelButtonReleased)
IsBarrelButtonPressed = false;
}
public PointerPointProperties(RawInputModifiers modifiers, PointerUpdateKind kind,
float twist, float pressure, float xTilt, float yTilt
) : this (modifiers, kind)
{
Twist = twist;
Pressure = pressure;
XTilt = xTilt;
YTilt = yTilt;
} }
public static PointerPointProperties None { get; } = new PointerPointProperties(); public static PointerPointProperties None { get; } = new PointerPointProperties();
@ -77,7 +101,9 @@ namespace Avalonia.Input
RightButtonReleased, RightButtonReleased,
XButton1Released, XButton1Released,
XButton2Released, XButton2Released,
Other Other,
BarrelButtonPressed,
BarrelButtonReleased
} }
public static class PointerUpdateKindExtensions public static class PointerUpdateKindExtensions

8
src/Avalonia.Input/Raw/RawPointerEventArgs.cs

@ -21,7 +21,13 @@ namespace Avalonia.Input.Raw
TouchBegin, TouchBegin,
TouchUpdate, TouchUpdate,
TouchEnd, TouchEnd,
TouchCancel TouchCancel,
PenBegin,
PenUpdate,
PenEnd,
PenCancel,
BarrelUp,
BarrelDown,
} }
/// <summary> /// <summary>

64
src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs

@ -374,17 +374,6 @@ namespace Avalonia.Win32
break; break;
} }
case WindowsMessage.WM_POINTERDEVICECHANGE: case WindowsMessage.WM_POINTERDEVICECHANGE:
{ {
//notifies about changes in the settings of a monitor that has a digitizer attached to it. //notifies about changes in the settings of a monitor that has a digitizer attached to it.
@ -414,7 +403,10 @@ namespace Avalonia.Win32
GetDeviceInfo(wParam, out var device, out var info); GetDeviceInfo(wParam, out var device, out var info);
var point = PointToClient(PointFromLParam(lParam)); var point = PointToClient(PointFromLParam(lParam));
var modifiers = GetInputModifiers(info.dwKeyStates); var modifiers = GetInputModifiers(info.dwKeyStates);
var eventType = info.ButtonChangeType switch
if (info.ButtonChangeType != PointerButtonChangeType.POINTER_CHANGE_NONE)
{
var eventType = info.ButtonChangeType switch
{ {
PointerButtonChangeType.POINTER_CHANGE_FIRSTBUTTON_DOWN => RawPointerEventType.LeftButtonDown, PointerButtonChangeType.POINTER_CHANGE_FIRSTBUTTON_DOWN => RawPointerEventType.LeftButtonDown,
PointerButtonChangeType.POINTER_CHANGE_SECONDBUTTON_DOWN => RawPointerEventType.RightButtonDown, PointerButtonChangeType.POINTER_CHANGE_SECONDBUTTON_DOWN => RawPointerEventType.RightButtonDown,
@ -428,12 +420,13 @@ namespace Avalonia.Win32
PointerButtonChangeType.POINTER_CHANGE_FOURTHBUTTON_UP => RawPointerEventType.XButton1Up, PointerButtonChangeType.POINTER_CHANGE_FOURTHBUTTON_UP => RawPointerEventType.XButton1Up,
PointerButtonChangeType.POINTER_CHANGE_FIFTHBUTTON_UP => RawPointerEventType.XButton2Up, PointerButtonChangeType.POINTER_CHANGE_FIFTHBUTTON_UP => RawPointerEventType.XButton2Up,
}; };
if (eventType == RawPointerEventType.NonClientLeftButtonDown && if (eventType == RawPointerEventType.NonClientLeftButtonDown &&
(WindowsMessage)msg == WindowsMessage.WM_NCPOINTERDOWN) (WindowsMessage)msg == WindowsMessage.WM_NCPOINTERDOWN)
{ {
eventType = RawPointerEventType.NonClientLeftButtonDown; eventType = RawPointerEventType.NonClientLeftButtonDown;
}
e = new RawPointerEventArgs(device, timestamp, _owner, eventType, point, modifiers);
} }
e = new RawPointerEventArgs(device, timestamp, _owner, eventType, point, modifiers);
break; break;
} }
case WindowsMessage.WM_POINTERUPDATE: case WindowsMessage.WM_POINTERUPDATE:
@ -446,7 +439,8 @@ namespace Avalonia.Win32
var point = PointToClient(PointFromLParam(lParam)); var point = PointToClient(PointFromLParam(lParam));
var modifiers = GetInputModifiers(info.dwKeyStates); var modifiers = GetInputModifiers(info.dwKeyStates);
e = new RawPointerEventArgs(device, timestamp, _owner, RawPointerEventType.Move, point, modifiers); e = new RawPointerEventArgs(
device, timestamp, _owner, RawPointerEventType.Move, point, modifiers);
break; break;
} }
case WindowsMessage.WM_POINTERENTER: case WindowsMessage.WM_POINTERENTER:
@ -462,14 +456,10 @@ namespace Avalonia.Win32
{ {
GetDeviceInfo(wParam, out var device, out var info); GetDeviceInfo(wParam, out var device, out var info);
var point = PointToClient(PointFromLParam(lParam)); var point = PointToClient(PointFromLParam(lParam));
var modifiers = GetInputModifiers(info.dwKeyStates);
e = new RawPointerEventArgs( e = new RawPointerEventArgs(
device, device, timestamp, _owner, RawPointerEventType.LeaveWindow, point, modifiers);
timestamp,
_owner,
RawPointerEventType.LeaveWindow,
point,
WindowsKeyboardDevice.Instance.Modifiers);
break; break;
} }
case WindowsMessage.WM_POINTERACTIVATE: case WindowsMessage.WM_POINTERACTIVATE:
@ -520,33 +510,11 @@ namespace Avalonia.Win32
} }
case WindowsMessage.WM_PARENTNOTIFY: case WindowsMessage.WM_PARENTNOTIFY:
{ {
//This message is sent in a dialog scenarios. Contains mouse position in an old-way, //This message is sent in a dialog scenarios. Contains mouse position.
//but listed in the wm_pointer reference //Old message, but listed in the wm_pointer reference
//https://docs.microsoft.com/en-us/previous-versions/windows/desktop/inputmsg/wm-parentnotify //https://docs.microsoft.com/en-us/previous-versions/windows/desktop/inputmsg/wm-parentnotify
break; break;
} }
case WindowsMessage.WM_NCPAINT: case WindowsMessage.WM_NCPAINT:
{ {
if (!HasFullDecorations) if (!HasFullDecorations)

Loading…
Cancel
Save