From 0bad390dac05b4dde51dcb5d58469abd6320d0c3 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Sat, 10 Aug 2019 11:21:26 +0300 Subject: [PATCH] Added PointerUpdateKind and replaced InputModifiers with KeyModifiers --- src/Avalonia.Controls/MenuItem.cs | 4 +- .../Platform/InProcessDragSource.cs | 4 +- .../Remote/Server/RemoteServerTopLevelImpl.cs | 18 ++-- src/Avalonia.Input/IKeyboardDevice.cs | 1 + src/Avalonia.Input/MouseDevice.cs | 85 +++++++++++-------- src/Avalonia.Input/PointerEventArgs.cs | 50 +++++++++-- src/Avalonia.Input/PointerPoint.cs | 54 +++++++++--- src/Avalonia.Input/PointerWheelEventArgs.cs | 2 +- .../Raw/RawMouseWheelEventArgs.cs | 2 +- src/Avalonia.Input/Raw/RawPointerEventArgs.cs | 4 +- src/Avalonia.Input/Raw/RawTouchEventArgs.cs | 2 +- src/Avalonia.Input/TouchDevice.cs | 31 ++++--- src/Avalonia.Native/WindowImplBase.cs | 4 +- src/Avalonia.X11/X11Window.cs | 18 ++-- src/Avalonia.X11/XI2Manager.cs | 16 ++-- .../Input/LibInput/LibInputBackend.cs | 6 +- .../Input/WindowsKeyboardDevice.cs | 14 +-- src/Windows/Avalonia.Win32/WindowImpl.cs | 8 +- .../DefaultMenuInteractionHandlerTests.cs | 6 +- .../MouseDeviceTests.cs | 2 +- tests/Avalonia.UnitTests/MouseTestHelper.cs | 23 +++-- 21 files changed, 223 insertions(+), 131 deletions(-) diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs index 38cc3f6daf..33a708b6a5 100644 --- a/src/Avalonia.Controls/MenuItem.cs +++ b/src/Avalonia.Controls/MenuItem.cs @@ -339,7 +339,7 @@ namespace Avalonia.Controls var point = e.GetPointerPoint(null); RaiseEvent(new PointerEventArgs(PointerEnterItemEvent, this, e.Pointer, this.VisualRoot, point.Position, - e.Timestamp, point.Properties, e.InputModifiers)); + e.Timestamp, point.Properties, e.KeyModifiers)); } /// @@ -349,7 +349,7 @@ namespace Avalonia.Controls var point = e.GetPointerPoint(null); RaiseEvent(new PointerEventArgs(PointerLeaveItemEvent, this, e.Pointer, this.VisualRoot, point.Position, - e.Timestamp, point.Properties, e.InputModifiers)); + e.Timestamp, point.Properties, e.KeyModifiers)); } /// diff --git a/src/Avalonia.Controls/Platform/InProcessDragSource.cs b/src/Avalonia.Controls/Platform/InProcessDragSource.cs index d4df41d2f2..2765cd7106 100644 --- a/src/Avalonia.Controls/Platform/InProcessDragSource.cs +++ b/src/Avalonia.Controls/Platform/InProcessDragSource.cs @@ -14,7 +14,7 @@ namespace Avalonia.Platform { class InProcessDragSource : IPlatformDragSource { - private const InputModifiers MOUSE_INPUTMODIFIERS = InputModifiers.LeftMouseButton|InputModifiers.MiddleMouseButton|InputModifiers.RightMouseButton; + private const RawInputModifiers MOUSE_INPUTMODIFIERS = RawInputModifiers.LeftMouseButton|RawInputModifiers.MiddleMouseButton|RawInputModifiers.RightMouseButton; private readonly IDragDropDevice _dragDrop; private readonly IInputManager _inputManager; private readonly Subject _result = new Subject(); @@ -25,7 +25,7 @@ namespace Avalonia.Platform private Point _lastPosition; private StandardCursorType _lastCursorType; private object _originalCursor; - private InputModifiers? _initialInputModifiers; + private RawInputModifiers? _initialInputModifiers; public InProcessDragSource() { diff --git a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs index cfd28106eb..be24f22e20 100644 --- a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs +++ b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs @@ -61,9 +61,9 @@ namespace Avalonia.Controls.Remote.Server Avalonia.Remote.Protocol.Input.InputModifiers[] modifiers) => (RawInputModifiers)GetAvaloniaInputModifiers(modifiers); - private static InputModifiers GetAvaloniaInputModifiers (Avalonia.Remote.Protocol.Input.InputModifiers[] modifiers) + private static RawInputModifiers GetAvaloniaInputModifiers (Avalonia.Remote.Protocol.Input.InputModifiers[] modifiers) { - var result = InputModifiers.None; + var result = RawInputModifiers.None; if (modifiers == null) { @@ -75,31 +75,31 @@ namespace Avalonia.Controls.Remote.Server switch (modifier) { case Avalonia.Remote.Protocol.Input.InputModifiers.Control: - result |= InputModifiers.Control; + result |= RawInputModifiers.Control; break; case Avalonia.Remote.Protocol.Input.InputModifiers.Alt: - result |= InputModifiers.Alt; + result |= RawInputModifiers.Alt; break; case Avalonia.Remote.Protocol.Input.InputModifiers.Shift: - result |= InputModifiers.Shift; + result |= RawInputModifiers.Shift; break; case Avalonia.Remote.Protocol.Input.InputModifiers.Windows: - result |= InputModifiers.Windows; + result |= RawInputModifiers.Meta; break; case Avalonia.Remote.Protocol.Input.InputModifiers.LeftMouseButton: - result |= InputModifiers.LeftMouseButton; + result |= RawInputModifiers.LeftMouseButton; break; case Avalonia.Remote.Protocol.Input.InputModifiers.MiddleMouseButton: - result |= InputModifiers.MiddleMouseButton; + result |= RawInputModifiers.MiddleMouseButton; break; case Avalonia.Remote.Protocol.Input.InputModifiers.RightMouseButton: - result |= InputModifiers.RightMouseButton; + result |= RawInputModifiers.RightMouseButton; break; } } diff --git a/src/Avalonia.Input/IKeyboardDevice.cs b/src/Avalonia.Input/IKeyboardDevice.cs index 6b3e8435d9..1a82f7d671 100644 --- a/src/Avalonia.Input/IKeyboardDevice.cs +++ b/src/Avalonia.Input/IKeyboardDevice.cs @@ -37,6 +37,7 @@ namespace Avalonia.Input Toggled = 2, } + [Flags] public enum RawInputModifiers { None = 0, diff --git a/src/Avalonia.Input/MouseDevice.cs b/src/Avalonia.Input/MouseDevice.cs index ee7d0c9501..d5152f58d5 100644 --- a/src/Avalonia.Input/MouseDevice.cs +++ b/src/Avalonia.Input/MouseDevice.cs @@ -94,11 +94,13 @@ namespace Avalonia.Input { if (_pointer.Captured == null) { - SetPointerOver(this, 0 /* TODO: proper timestamp */, root, clientPoint, InputModifiers.None); + SetPointerOver(this, 0 /* TODO: proper timestamp */, root, clientPoint, + PointerPointProperties.None, KeyModifiers.None); } else { - SetPointerOver(this, 0 /* TODO: proper timestamp */, root, _pointer.Captured, InputModifiers.None); + SetPointerOver(this, 0 /* TODO: proper timestamp */, root, _pointer.Captured, + PointerPointProperties.None, KeyModifiers.None); } } } @@ -123,69 +125,73 @@ namespace Avalonia.Input Position = e.Root.PointToScreen(e.Position); var props = CreateProperties(e); + var keyModifiers = KeyModifiersUtils.ConvertToKey(e.InputModifiers); switch (e.Type) { case RawPointerEventType.LeaveWindow: - LeaveWindow(mouse, e.Timestamp, e.Root, e.InputModifiers); + LeaveWindow(mouse, e.Timestamp, e.Root, props, keyModifiers); break; case RawPointerEventType.LeftButtonDown: case RawPointerEventType.RightButtonDown: case RawPointerEventType.MiddleButtonDown: if (ButtonCount(props) > 1) - e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, e.InputModifiers); + e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers); else e.Handled = MouseDown(mouse, e.Timestamp, e.Root, e.Position, - props, e.InputModifiers); + props, keyModifiers); break; case RawPointerEventType.LeftButtonUp: case RawPointerEventType.RightButtonUp: case RawPointerEventType.MiddleButtonUp: if (ButtonCount(props) != 0) - e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, e.InputModifiers); + e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers); else - e.Handled = MouseUp(mouse, e.Timestamp, e.Root, e.Position, props, e.InputModifiers); + e.Handled = MouseUp(mouse, e.Timestamp, e.Root, e.Position, props, keyModifiers); break; case RawPointerEventType.Move: - e.Handled = MouseMove(mouse, e.Timestamp, e.Root, e.Position, props, e.InputModifiers); + e.Handled = MouseMove(mouse, 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, e.InputModifiers); + e.Handled = MouseWheel(mouse, e.Timestamp, e.Root, e.Position, props, ((RawMouseWheelEventArgs)e).Delta, keyModifiers); break; } } - private void LeaveWindow(IMouseDevice device, ulong timestamp, IInputRoot root, InputModifiers inputModifiers) + private void LeaveWindow(IMouseDevice device, ulong timestamp, IInputRoot root, PointerPointProperties properties, + KeyModifiers inputModifiers) { Contract.Requires(device != null); Contract.Requires(root != null); - ClearPointerOver(this, timestamp, root, inputModifiers); + ClearPointerOver(this, timestamp, root, properties, inputModifiers); } PointerPointProperties CreateProperties(RawPointerEventArgs args) { - var rv = new PointerPointProperties(args.InputModifiers); + + var kind = PointerUpdateKind.Other; if (args.Type == RawPointerEventType.LeftButtonDown) - rv.IsLeftButtonPressed = true; + kind = PointerUpdateKind.LeftButtonPressed; if (args.Type == RawPointerEventType.MiddleButtonDown) - rv.IsMiddleButtonPressed = true; + kind = PointerUpdateKind.MiddleButtonPressed; if (args.Type == RawPointerEventType.RightButtonDown) - rv.IsRightButtonPressed = true; + kind = PointerUpdateKind.RightButtonPressed; if (args.Type == RawPointerEventType.LeftButtonUp) - rv.IsLeftButtonPressed = false; + kind = PointerUpdateKind.LeftButtonReleased; if (args.Type == RawPointerEventType.MiddleButtonUp) - rv.IsMiddleButtonPressed = false; + kind = PointerUpdateKind.MiddleButtonReleased; if (args.Type == RawPointerEventType.RightButtonUp) - rv.IsRightButtonPressed = false; - return rv; + kind = PointerUpdateKind.RightButtonReleased; + + return new PointerPointProperties(args.InputModifiers, kind); } private MouseButton _lastMouseDownButton; private bool MouseDown(IMouseDevice device, ulong timestamp, IInputElement root, Point p, PointerPointProperties properties, - InputModifiers inputModifiers) + KeyModifiers inputModifiers) { Contract.Requires(device != null); Contract.Requires(root != null); @@ -221,7 +227,7 @@ namespace Avalonia.Input } private bool MouseMove(IMouseDevice device, ulong timestamp, IInputRoot root, Point p, PointerPointProperties properties, - InputModifiers inputModifiers) + KeyModifiers inputModifiers) { Contract.Requires(device != null); Contract.Requires(root != null); @@ -230,11 +236,11 @@ namespace Avalonia.Input if (_pointer.Captured == null) { - source = SetPointerOver(this, timestamp, root, p, inputModifiers); + source = SetPointerOver(this, timestamp, root, p, properties, inputModifiers); } else { - SetPointerOver(this, timestamp, root, _pointer.Captured, inputModifiers); + SetPointerOver(this, timestamp, root, _pointer.Captured, properties, inputModifiers); source = _pointer.Captured; } @@ -246,7 +252,7 @@ namespace Avalonia.Input } private bool MouseUp(IMouseDevice device, ulong timestamp, IInputRoot root, Point p, PointerPointProperties props, - InputModifiers inputModifiers) + KeyModifiers inputModifiers) { Contract.Requires(device != null); Contract.Requires(root != null); @@ -256,8 +262,7 @@ namespace Avalonia.Input if (hit != null) { var source = GetSource(hit); - var e = new PointerReleasedEventArgs(source, _pointer, root, p, timestamp, props, inputModifiers, - _lastMouseDownButton); + var e = new PointerReleasedEventArgs(source, _pointer, root, p, timestamp, props, inputModifiers); source?.RaiseEvent(e); _pointer.Capture(null); @@ -269,7 +274,7 @@ namespace Avalonia.Input private bool MouseWheel(IMouseDevice device, ulong timestamp, IInputRoot root, Point p, PointerPointProperties props, - Vector delta, InputModifiers inputModifiers) + Vector delta, KeyModifiers inputModifiers) { Contract.Requires(device != null); Contract.Requires(root != null); @@ -304,19 +309,23 @@ namespace Avalonia.Input return _pointer.Captured ?? root.InputHitTest(p); } - PointerEventArgs CreateSimpleEvent(RoutedEvent ev, ulong timestamp, IInteractive source, InputModifiers inputModifiers) + PointerEventArgs CreateSimpleEvent(RoutedEvent ev, ulong timestamp, IInteractive source, + PointerPointProperties properties, + KeyModifiers inputModifiers) { return new PointerEventArgs(ev, source, _pointer, null, default, - timestamp, new PointerPointProperties(inputModifiers), inputModifiers); + timestamp, properties, inputModifiers); } - private void ClearPointerOver(IPointerDevice device, ulong timestamp, IInputRoot root, InputModifiers inputModifiers) + private void ClearPointerOver(IPointerDevice device, ulong timestamp, IInputRoot root, + PointerPointProperties properties, + KeyModifiers inputModifiers) { Contract.Requires(device != null); Contract.Requires(root != null); var element = root.PointerOverElement; - var e = CreateSimpleEvent(InputElement.PointerLeaveEvent, timestamp, element, inputModifiers); + var e = CreateSimpleEvent(InputElement.PointerLeaveEvent, timestamp, element, properties, inputModifiers); if (element!=null && !element.IsAttachedToVisualTree) { @@ -353,7 +362,9 @@ namespace Avalonia.Input } } - private IInputElement SetPointerOver(IPointerDevice device, ulong timestamp, IInputRoot root, Point p, InputModifiers inputModifiers) + private IInputElement SetPointerOver(IPointerDevice device, ulong timestamp, IInputRoot root, Point p, + PointerPointProperties properties, + KeyModifiers inputModifiers) { Contract.Requires(device != null); Contract.Requires(root != null); @@ -364,18 +375,20 @@ namespace Avalonia.Input { if (element != null) { - SetPointerOver(device, timestamp, root, element, inputModifiers); + SetPointerOver(device, timestamp, root, element, properties, inputModifiers); } else { - ClearPointerOver(device, timestamp, root, inputModifiers); + ClearPointerOver(device, timestamp, root, properties, inputModifiers); } } return element; } - private void SetPointerOver(IPointerDevice device, ulong timestamp, IInputRoot root, IInputElement element, InputModifiers inputModifiers) + private void SetPointerOver(IPointerDevice device, ulong timestamp, IInputRoot root, IInputElement element, + PointerPointProperties properties, + KeyModifiers inputModifiers) { Contract.Requires(device != null); Contract.Requires(root != null); @@ -397,7 +410,7 @@ namespace Avalonia.Input el = root.PointerOverElement; - var e = CreateSimpleEvent(InputElement.PointerLeaveEvent, timestamp, el, inputModifiers); + var e = CreateSimpleEvent(InputElement.PointerLeaveEvent, timestamp, el, properties, inputModifiers); if (el!=null && branch!=null && !el.IsAttachedToVisualTree) { ClearChildrenPointerOver(e,branch,false); diff --git a/src/Avalonia.Input/PointerEventArgs.cs b/src/Avalonia.Input/PointerEventArgs.cs index c827822192..0fda4e2465 100644 --- a/src/Avalonia.Input/PointerEventArgs.cs +++ b/src/Avalonia.Input/PointerEventArgs.cs @@ -20,7 +20,7 @@ namespace Avalonia.Input IVisual rootVisual, Point rootVisualPosition, ulong timestamp, PointerPointProperties properties, - InputModifiers modifiers) + KeyModifiers modifiers) : base(routedEvent) { Source = source; @@ -29,7 +29,7 @@ namespace Avalonia.Input _properties = properties; Pointer = pointer; Timestamp = timestamp; - InputModifiers = modifiers; + KeyModifiers = modifiers; } class EmulatedDevice : IPointerDevice @@ -60,7 +60,39 @@ namespace Avalonia.Input [Obsolete("Use Pointer to get pointer-specific information")] public IPointerDevice Device => _device ?? (_device = new EmulatedDevice(this)); - public InputModifiers InputModifiers { get; } + [Obsolete("Use KeyModifiers and PointerPointProperties")] + public InputModifiers InputModifiers + { + get + { + var mods = (InputModifiers)KeyModifiers; + if (_properties.IsLeftButtonPressed) + mods |= InputModifiers.LeftMouseButton; + if (_properties.IsMiddleButtonPressed) + mods |= InputModifiers.MiddleMouseButton; + if (_properties.IsRightButtonPressed) + mods |= InputModifiers.RightMouseButton; + + // The old InputModifiers has indicated the *previous* state, so we are emulating this legacy behavior + if (_properties.PointerUpdateKind == PointerUpdateKind.LeftButtonPressed) + mods &= ~InputModifiers.LeftMouseButton; + if (_properties.PointerUpdateKind == PointerUpdateKind.MiddleButtonPressed) + mods &= ~InputModifiers.MiddleMouseButton; + if (_properties.PointerUpdateKind == PointerUpdateKind.RightButtonPressed) + mods &= ~InputModifiers.RightMouseButton; + + if (_properties.PointerUpdateKind == PointerUpdateKind.LeftButtonReleased) + mods |= InputModifiers.LeftMouseButton; + if (_properties.PointerUpdateKind == PointerUpdateKind.MiddleButtonReleased) + mods |= InputModifiers.MiddleMouseButton; + if (_properties.PointerUpdateKind == PointerUpdateKind.RightButtonReleased) + mods |= InputModifiers.RightMouseButton; + + return mods; + } + } + + public KeyModifiers KeyModifiers { get; } public Point GetPosition(IVisual relativeTo) { @@ -73,6 +105,8 @@ namespace Avalonia.Input public PointerPoint GetPointerPoint(IVisual relativeTo) => new PointerPoint(Pointer, GetPosition(relativeTo), _properties); + + protected PointerPointProperties Properties => _properties; } public enum MouseButton @@ -93,7 +127,7 @@ namespace Avalonia.Input IVisual rootVisual, Point rootVisualPosition, ulong timestamp, PointerPointProperties properties, - InputModifiers modifiers, + KeyModifiers modifiers, int obsoleteClickCount = 1) : base(InputElement.PointerPressedEvent, source, pointer, rootVisual, rootVisualPosition, timestamp, properties, modifiers) @@ -112,15 +146,15 @@ namespace Avalonia.Input public PointerReleasedEventArgs( IInteractive source, IPointer pointer, IVisual rootVisual, Point rootVisualPosition, ulong timestamp, - PointerPointProperties properties, InputModifiers modifiers, MouseButton obsoleteMouseButton) + PointerPointProperties properties, KeyModifiers modifiers) : base(InputElement.PointerReleasedEvent, source, pointer, rootVisual, rootVisualPosition, timestamp, properties, modifiers) { - MouseButton = obsoleteMouseButton; + } - [Obsolete()] - public MouseButton MouseButton { get; private set; } + [Obsolete("Use PointerUpdateKind")] + public MouseButton MouseButton => Properties.GetObsoleteMouseButton(); } public class PointerCaptureLostEventArgs : RoutedEventArgs diff --git a/src/Avalonia.Input/PointerPoint.cs b/src/Avalonia.Input/PointerPoint.cs index 7117b5709c..d823a78090 100644 --- a/src/Avalonia.Input/PointerPoint.cs +++ b/src/Avalonia.Input/PointerPoint.cs @@ -15,31 +15,61 @@ namespace Avalonia.Input public sealed class PointerPointProperties { - public bool IsLeftButtonPressed { get; set; } - public bool IsMiddleButtonPressed { get; set; } - public bool IsRightButtonPressed { get; set; } - - public PointerPointProperties() + public bool IsLeftButtonPressed { get; } + public bool IsMiddleButtonPressed { get; } + public bool IsRightButtonPressed { get; } + public PointerUpdateKind PointerUpdateKind { get; } + private PointerPointProperties() { } - public PointerPointProperties(InputModifiers modifiers) + public PointerPointProperties(RawInputModifiers modifiers, PointerUpdateKind kind) { - IsLeftButtonPressed = modifiers.HasFlag(InputModifiers.LeftMouseButton); - IsMiddleButtonPressed = modifiers.HasFlag(InputModifiers.MiddleMouseButton); - IsRightButtonPressed = modifiers.HasFlag(InputModifiers.RightMouseButton); + PointerUpdateKind = kind; + IsLeftButtonPressed = modifiers.HasFlag(RawInputModifiers.LeftMouseButton); + IsMiddleButtonPressed = modifiers.HasFlag(RawInputModifiers.MiddleMouseButton); + IsRightButtonPressed = modifiers.HasFlag(RawInputModifiers.RightMouseButton); + + // The underlying input source might be reporting the previous state, + // so make sure that we reflect the current state + + if (kind == PointerUpdateKind.LeftButtonPressed) + IsLeftButtonPressed = true; + if (kind == PointerUpdateKind.LeftButtonReleased) + IsLeftButtonPressed = false; + if (kind == PointerUpdateKind.MiddleButtonPressed) + IsMiddleButtonPressed = true; + if (kind == PointerUpdateKind.MiddleButtonReleased) + IsMiddleButtonPressed = false; + if (kind == PointerUpdateKind.RightButtonPressed) + IsRightButtonPressed = true; + if (kind == PointerUpdateKind.RightButtonReleased) + IsRightButtonPressed = false; } + + public static PointerPointProperties None { get; } = new PointerPointProperties(); public MouseButton GetObsoleteMouseButton() { - if (IsLeftButtonPressed) + if (PointerUpdateKind == PointerUpdateKind.LeftButtonPressed || PointerUpdateKind == PointerUpdateKind.LeftButtonReleased) return MouseButton.Left; - if (IsMiddleButtonPressed) + if (PointerUpdateKind == PointerUpdateKind.MiddleButtonPressed || PointerUpdateKind == PointerUpdateKind.MiddleButtonReleased) return MouseButton.Middle; - if (IsRightButtonPressed) + if (PointerUpdateKind == PointerUpdateKind.RightButtonPressed || PointerUpdateKind == PointerUpdateKind.RightButtonReleased) return MouseButton.Right; return MouseButton.None; } } + + public enum PointerUpdateKind + { + LeftButtonPressed, + MiddleButtonPressed, + RightButtonPressed, + LeftButtonReleased, + MiddleButtonReleased, + RightButtonReleased, + Other + } } diff --git a/src/Avalonia.Input/PointerWheelEventArgs.cs b/src/Avalonia.Input/PointerWheelEventArgs.cs index de1badfe96..3d7f93ddde 100644 --- a/src/Avalonia.Input/PointerWheelEventArgs.cs +++ b/src/Avalonia.Input/PointerWheelEventArgs.cs @@ -12,7 +12,7 @@ namespace Avalonia.Input public PointerWheelEventArgs(IInteractive source, IPointer pointer, IVisual rootVisual, Point rootVisualPosition, ulong timestamp, - PointerPointProperties properties, InputModifiers modifiers, Vector delta) + PointerPointProperties properties, KeyModifiers modifiers, Vector delta) : base(InputElement.PointerWheelChangedEvent, source, pointer, rootVisual, rootVisualPosition, timestamp, properties, modifiers) { diff --git a/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs b/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs index 186ad99efc..516234de7e 100644 --- a/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs +++ b/src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs @@ -11,7 +11,7 @@ namespace Avalonia.Input.Raw ulong timestamp, IInputRoot root, Point position, - Vector delta, InputModifiers inputModifiers) + Vector delta, RawInputModifiers inputModifiers) : base(device, timestamp, root, RawPointerEventType.Wheel, position, inputModifiers) { Delta = delta; diff --git a/src/Avalonia.Input/Raw/RawPointerEventArgs.cs b/src/Avalonia.Input/Raw/RawPointerEventArgs.cs index 6fac90f255..88f6daf11f 100644 --- a/src/Avalonia.Input/Raw/RawPointerEventArgs.cs +++ b/src/Avalonia.Input/Raw/RawPointerEventArgs.cs @@ -43,7 +43,7 @@ namespace Avalonia.Input.Raw IInputRoot root, RawPointerEventType type, Point position, - InputModifiers inputModifiers) + RawInputModifiers inputModifiers) : base(device, timestamp) { Contract.Requires(device != null); @@ -73,6 +73,6 @@ namespace Avalonia.Input.Raw /// /// Gets the input modifiers. /// - public InputModifiers InputModifiers { get; private set; } + public RawInputModifiers InputModifiers { get; private set; } } } diff --git a/src/Avalonia.Input/Raw/RawTouchEventArgs.cs b/src/Avalonia.Input/Raw/RawTouchEventArgs.cs index 5299633b26..020b40e55b 100644 --- a/src/Avalonia.Input/Raw/RawTouchEventArgs.cs +++ b/src/Avalonia.Input/Raw/RawTouchEventArgs.cs @@ -3,7 +3,7 @@ namespace Avalonia.Input.Raw public class RawTouchEventArgs : RawPointerEventArgs { public RawTouchEventArgs(IInputDevice device, ulong timestamp, IInputRoot root, - RawPointerEventType type, Point position, InputModifiers inputModifiers, + RawPointerEventType type, Point position, RawInputModifiers inputModifiers, long touchPointId) : base(device, timestamp, root, type, position, inputModifiers) { diff --git a/src/Avalonia.Input/TouchDevice.cs b/src/Avalonia.Input/TouchDevice.cs index c85f98b04a..765e02848f 100644 --- a/src/Avalonia.Input/TouchDevice.cs +++ b/src/Avalonia.Input/TouchDevice.cs @@ -15,14 +15,15 @@ namespace Avalonia.Input { Dictionary _pointers = new Dictionary(); - static InputModifiers GetModifiers(InputModifiers modifiers, bool left) + KeyModifiers GetKeyModifiers(RawInputModifiers modifiers) => + (KeyModifiers)(modifiers & RawInputModifiers.KeyboardMask); + + RawInputModifiers GetModifiers(RawInputModifiers modifiers, bool isLeftButtonDown) { - var mask = (InputModifiers)0x7fffffff ^ InputModifiers.LeftMouseButton ^ InputModifiers.MiddleMouseButton ^ - InputModifiers.RightMouseButton; - modifiers &= mask; - if (left) - modifiers |= InputModifiers.LeftMouseButton; - return modifiers; + var rv = modifiers &= RawInputModifiers.KeyboardMask; + if (isLeftButtonDown) + rv |= RawInputModifiers.LeftMouseButton; + return rv; } public void ProcessRawEvent(RawInputEventArgs ev) @@ -45,8 +46,9 @@ namespace Avalonia.Input { target.RaiseEvent(new PointerPressedEventArgs(target, pointer, args.Root, args.Position, ev.Timestamp, - new PointerPointProperties(GetModifiers(args.InputModifiers, pointer.IsPrimary)), - GetModifiers(args.InputModifiers, false))); + new PointerPointProperties(GetModifiers(args.InputModifiers, true), + PointerUpdateKind.LeftButtonPressed), + GetKeyModifiers(args.InputModifiers))); } if (args.Type == RawPointerEventType.TouchEnd) @@ -56,11 +58,12 @@ namespace Avalonia.Input { target.RaiseEvent(new PointerReleasedEventArgs(target, pointer, args.Root, args.Position, ev.Timestamp, - new PointerPointProperties(GetModifiers(args.InputModifiers, false)), - GetModifiers(args.InputModifiers, pointer.IsPrimary), - pointer.IsPrimary ? MouseButton.Left : MouseButton.None)); + new PointerPointProperties(GetModifiers(args.InputModifiers, false), + PointerUpdateKind.LeftButtonReleased), + GetKeyModifiers(args.InputModifiers))); } } + if (args.Type == RawPointerEventType.TouchCancel) { _pointers.Remove(args.TouchPointId); @@ -72,7 +75,9 @@ namespace Avalonia.Input { var modifiers = GetModifiers(args.InputModifiers, pointer.IsPrimary); target.RaiseEvent(new PointerEventArgs(InputElement.PointerMovedEvent, target, pointer, args.Root, - args.Position, ev.Timestamp, new PointerPointProperties(modifiers), modifiers)); + args.Position, ev.Timestamp, + new PointerPointProperties(GetModifiers(args.InputModifiers, true), PointerUpdateKind.Other), + GetKeyModifiers(args.InputModifiers))); } diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index dd03f7d81e..217fb4b078 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -223,11 +223,11 @@ namespace Avalonia.Native switch (type) { case AvnRawMouseEventType.Wheel: - Input?.Invoke(new RawMouseWheelEventArgs(_mouse, timeStamp, _inputRoot, point.ToAvaloniaPoint(), new Vector(delta.X, delta.Y), (InputModifiers)modifiers)); + Input?.Invoke(new RawMouseWheelEventArgs(_mouse, timeStamp, _inputRoot, point.ToAvaloniaPoint(), new Vector(delta.X, delta.Y), (RawInputModifiers)modifiers)); break; default: - Input?.Invoke(new RawPointerEventArgs(_mouse, timeStamp, _inputRoot, (RawPointerEventType)type, point.ToAvaloniaPoint(), (InputModifiers)modifiers)); + Input?.Invoke(new RawPointerEventArgs(_mouse, timeStamp, _inputRoot, (RawPointerEventType)type, point.ToAvaloniaPoint(), (RawInputModifiers)modifiers)); break; } } diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 95b3e40063..accd7ea40a 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -560,23 +560,23 @@ namespace Avalonia.X11 RawInputModifiers TranslateRawModifiers(XModifierMask state) => (RawInputModifiers)TranslateModifiers(state); - InputModifiers TranslateModifiers(XModifierMask state) + RawInputModifiers TranslateModifiers(XModifierMask state) { - var rv = default(InputModifiers); + var rv = default(RawInputModifiers); if (state.HasFlag(XModifierMask.Button1Mask)) - rv |= InputModifiers.LeftMouseButton; + rv |= RawInputModifiers.LeftMouseButton; if (state.HasFlag(XModifierMask.Button2Mask)) - rv |= InputModifiers.RightMouseButton; + rv |= RawInputModifiers.RightMouseButton; if (state.HasFlag(XModifierMask.Button2Mask)) - rv |= InputModifiers.MiddleMouseButton; + rv |= RawInputModifiers.MiddleMouseButton; if (state.HasFlag(XModifierMask.ShiftMask)) - rv |= InputModifiers.Shift; + rv |= RawInputModifiers.Shift; if (state.HasFlag(XModifierMask.ControlMask)) - rv |= InputModifiers.Control; + rv |= RawInputModifiers.Control; if (state.HasFlag(XModifierMask.Mod1Mask)) - rv |= InputModifiers.Alt; + rv |= RawInputModifiers.Alt; if (state.HasFlag(XModifierMask.Mod4Mask)) - rv |= InputModifiers.Windows; + rv |= RawInputModifiers.Meta; return rv; } diff --git a/src/Avalonia.X11/XI2Manager.cs b/src/Avalonia.X11/XI2Manager.cs index 0a78c0dfd9..cf75572601 100644 --- a/src/Avalonia.X11/XI2Manager.cs +++ b/src/Avalonia.X11/XI2Manager.cs @@ -247,7 +247,7 @@ namespace Avalonia.X11 unsafe class ParsedDeviceEvent { public XiEventType Type { get; } - public InputModifiers Modifiers { get; } + public RawInputModifiers Modifiers { get; } public ulong Timestamp { get; } public Point Position { get; } public int Button { get; set; } @@ -260,25 +260,25 @@ namespace Avalonia.X11 Timestamp = (ulong)ev->time.ToInt64(); var state = (XModifierMask)ev->mods.Effective; if (state.HasFlag(XModifierMask.ShiftMask)) - Modifiers |= InputModifiers.Shift; + Modifiers |= RawInputModifiers.Shift; if (state.HasFlag(XModifierMask.ControlMask)) - Modifiers |= InputModifiers.Control; + Modifiers |= RawInputModifiers.Control; if (state.HasFlag(XModifierMask.Mod1Mask)) - Modifiers |= InputModifiers.Alt; + Modifiers |= RawInputModifiers.Alt; if (state.HasFlag(XModifierMask.Mod4Mask)) - Modifiers |= InputModifiers.Windows; + Modifiers |= RawInputModifiers.Meta; if (ev->buttons.MaskLen > 0) { var buttons = ev->buttons.Mask; if (XIMaskIsSet(buttons, 1)) - Modifiers |= InputModifiers.LeftMouseButton; + Modifiers |= RawInputModifiers.LeftMouseButton; if (XIMaskIsSet(buttons, 2)) - Modifiers |= InputModifiers.MiddleMouseButton; + Modifiers |= RawInputModifiers.MiddleMouseButton; if (XIMaskIsSet(buttons, 3)) - Modifiers |= InputModifiers.RightMouseButton; + Modifiers |= RawInputModifiers.RightMouseButton; } Valuators = new Dictionary(); diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs index 723028c666..432344955a 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs @@ -125,7 +125,7 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput : type == LibInputEventType.LIBINPUT_EVENT_TOUCH_UP ? RawPointerEventType.TouchEnd : type == LibInputEventType.LIBINPUT_EVENT_TOUCH_MOTION ? RawPointerEventType.TouchUpdate : RawPointerEventType.TouchCancel, - pt, InputModifiers.None, slot)); + pt, RawInputModifiers.None, slot)); } } @@ -140,7 +140,7 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput _mousePosition = new Point(libinput_event_pointer_get_absolute_x_transformed(pev, (int)info.Width), libinput_event_pointer_get_absolute_y_transformed(pev, (int)info.Height)); ScheduleInput(new RawPointerEventArgs(_mouse, ts, _inputRoot, RawPointerEventType.Move, _mousePosition, - InputModifiers.None)); + RawInputModifiers.None)); } else if (type == LibInputEventType.LIBINPUT_EVENT_POINTER_BUTTON) { @@ -162,7 +162,7 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput ScheduleInput( - new RawPointerEventArgs(_mouse, ts, _inputRoot, evnt, _mousePosition, InputModifiers.None)); + new RawPointerEventArgs(_mouse, ts, _inputRoot, evnt, _mousePosition, RawInputModifiers.None)); } } diff --git a/src/Windows/Avalonia.Win32/Input/WindowsKeyboardDevice.cs b/src/Windows/Avalonia.Win32/Input/WindowsKeyboardDevice.cs index 93adf7bee3..233f110c37 100644 --- a/src/Windows/Avalonia.Win32/Input/WindowsKeyboardDevice.cs +++ b/src/Windows/Avalonia.Win32/Input/WindowsKeyboardDevice.cs @@ -14,32 +14,32 @@ namespace Avalonia.Win32.Input public new static WindowsKeyboardDevice Instance { get; } = new WindowsKeyboardDevice(); - public RawInputModifiers RawModifiers => (RawInputModifiers)Modifiers; - public InputModifiers Modifiers + public RawInputModifiers RawModifiers => Modifiers; + public RawInputModifiers Modifiers { get { UpdateKeyStates(); - InputModifiers result = 0; + RawInputModifiers result = 0; if (IsDown(Key.LeftAlt) || IsDown(Key.RightAlt)) { - result |= InputModifiers.Alt; + result |= RawInputModifiers.Alt; } if (IsDown(Key.LeftCtrl) || IsDown(Key.RightCtrl)) { - result |= InputModifiers.Control; + result |= RawInputModifiers.Control; } if (IsDown(Key.LeftShift) || IsDown(Key.RightShift)) { - result |= InputModifiers.Shift; + result |= RawInputModifiers.Shift; } if (IsDown(Key.LWin) || IsDown(Key.RWin)) { - result |= InputModifiers.Windows; + result |= RawInputModifiers.Meta; } return result; diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 65fb2e447e..c3a0a9c717 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -762,16 +762,16 @@ namespace Avalonia.Win32 return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam); } - static InputModifiers GetMouseModifiers(IntPtr wParam) + static RawInputModifiers GetMouseModifiers(IntPtr wParam) { var keys = (UnmanagedMethods.ModifierKeys)ToInt32(wParam); var modifiers = WindowsKeyboardDevice.Instance.Modifiers; if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_LBUTTON)) - modifiers |= InputModifiers.LeftMouseButton; + modifiers |= RawInputModifiers.LeftMouseButton; if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_RBUTTON)) - modifiers |= InputModifiers.RightMouseButton; + modifiers |= RawInputModifiers.RightMouseButton; if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_MBUTTON)) - modifiers |= InputModifiers.MiddleMouseButton; + modifiers |= RawInputModifiers.MiddleMouseButton; return modifiers; } diff --git a/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs b/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs index ba4d6ca9c5..ff11bc513d 100644 --- a/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs @@ -11,14 +11,14 @@ namespace Avalonia.Controls.UnitTests.Platform public class DefaultMenuInteractionHandlerTests { static PointerEventArgs CreateArgs(RoutedEvent ev, IInteractive source) - => new PointerEventArgs(ev, source, new FakePointer(), (IVisual)source, default, 0, new PointerPointProperties(), default); + => new PointerEventArgs(ev, source, new FakePointer(), (IVisual)source, default, 0, PointerPointProperties.None, default); static PointerPressedEventArgs CreatePressed(IInteractive source) => new PointerPressedEventArgs(source, - new FakePointer(), (IVisual)source, default,0, new PointerPointProperties {IsLeftButtonPressed = true}, + new FakePointer(), (IVisual)source, default,0, new PointerPointProperties (RawInputModifiers.None, PointerUpdateKind.LeftButtonPressed), default); static PointerReleasedEventArgs CreateReleased(IInteractive source) => new PointerReleasedEventArgs(source, - new FakePointer(), (IVisual)source, default,0, new PointerPointProperties(), default, MouseButton.Left); + new FakePointer(), (IVisual)source, default,0, new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.LeftButtonReleased), default); public class TopLevel { diff --git a/tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs b/tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs index 983f541c2a..214aead521 100644 --- a/tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs +++ b/tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs @@ -231,7 +231,7 @@ namespace Avalonia.Input.UnitTests root, RawPointerEventType.Move, p, - InputModifiers.None)); + RawInputModifiers.None)); } private void SetHit(Mock renderer, IControl hit) diff --git a/tests/Avalonia.UnitTests/MouseTestHelper.cs b/tests/Avalonia.UnitTests/MouseTestHelper.cs index 00ad850cf8..d6e64936c7 100644 --- a/tests/Avalonia.UnitTests/MouseTestHelper.cs +++ b/tests/Avalonia.UnitTests/MouseTestHelper.cs @@ -32,7 +32,8 @@ namespace Avalonia.UnitTests private MouseButton _pressedButton; - InputModifiers GetModifiers(InputModifiers modifiers) => modifiers | _pressedButtons; + KeyModifiers GetModifiers(InputModifiers modifiers) => + (KeyModifiers)((int)modifiers & (int)RawInputModifiers.KeyboardMask); public void Down(IInteractive target, MouseButton mouseButton = MouseButton.Left, Point position = default, InputModifiers modifiers = default, int clickCount = 1) @@ -44,7 +45,11 @@ namespace Avalonia.UnitTests Point position = default, InputModifiers modifiers = default, int clickCount = 1) { _pressedButtons |= Convert(mouseButton); - var props = new PointerPointProperties(_pressedButtons); + var props = new PointerPointProperties((RawInputModifiers)_pressedButtons, + mouseButton == MouseButton.Left ? PointerUpdateKind.LeftButtonPressed + : mouseButton == MouseButton.Middle ? PointerUpdateKind.MiddleButtonPressed + : mouseButton == MouseButton.Right ? PointerUpdateKind.RightButtonPressed : PointerUpdateKind.Other + ); if (ButtonCount(props) > 1) Move(target, source, position); else @@ -60,7 +65,7 @@ namespace Avalonia.UnitTests public void Move(IInteractive target, IInteractive source, in Point position, InputModifiers modifiers = default) { target.RaiseEvent(new PointerEventArgs(InputElement.PointerMovedEvent, source, _pointer, (IVisual)target, position, - Timestamp(), new PointerPointProperties(_pressedButtons), GetModifiers(modifiers))); + Timestamp(), new PointerPointProperties((RawInputModifiers)_pressedButtons, PointerUpdateKind.Other), GetModifiers(modifiers))); } public void Up(IInteractive target, MouseButton mouseButton = MouseButton.Left, Point position = default, @@ -72,13 +77,17 @@ namespace Avalonia.UnitTests { var conv = Convert(mouseButton); _pressedButtons = (_pressedButtons | conv) ^ conv; - var props = new PointerPointProperties(_pressedButtons); + var props = new PointerPointProperties((RawInputModifiers)_pressedButtons, + mouseButton == MouseButton.Left ? PointerUpdateKind.LeftButtonReleased + : mouseButton == MouseButton.Middle ? PointerUpdateKind.MiddleButtonReleased + : mouseButton == MouseButton.Right ? PointerUpdateKind.RightButtonReleased : PointerUpdateKind.Other + ); if (ButtonCount(props) == 0) { _pointer.Capture(null); target.RaiseEvent(new PointerReleasedEventArgs(source, _pointer, (IVisual)target, position, Timestamp(), props, - GetModifiers(modifiers), _pressedButton)); + GetModifiers(modifiers))); } else Move(target, source, position); @@ -97,13 +106,13 @@ namespace Avalonia.UnitTests public void Enter(IInteractive target) { target.RaiseEvent(new PointerEventArgs(InputElement.PointerEnterEvent, target, _pointer, (IVisual)target, default, - Timestamp(), new PointerPointProperties(_pressedButtons), _pressedButtons)); + Timestamp(), new PointerPointProperties((RawInputModifiers)_pressedButtons, PointerUpdateKind.Other), KeyModifiers.None)); } public void Leave(IInteractive target) { target.RaiseEvent(new PointerEventArgs(InputElement.PointerLeaveEvent, target, _pointer, (IVisual)target, default, - Timestamp(), new PointerPointProperties(_pressedButtons), _pressedButtons)); + Timestamp(), new PointerPointProperties((RawInputModifiers)_pressedButtons, PointerUpdateKind.Other), KeyModifiers.None)); } }