Browse Source

Merge pull request #2829 from AvaloniaUI/pointerpoint

PointerPointUpdateKind + KeyModifiers
pull/2865/head
Nikita Tsukanov 7 years ago
committed by GitHub
parent
commit
f079e6574a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs
  2. 6
      src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
  3. 4
      src/Avalonia.Controls/MenuItem.cs
  4. 23
      src/Avalonia.Controls/Platform/InProcessDragSource.cs
  5. 24
      src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs
  6. 4
      src/Avalonia.Diagnostics/DevTools.xaml.cs
  7. 32
      src/Avalonia.Input/IKeyboardDevice.cs
  8. 5
      src/Avalonia.Input/KeyEventArgs.cs
  9. 9
      src/Avalonia.Input/KeyGesture.cs
  10. 2
      src/Avalonia.Input/KeyboardDevice.cs
  11. 85
      src/Avalonia.Input/MouseDevice.cs
  12. 38
      src/Avalonia.Input/PointerEventArgs.cs
  13. 54
      src/Avalonia.Input/PointerPoint.cs
  14. 2
      src/Avalonia.Input/PointerWheelEventArgs.cs
  15. 4
      src/Avalonia.Input/Raw/RawDragEvent.cs
  16. 4
      src/Avalonia.Input/Raw/RawKeyEventArgs.cs
  17. 2
      src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs
  18. 4
      src/Avalonia.Input/Raw/RawPointerEventArgs.cs
  19. 2
      src/Avalonia.Input/Raw/RawTouchEventArgs.cs
  20. 31
      src/Avalonia.Input/TouchDevice.cs
  21. 6
      src/Avalonia.Native/WindowImplBase.cs
  22. 19
      src/Avalonia.X11/X11Window.cs
  23. 16
      src/Avalonia.X11/XI2Manager.cs
  24. 6
      src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs
  25. 32
      src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs
  26. 12
      src/Windows/Avalonia.Win32/Input/WindowsKeyboardDevice.cs
  27. 18
      src/Windows/Avalonia.Win32/OleDropTarget.cs
  28. 8
      src/Windows/Avalonia.Win32/WindowImpl.cs
  29. 2
      src/iOS/Avalonia.iOS/Specific/KeyboardEventsHelper.cs
  30. 10
      src/iOS/Avalonia.iOS/TopLevelImpl.cs
  31. 6
      tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs
  32. 30
      tests/Avalonia.Controls.UnitTests/TextBoxTests.cs
  33. 2
      tests/Avalonia.Controls.UnitTests/TopLevelTests.cs
  34. 6
      tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
  35. 2
      tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs
  36. 23
      tests/Avalonia.UnitTests/MouseTestHelper.cs

8
src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidKeyboardEventsHelper.cs

@ -72,12 +72,12 @@ namespace Avalonia.Android.Platform.Specific.Helpers
return false; return false;
} }
private static InputModifiers GetModifierKeys(KeyEvent e) private static RawInputModifiers GetModifierKeys(KeyEvent e)
{ {
var rv = InputModifiers.None; var rv = RawInputModifiers.None;
if (e.IsCtrlPressed) rv |= InputModifiers.Control; if (e.IsCtrlPressed) rv |= RawInputModifiers.Control;
if (e.IsShiftPressed) rv |= InputModifiers.Shift; if (e.IsShiftPressed) rv |= RawInputModifiers.Shift;
return rv; return rv;
} }

6
src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs

@ -78,12 +78,12 @@ namespace Avalonia.Android.Platform.Specific.Helpers
if (mouseEventType == RawPointerEventType.LeftButtonDown) if (mouseEventType == RawPointerEventType.LeftButtonDown)
{ {
var me = new RawPointerEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot, var me = new RawPointerEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
RawPointerEventType.Move, _point, InputModifiers.None); RawPointerEventType.Move, _point, RawInputModifiers.None);
_view.Input(me); _view.Input(me);
} }
var mouseEvent = new RawPointerEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot, var mouseEvent = new RawPointerEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
mouseEventType.Value, _point, InputModifiers.LeftMouseButton); mouseEventType.Value, _point, RawInputModifiers.LeftMouseButton);
_view.Input(mouseEvent); _view.Input(mouseEvent);
if (e.Action == MotionEventActions.Move && mouseDevice.Captured == null) if (e.Action == MotionEventActions.Move && mouseDevice.Captured == null)
@ -102,7 +102,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers
(uint)eventTime.Ticks, (uint)eventTime.Ticks,
inputRoot, inputRoot,
_point, _point,
new Vector(vectorX * correction / ps, vectorY * correction / ps), InputModifiers.LeftMouseButton); new Vector(vectorX * correction / ps, vectorY * correction / ps), RawInputModifiers.LeftMouseButton);
_view.Input(mouseWheelEvent); _view.Input(mouseWheelEvent);
} }
_lastTouchMovePoint = _point; _lastTouchMovePoint = _point;

4
src/Avalonia.Controls/MenuItem.cs

@ -339,7 +339,7 @@ namespace Avalonia.Controls
var point = e.GetPointerPoint(null); var point = e.GetPointerPoint(null);
RaiseEvent(new PointerEventArgs(PointerEnterItemEvent, this, e.Pointer, this.VisualRoot, point.Position, RaiseEvent(new PointerEventArgs(PointerEnterItemEvent, this, e.Pointer, this.VisualRoot, point.Position,
e.Timestamp, point.Properties, e.InputModifiers)); e.Timestamp, point.Properties, e.KeyModifiers));
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -349,7 +349,7 @@ namespace Avalonia.Controls
var point = e.GetPointerPoint(null); var point = e.GetPointerPoint(null);
RaiseEvent(new PointerEventArgs(PointerLeaveItemEvent, this, e.Pointer, this.VisualRoot, point.Position, RaiseEvent(new PointerEventArgs(PointerLeaveItemEvent, this, e.Pointer, this.VisualRoot, point.Position,
e.Timestamp, point.Properties, e.InputModifiers)); e.Timestamp, point.Properties, e.KeyModifiers));
} }
/// <summary> /// <summary>

23
src/Avalonia.Controls/Platform/InProcessDragSource.cs

@ -14,7 +14,7 @@ namespace Avalonia.Platform
{ {
class InProcessDragSource : IPlatformDragSource 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 IDragDropDevice _dragDrop;
private readonly IInputManager _inputManager; private readonly IInputManager _inputManager;
private readonly Subject<DragDropEffects> _result = new Subject<DragDropEffects>(); private readonly Subject<DragDropEffects> _result = new Subject<DragDropEffects>();
@ -25,7 +25,7 @@ namespace Avalonia.Platform
private Point _lastPosition; private Point _lastPosition;
private StandardCursorType _lastCursorType; private StandardCursorType _lastCursorType;
private object _originalCursor; private object _originalCursor;
private InputModifiers? _initialInputModifiers; private RawInputModifiers? _initialInputModifiers;
public InProcessDragSource() public InProcessDragSource()
{ {
@ -56,8 +56,7 @@ namespace Avalonia.Platform
return DragDropEffects.None; return DragDropEffects.None;
} }
private DragDropEffects RaiseEventAndUpdateCursor(RawDragEventType type, IInputElement root, Point pt, RawInputModifiers modifiers)
private DragDropEffects RaiseEventAndUpdateCursor(RawDragEventType type, IInputElement root, Point pt, InputModifiers modifiers)
{ {
_lastPosition = pt; _lastPosition = pt;
@ -70,13 +69,13 @@ namespace Avalonia.Platform
return effect; return effect;
} }
private DragDropEffects GetPreferredEffect(DragDropEffects effect, InputModifiers modifiers) private DragDropEffects GetPreferredEffect(DragDropEffects effect, RawInputModifiers modifiers)
{ {
if (effect == DragDropEffects.Copy || effect == DragDropEffects.Move || effect == DragDropEffects.Link || effect == DragDropEffects.None) if (effect == DragDropEffects.Copy || effect == DragDropEffects.Move || effect == DragDropEffects.Link || effect == DragDropEffects.None)
return effect; // No need to check for the modifiers. return effect; // No need to check for the modifiers.
if (effect.HasFlag(DragDropEffects.Link) && modifiers.HasFlag(InputModifiers.Alt)) if (effect.HasFlag(DragDropEffects.Link) && modifiers.HasFlag(RawInputModifiers.Alt))
return DragDropEffects.Link; return DragDropEffects.Link;
if (effect.HasFlag(DragDropEffects.Copy) && modifiers.HasFlag(InputModifiers.Control)) if (effect.HasFlag(DragDropEffects.Copy) && modifiers.HasFlag(RawInputModifiers.Control))
return DragDropEffects.Copy; return DragDropEffects.Copy;
return DragDropEffects.Move; return DragDropEffects.Move;
} }
@ -132,7 +131,7 @@ namespace Avalonia.Platform
private void CancelDragging() private void CancelDragging()
{ {
if (_lastRoot != null) if (_lastRoot != null)
RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, _lastRoot, _lastPosition, InputModifiers.None); RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, _lastRoot, _lastPosition, RawInputModifiers.None);
UpdateCursor(null, DragDropEffects.None); UpdateCursor(null, DragDropEffects.None);
_result.OnNext(DragDropEffects.None); _result.OnNext(DragDropEffects.None);
} }
@ -160,7 +159,7 @@ namespace Avalonia.Platform
_initialInputModifiers = e.InputModifiers & MOUSE_INPUTMODIFIERS; _initialInputModifiers = e.InputModifiers & MOUSE_INPUTMODIFIERS;
void CheckDraggingAccepted(InputModifiers changedMouseButton) void CheckDraggingAccepted(RawInputModifiers changedMouseButton)
{ {
if (_initialInputModifiers.Value.HasFlag(changedMouseButton)) if (_initialInputModifiers.Value.HasFlag(changedMouseButton))
{ {
@ -185,11 +184,11 @@ namespace Avalonia.Platform
case RawPointerEventType.LeaveWindow: case RawPointerEventType.LeaveWindow:
RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, e.Root, e.Position, e.InputModifiers); break; RaiseEventAndUpdateCursor(RawDragEventType.DragLeave, e.Root, e.Position, e.InputModifiers); break;
case RawPointerEventType.LeftButtonUp: case RawPointerEventType.LeftButtonUp:
CheckDraggingAccepted(InputModifiers.LeftMouseButton); break; CheckDraggingAccepted(RawInputModifiers.LeftMouseButton); break;
case RawPointerEventType.MiddleButtonUp: case RawPointerEventType.MiddleButtonUp:
CheckDraggingAccepted(InputModifiers.MiddleMouseButton); break; CheckDraggingAccepted(RawInputModifiers.MiddleMouseButton); break;
case RawPointerEventType.RightButtonUp: case RawPointerEventType.RightButtonUp:
CheckDraggingAccepted(InputModifiers.RightMouseButton); break; CheckDraggingAccepted(RawInputModifiers.RightMouseButton); break;
case RawPointerEventType.Move: case RawPointerEventType.Move:
var mods = e.InputModifiers & MOUSE_INPUTMODIFIERS; var mods = e.InputModifiers & MOUSE_INPUTMODIFIERS;
if (_initialInputModifiers.Value != mods) if (_initialInputModifiers.Value != mods)

24
src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs

@ -57,9 +57,13 @@ namespace Avalonia.Controls.Remote.Server
} }
} }
private static InputModifiers GetAvaloniaInputModifiers (Avalonia.Remote.Protocol.Input.InputModifiers[] modifiers) private static RawInputModifiers GetAvaloniaRawInputModifiers(
Avalonia.Remote.Protocol.Input.InputModifiers[] modifiers)
=> (RawInputModifiers)GetAvaloniaInputModifiers(modifiers);
private static RawInputModifiers GetAvaloniaInputModifiers (Avalonia.Remote.Protocol.Input.InputModifiers[] modifiers)
{ {
var result = InputModifiers.None; var result = RawInputModifiers.None;
if (modifiers == null) if (modifiers == null)
{ {
@ -71,31 +75,31 @@ namespace Avalonia.Controls.Remote.Server
switch (modifier) switch (modifier)
{ {
case Avalonia.Remote.Protocol.Input.InputModifiers.Control: case Avalonia.Remote.Protocol.Input.InputModifiers.Control:
result |= InputModifiers.Control; result |= RawInputModifiers.Control;
break; break;
case Avalonia.Remote.Protocol.Input.InputModifiers.Alt: case Avalonia.Remote.Protocol.Input.InputModifiers.Alt:
result |= InputModifiers.Alt; result |= RawInputModifiers.Alt;
break; break;
case Avalonia.Remote.Protocol.Input.InputModifiers.Shift: case Avalonia.Remote.Protocol.Input.InputModifiers.Shift:
result |= InputModifiers.Shift; result |= RawInputModifiers.Shift;
break; break;
case Avalonia.Remote.Protocol.Input.InputModifiers.Windows: case Avalonia.Remote.Protocol.Input.InputModifiers.Windows:
result |= InputModifiers.Windows; result |= RawInputModifiers.Meta;
break; break;
case Avalonia.Remote.Protocol.Input.InputModifiers.LeftMouseButton: case Avalonia.Remote.Protocol.Input.InputModifiers.LeftMouseButton:
result |= InputModifiers.LeftMouseButton; result |= RawInputModifiers.LeftMouseButton;
break; break;
case Avalonia.Remote.Protocol.Input.InputModifiers.MiddleMouseButton: case Avalonia.Remote.Protocol.Input.InputModifiers.MiddleMouseButton:
result |= InputModifiers.MiddleMouseButton; result |= RawInputModifiers.MiddleMouseButton;
break; break;
case Avalonia.Remote.Protocol.Input.InputModifiers.RightMouseButton: case Avalonia.Remote.Protocol.Input.InputModifiers.RightMouseButton:
result |= InputModifiers.RightMouseButton; result |= RawInputModifiers.RightMouseButton;
break; break;
} }
} }
@ -225,7 +229,7 @@ namespace Avalonia.Controls.Remote.Server
0, 0,
key.IsDown ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp, key.IsDown ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
(Key)key.Key, (Key)key.Key,
GetAvaloniaInputModifiers(key.Modifiers))); GetAvaloniaRawInputModifiers(key.Modifiers)));
}, DispatcherPriority.Input); }, DispatcherPriority.Input);
} }
if(obj is TextInputEventMessage text) if(obj is TextInputEventMessage text)

4
src/Avalonia.Diagnostics/DevTools.xaml.cs

@ -116,9 +116,9 @@ namespace Avalonia.Diagnostics
private void RawKeyDown(RawKeyEventArgs e) private void RawKeyDown(RawKeyEventArgs e)
{ {
const InputModifiers modifiers = InputModifiers.Control | InputModifiers.Shift; const RawInputModifiers modifiers = RawInputModifiers.Control | RawInputModifiers.Shift;
if ((e.Modifiers) == modifiers) if (e.Modifiers == modifiers)
{ {
var point = (Root.VisualRoot as IInputRoot)?.MouseDevice?.GetPosition(Root) ?? default(Point); var point = (Root.VisualRoot as IInputRoot)?.MouseDevice?.GetPosition(Root) ?? default(Point);
var control = Root.GetVisualsAt(point, x => (!(x is AdornerLayer) && x.IsVisible)) var control = Root.GetVisualsAt(point, x => (!(x is AdornerLayer) && x.IsVisible))

32
src/Avalonia.Input/IKeyboardDevice.cs

@ -6,7 +6,7 @@ using System.ComponentModel;
namespace Avalonia.Input namespace Avalonia.Input
{ {
[Flags] [Flags, Obsolete("Use KeyModifiers and PointerPointProperties")]
public enum InputModifiers public enum InputModifiers
{ {
None = 0, None = 0,
@ -19,6 +19,16 @@ namespace Avalonia.Input
MiddleMouseButton = 64 MiddleMouseButton = 64
} }
[Flags]
public enum KeyModifiers
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Meta = 8,
}
[Flags] [Flags]
public enum KeyStates public enum KeyStates
{ {
@ -27,6 +37,26 @@ namespace Avalonia.Input
Toggled = 2, Toggled = 2,
} }
[Flags]
public enum RawInputModifiers
{
None = 0,
Alt = 1,
Control = 2,
Shift = 4,
Meta = 8,
LeftMouseButton = 16,
RightMouseButton = 32,
MiddleMouseButton = 64,
KeyboardMask = Alt | Control | Shift | Meta
}
internal static class KeyModifiersUtils
{
public static KeyModifiers ConvertToKey(RawInputModifiers modifiers) =>
(KeyModifiers)(modifiers & RawInputModifiers.KeyboardMask);
}
public interface IKeyboardDevice : IInputDevice, INotifyPropertyChanged public interface IKeyboardDevice : IInputDevice, INotifyPropertyChanged
{ {
IInputElement FocusedElement { get; } IInputElement FocusedElement { get; }

5
src/Avalonia.Input/KeyEventArgs.cs

@ -1,6 +1,7 @@
// Copyright (c) The Avalonia Project. All rights reserved. // Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Avalonia.Interactivity; using Avalonia.Interactivity;
namespace Avalonia.Input namespace Avalonia.Input
@ -11,6 +12,8 @@ namespace Avalonia.Input
public Key Key { get; set; } public Key Key { get; set; }
public InputModifiers Modifiers { get; set; } [Obsolete("Use KeyModifiers")]
public InputModifiers Modifiers => (InputModifiers)KeyModifiers;
public KeyModifiers KeyModifiers { get; set; }
} }
} }

9
src/Avalonia.Input/KeyGesture.cs

@ -51,7 +51,14 @@ namespace Avalonia.Input
public Key Key { get; set; } public Key Key { get; set; }
public InputModifiers Modifiers { get; set; } [Obsolete("Use KeyModifiers")]
public InputModifiers Modifiers
{
get => (InputModifiers)KeyModifiers;
set => KeyModifiers = (KeyModifiers)(((int)value) & 0xf);
}
public KeyModifiers KeyModifiers { get; set; }
static readonly Dictionary<string, Key> KeySynonyms = new Dictionary<string, Key> static readonly Dictionary<string, Key> KeySynonyms = new Dictionary<string, Key>

2
src/Avalonia.Input/KeyboardDevice.cs

@ -91,7 +91,7 @@ namespace Avalonia.Input
RoutedEvent = routedEvent, RoutedEvent = routedEvent,
Device = this, Device = this,
Key = keyInput.Key, Key = keyInput.Key,
Modifiers = keyInput.Modifiers, KeyModifiers = KeyModifiersUtils.ConvertToKey(keyInput.Modifiers),
Source = element, Source = element,
}; };

85
src/Avalonia.Input/MouseDevice.cs

@ -94,11 +94,13 @@ namespace Avalonia.Input
{ {
if (_pointer.Captured == null) 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 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); Position = e.Root.PointToScreen(e.Position);
var props = CreateProperties(e); var props = CreateProperties(e);
var keyModifiers = KeyModifiersUtils.ConvertToKey(e.InputModifiers);
switch (e.Type) switch (e.Type)
{ {
case RawPointerEventType.LeaveWindow: case RawPointerEventType.LeaveWindow:
LeaveWindow(mouse, e.Timestamp, e.Root, e.InputModifiers); LeaveWindow(mouse, e.Timestamp, e.Root, props, keyModifiers);
break; break;
case RawPointerEventType.LeftButtonDown: case RawPointerEventType.LeftButtonDown:
case RawPointerEventType.RightButtonDown: case RawPointerEventType.RightButtonDown:
case RawPointerEventType.MiddleButtonDown: case RawPointerEventType.MiddleButtonDown:
if (ButtonCount(props) > 1) 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 else
e.Handled = MouseDown(mouse, e.Timestamp, e.Root, e.Position, e.Handled = MouseDown(mouse, e.Timestamp, e.Root, e.Position,
props, e.InputModifiers); props, keyModifiers);
break; break;
case RawPointerEventType.LeftButtonUp: case RawPointerEventType.LeftButtonUp:
case RawPointerEventType.RightButtonUp: case RawPointerEventType.RightButtonUp:
case RawPointerEventType.MiddleButtonUp: case RawPointerEventType.MiddleButtonUp:
if (ButtonCount(props) != 0) 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 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; break;
case RawPointerEventType.Move: 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; break;
case RawPointerEventType.Wheel: 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; 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<ArgumentNullException>(device != null); Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null); Contract.Requires<ArgumentNullException>(root != null);
ClearPointerOver(this, timestamp, root, inputModifiers); ClearPointerOver(this, timestamp, root, properties, inputModifiers);
} }
PointerPointProperties CreateProperties(RawPointerEventArgs args) PointerPointProperties CreateProperties(RawPointerEventArgs args)
{ {
var rv = new PointerPointProperties(args.InputModifiers);
var kind = PointerUpdateKind.Other;
if (args.Type == RawPointerEventType.LeftButtonDown) if (args.Type == RawPointerEventType.LeftButtonDown)
rv.IsLeftButtonPressed = true; kind = PointerUpdateKind.LeftButtonPressed;
if (args.Type == RawPointerEventType.MiddleButtonDown) if (args.Type == RawPointerEventType.MiddleButtonDown)
rv.IsMiddleButtonPressed = true; kind = PointerUpdateKind.MiddleButtonPressed;
if (args.Type == RawPointerEventType.RightButtonDown) if (args.Type == RawPointerEventType.RightButtonDown)
rv.IsRightButtonPressed = true; kind = PointerUpdateKind.RightButtonPressed;
if (args.Type == RawPointerEventType.LeftButtonUp) if (args.Type == RawPointerEventType.LeftButtonUp)
rv.IsLeftButtonPressed = false; kind = PointerUpdateKind.LeftButtonReleased;
if (args.Type == RawPointerEventType.MiddleButtonUp) if (args.Type == RawPointerEventType.MiddleButtonUp)
rv.IsMiddleButtonPressed = false; kind = PointerUpdateKind.MiddleButtonReleased;
if (args.Type == RawPointerEventType.RightButtonUp) if (args.Type == RawPointerEventType.RightButtonUp)
rv.IsRightButtonPressed = false; kind = PointerUpdateKind.RightButtonReleased;
return rv;
return new PointerPointProperties(args.InputModifiers, kind);
} }
private MouseButton _lastMouseDownButton; private MouseButton _lastMouseDownButton;
private bool MouseDown(IMouseDevice device, ulong timestamp, IInputElement root, Point p, private bool MouseDown(IMouseDevice device, ulong timestamp, IInputElement root, Point p,
PointerPointProperties properties, PointerPointProperties properties,
InputModifiers inputModifiers) KeyModifiers inputModifiers)
{ {
Contract.Requires<ArgumentNullException>(device != null); Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null); Contract.Requires<ArgumentNullException>(root != null);
@ -221,7 +227,7 @@ namespace Avalonia.Input
} }
private bool MouseMove(IMouseDevice device, ulong timestamp, IInputRoot root, Point p, PointerPointProperties properties, private bool MouseMove(IMouseDevice device, ulong timestamp, IInputRoot root, Point p, PointerPointProperties properties,
InputModifiers inputModifiers) KeyModifiers inputModifiers)
{ {
Contract.Requires<ArgumentNullException>(device != null); Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null); Contract.Requires<ArgumentNullException>(root != null);
@ -230,11 +236,11 @@ namespace Avalonia.Input
if (_pointer.Captured == null) if (_pointer.Captured == null)
{ {
source = SetPointerOver(this, timestamp, root, p, inputModifiers); source = SetPointerOver(this, timestamp, root, p, properties, inputModifiers);
} }
else else
{ {
SetPointerOver(this, timestamp, root, _pointer.Captured, inputModifiers); SetPointerOver(this, timestamp, root, _pointer.Captured, properties, inputModifiers);
source = _pointer.Captured; source = _pointer.Captured;
} }
@ -246,7 +252,7 @@ namespace Avalonia.Input
} }
private bool MouseUp(IMouseDevice device, ulong timestamp, IInputRoot root, Point p, PointerPointProperties props, private bool MouseUp(IMouseDevice device, ulong timestamp, IInputRoot root, Point p, PointerPointProperties props,
InputModifiers inputModifiers) KeyModifiers inputModifiers)
{ {
Contract.Requires<ArgumentNullException>(device != null); Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null); Contract.Requires<ArgumentNullException>(root != null);
@ -256,8 +262,7 @@ namespace Avalonia.Input
if (hit != null) if (hit != null)
{ {
var source = GetSource(hit); var source = GetSource(hit);
var e = new PointerReleasedEventArgs(source, _pointer, root, p, timestamp, props, inputModifiers, var e = new PointerReleasedEventArgs(source, _pointer, root, p, timestamp, props, inputModifiers);
_lastMouseDownButton);
source?.RaiseEvent(e); source?.RaiseEvent(e);
_pointer.Capture(null); _pointer.Capture(null);
@ -269,7 +274,7 @@ namespace Avalonia.Input
private bool MouseWheel(IMouseDevice device, ulong timestamp, IInputRoot root, Point p, private bool MouseWheel(IMouseDevice device, ulong timestamp, IInputRoot root, Point p,
PointerPointProperties props, PointerPointProperties props,
Vector delta, InputModifiers inputModifiers) Vector delta, KeyModifiers inputModifiers)
{ {
Contract.Requires<ArgumentNullException>(device != null); Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null); Contract.Requires<ArgumentNullException>(root != null);
@ -304,19 +309,23 @@ namespace Avalonia.Input
return _pointer.Captured ?? root.InputHitTest(p); 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, 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<ArgumentNullException>(device != null); Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null); Contract.Requires<ArgumentNullException>(root != null);
var element = root.PointerOverElement; 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) 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<ArgumentNullException>(device != null); Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null); Contract.Requires<ArgumentNullException>(root != null);
@ -364,18 +375,20 @@ namespace Avalonia.Input
{ {
if (element != null) if (element != null)
{ {
SetPointerOver(device, timestamp, root, element, inputModifiers); SetPointerOver(device, timestamp, root, element, properties, inputModifiers);
} }
else else
{ {
ClearPointerOver(device, timestamp, root, inputModifiers); ClearPointerOver(device, timestamp, root, properties, inputModifiers);
} }
} }
return element; 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<ArgumentNullException>(device != null); Contract.Requires<ArgumentNullException>(device != null);
Contract.Requires<ArgumentNullException>(root != null); Contract.Requires<ArgumentNullException>(root != null);
@ -397,7 +410,7 @@ namespace Avalonia.Input
el = root.PointerOverElement; 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) if (el!=null && branch!=null && !el.IsAttachedToVisualTree)
{ {
ClearChildrenPointerOver(e,branch,false); ClearChildrenPointerOver(e,branch,false);

38
src/Avalonia.Input/PointerEventArgs.cs

@ -20,7 +20,7 @@ namespace Avalonia.Input
IVisual rootVisual, Point rootVisualPosition, IVisual rootVisual, Point rootVisualPosition,
ulong timestamp, ulong timestamp,
PointerPointProperties properties, PointerPointProperties properties,
InputModifiers modifiers) KeyModifiers modifiers)
: base(routedEvent) : base(routedEvent)
{ {
Source = source; Source = source;
@ -29,7 +29,7 @@ namespace Avalonia.Input
_properties = properties; _properties = properties;
Pointer = pointer; Pointer = pointer;
Timestamp = timestamp; Timestamp = timestamp;
InputModifiers = modifiers; KeyModifiers = modifiers;
} }
class EmulatedDevice : IPointerDevice class EmulatedDevice : IPointerDevice
@ -60,7 +60,24 @@ namespace Avalonia.Input
[Obsolete("Use Pointer to get pointer-specific information")] [Obsolete("Use Pointer to get pointer-specific information")]
public IPointerDevice Device => _device ?? (_device = new EmulatedDevice(this)); 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;
return mods;
}
}
public KeyModifiers KeyModifiers { get; }
public Point GetPosition(IVisual relativeTo) public Point GetPosition(IVisual relativeTo)
{ {
@ -73,6 +90,8 @@ namespace Avalonia.Input
public PointerPoint GetPointerPoint(IVisual relativeTo) public PointerPoint GetPointerPoint(IVisual relativeTo)
=> new PointerPoint(Pointer, GetPosition(relativeTo), _properties); => new PointerPoint(Pointer, GetPosition(relativeTo), _properties);
protected PointerPointProperties Properties => _properties;
} }
public enum MouseButton public enum MouseButton
@ -93,7 +112,7 @@ namespace Avalonia.Input
IVisual rootVisual, Point rootVisualPosition, IVisual rootVisual, Point rootVisualPosition,
ulong timestamp, ulong timestamp,
PointerPointProperties properties, PointerPointProperties properties,
InputModifiers modifiers, KeyModifiers modifiers,
int obsoleteClickCount = 1) int obsoleteClickCount = 1)
: base(InputElement.PointerPressedEvent, source, pointer, rootVisual, rootVisualPosition, : base(InputElement.PointerPressedEvent, source, pointer, rootVisual, rootVisualPosition,
timestamp, properties, modifiers) timestamp, properties, modifiers)
@ -104,7 +123,8 @@ namespace Avalonia.Input
[Obsolete("Use DoubleTapped or DoubleRightTapped event instead")] [Obsolete("Use DoubleTapped or DoubleRightTapped event instead")]
public int ClickCount => _obsoleteClickCount; public int ClickCount => _obsoleteClickCount;
[Obsolete] public MouseButton MouseButton => GetPointerPoint(null).Properties.GetObsoleteMouseButton(); [Obsolete("Use PointerUpdateKind")]
public MouseButton MouseButton => Properties.GetObsoleteMouseButton();
} }
public class PointerReleasedEventArgs : PointerEventArgs public class PointerReleasedEventArgs : PointerEventArgs
@ -112,15 +132,15 @@ namespace Avalonia.Input
public PointerReleasedEventArgs( public PointerReleasedEventArgs(
IInteractive source, IPointer pointer, IInteractive source, IPointer pointer,
IVisual rootVisual, Point rootVisualPosition, ulong timestamp, IVisual rootVisual, Point rootVisualPosition, ulong timestamp,
PointerPointProperties properties, InputModifiers modifiers, MouseButton obsoleteMouseButton) PointerPointProperties properties, KeyModifiers modifiers)
: base(InputElement.PointerReleasedEvent, source, pointer, rootVisual, rootVisualPosition, : base(InputElement.PointerReleasedEvent, source, pointer, rootVisual, rootVisualPosition,
timestamp, properties, modifiers) timestamp, properties, modifiers)
{ {
MouseButton = obsoleteMouseButton;
} }
[Obsolete()] [Obsolete("Use PointerUpdateKind")]
public MouseButton MouseButton { get; private set; } public MouseButton MouseButton => Properties.GetObsoleteMouseButton();
} }
public class PointerCaptureLostEventArgs : RoutedEventArgs public class PointerCaptureLostEventArgs : RoutedEventArgs

54
src/Avalonia.Input/PointerPoint.cs

@ -15,31 +15,61 @@ namespace Avalonia.Input
public sealed class PointerPointProperties public sealed class PointerPointProperties
{ {
public bool IsLeftButtonPressed { get; set; } public bool IsLeftButtonPressed { get; }
public bool IsMiddleButtonPressed { get; set; } public bool IsMiddleButtonPressed { get; }
public bool IsRightButtonPressed { get; set; } public bool IsRightButtonPressed { get; }
public PointerUpdateKind PointerUpdateKind { get; }
public PointerPointProperties() private PointerPointProperties()
{ {
} }
public PointerPointProperties(InputModifiers modifiers) public PointerPointProperties(RawInputModifiers modifiers, PointerUpdateKind kind)
{ {
IsLeftButtonPressed = modifiers.HasFlag(InputModifiers.LeftMouseButton); PointerUpdateKind = kind;
IsMiddleButtonPressed = modifiers.HasFlag(InputModifiers.MiddleMouseButton); IsLeftButtonPressed = modifiers.HasFlag(RawInputModifiers.LeftMouseButton);
IsRightButtonPressed = modifiers.HasFlag(InputModifiers.RightMouseButton); 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() public MouseButton GetObsoleteMouseButton()
{ {
if (IsLeftButtonPressed) if (PointerUpdateKind == PointerUpdateKind.LeftButtonPressed || PointerUpdateKind == PointerUpdateKind.LeftButtonReleased)
return MouseButton.Left; return MouseButton.Left;
if (IsMiddleButtonPressed) if (PointerUpdateKind == PointerUpdateKind.MiddleButtonPressed || PointerUpdateKind == PointerUpdateKind.MiddleButtonReleased)
return MouseButton.Middle; return MouseButton.Middle;
if (IsRightButtonPressed) if (PointerUpdateKind == PointerUpdateKind.RightButtonPressed || PointerUpdateKind == PointerUpdateKind.RightButtonReleased)
return MouseButton.Right; return MouseButton.Right;
return MouseButton.None; return MouseButton.None;
} }
} }
public enum PointerUpdateKind
{
LeftButtonPressed,
MiddleButtonPressed,
RightButtonPressed,
LeftButtonReleased,
MiddleButtonReleased,
RightButtonReleased,
Other
}
} }

2
src/Avalonia.Input/PointerWheelEventArgs.cs

@ -12,7 +12,7 @@ namespace Avalonia.Input
public PointerWheelEventArgs(IInteractive source, IPointer pointer, IVisual rootVisual, public PointerWheelEventArgs(IInteractive source, IPointer pointer, IVisual rootVisual,
Point rootVisualPosition, ulong timestamp, Point rootVisualPosition, ulong timestamp,
PointerPointProperties properties, InputModifiers modifiers, Vector delta) PointerPointProperties properties, KeyModifiers modifiers, Vector delta)
: base(InputElement.PointerWheelChangedEvent, source, pointer, rootVisual, rootVisualPosition, : base(InputElement.PointerWheelChangedEvent, source, pointer, rootVisual, rootVisualPosition,
timestamp, properties, modifiers) timestamp, properties, modifiers)
{ {

4
src/Avalonia.Input/Raw/RawDragEvent.cs

@ -10,7 +10,7 @@
public InputModifiers Modifiers { get; } public InputModifiers Modifiers { get; }
public RawDragEvent(IDragDropDevice inputDevice, RawDragEventType type, public RawDragEvent(IDragDropDevice inputDevice, RawDragEventType type,
IInputElement inputRoot, Point location, IDataObject data, DragDropEffects effects, InputModifiers modifiers) IInputElement inputRoot, Point location, IDataObject data, DragDropEffects effects, RawInputModifiers modifiers)
:base(inputDevice, 0) :base(inputDevice, 0)
{ {
Type = type; Type = type;
@ -18,7 +18,7 @@
Location = location; Location = location;
Data = data; Data = data;
Effects = effects; Effects = effects;
Modifiers = modifiers; Modifiers = (InputModifiers)modifiers;
} }
} }
} }

4
src/Avalonia.Input/Raw/RawKeyEventArgs.cs

@ -15,7 +15,7 @@ namespace Avalonia.Input.Raw
IKeyboardDevice device, IKeyboardDevice device,
ulong timestamp, ulong timestamp,
RawKeyEventType type, RawKeyEventType type,
Key key, InputModifiers modifiers) Key key, RawInputModifiers modifiers)
: base(device, timestamp) : base(device, timestamp)
{ {
Key = key; Key = key;
@ -25,7 +25,7 @@ namespace Avalonia.Input.Raw
public Key Key { get; set; } public Key Key { get; set; }
public InputModifiers Modifiers { get; set; } public RawInputModifiers Modifiers { get; set; }
public RawKeyEventType Type { get; set; } public RawKeyEventType Type { get; set; }
} }

2
src/Avalonia.Input/Raw/RawMouseWheelEventArgs.cs

@ -11,7 +11,7 @@ namespace Avalonia.Input.Raw
ulong timestamp, ulong timestamp,
IInputRoot root, IInputRoot root,
Point position, Point position,
Vector delta, InputModifiers inputModifiers) Vector delta, RawInputModifiers inputModifiers)
: base(device, timestamp, root, RawPointerEventType.Wheel, position, inputModifiers) : base(device, timestamp, root, RawPointerEventType.Wheel, position, inputModifiers)
{ {
Delta = delta; Delta = delta;

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

@ -43,7 +43,7 @@ namespace Avalonia.Input.Raw
IInputRoot root, IInputRoot root,
RawPointerEventType type, RawPointerEventType type,
Point position, Point position,
InputModifiers inputModifiers) RawInputModifiers inputModifiers)
: base(device, timestamp) : base(device, timestamp)
{ {
Contract.Requires<ArgumentNullException>(device != null); Contract.Requires<ArgumentNullException>(device != null);
@ -73,6 +73,6 @@ namespace Avalonia.Input.Raw
/// <summary> /// <summary>
/// Gets the input modifiers. /// Gets the input modifiers.
/// </summary> /// </summary>
public InputModifiers InputModifiers { get; private set; } public RawInputModifiers InputModifiers { get; private set; }
} }
} }

2
src/Avalonia.Input/Raw/RawTouchEventArgs.cs

@ -3,7 +3,7 @@ namespace Avalonia.Input.Raw
public class RawTouchEventArgs : RawPointerEventArgs public class RawTouchEventArgs : RawPointerEventArgs
{ {
public RawTouchEventArgs(IInputDevice device, ulong timestamp, IInputRoot root, public RawTouchEventArgs(IInputDevice device, ulong timestamp, IInputRoot root,
RawPointerEventType type, Point position, InputModifiers inputModifiers, RawPointerEventType type, Point position, RawInputModifiers inputModifiers,
long touchPointId) long touchPointId)
: base(device, timestamp, root, type, position, inputModifiers) : base(device, timestamp, root, type, position, inputModifiers)
{ {

31
src/Avalonia.Input/TouchDevice.cs

@ -15,14 +15,15 @@ namespace Avalonia.Input
{ {
Dictionary<long, Pointer> _pointers = new Dictionary<long, Pointer>(); Dictionary<long, Pointer> _pointers = new Dictionary<long, Pointer>();
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 ^ var rv = modifiers &= RawInputModifiers.KeyboardMask;
InputModifiers.RightMouseButton; if (isLeftButtonDown)
modifiers &= mask; rv |= RawInputModifiers.LeftMouseButton;
if (left) return rv;
modifiers |= InputModifiers.LeftMouseButton;
return modifiers;
} }
public void ProcessRawEvent(RawInputEventArgs ev) public void ProcessRawEvent(RawInputEventArgs ev)
@ -45,8 +46,9 @@ namespace Avalonia.Input
{ {
target.RaiseEvent(new PointerPressedEventArgs(target, pointer, target.RaiseEvent(new PointerPressedEventArgs(target, pointer,
args.Root, args.Position, ev.Timestamp, args.Root, args.Position, ev.Timestamp,
new PointerPointProperties(GetModifiers(args.InputModifiers, pointer.IsPrimary)), new PointerPointProperties(GetModifiers(args.InputModifiers, true),
GetModifiers(args.InputModifiers, false))); PointerUpdateKind.LeftButtonPressed),
GetKeyModifiers(args.InputModifiers)));
} }
if (args.Type == RawPointerEventType.TouchEnd) if (args.Type == RawPointerEventType.TouchEnd)
@ -56,11 +58,12 @@ namespace Avalonia.Input
{ {
target.RaiseEvent(new PointerReleasedEventArgs(target, pointer, target.RaiseEvent(new PointerReleasedEventArgs(target, pointer,
args.Root, args.Position, ev.Timestamp, args.Root, args.Position, ev.Timestamp,
new PointerPointProperties(GetModifiers(args.InputModifiers, false)), new PointerPointProperties(GetModifiers(args.InputModifiers, false),
GetModifiers(args.InputModifiers, pointer.IsPrimary), PointerUpdateKind.LeftButtonReleased),
pointer.IsPrimary ? MouseButton.Left : MouseButton.None)); GetKeyModifiers(args.InputModifiers)));
} }
} }
if (args.Type == RawPointerEventType.TouchCancel) if (args.Type == RawPointerEventType.TouchCancel)
{ {
_pointers.Remove(args.TouchPointId); _pointers.Remove(args.TouchPointId);
@ -72,7 +75,9 @@ namespace Avalonia.Input
{ {
var modifiers = GetModifiers(args.InputModifiers, pointer.IsPrimary); var modifiers = GetModifiers(args.InputModifiers, pointer.IsPrimary);
target.RaiseEvent(new PointerEventArgs(InputElement.PointerMovedEvent, target, pointer, args.Root, 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)));
} }

6
src/Avalonia.Native/WindowImplBase.cs

@ -209,7 +209,7 @@ namespace Avalonia.Native
{ {
Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1); Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
var args = new RawKeyEventArgs(_keyboard, timeStamp, (RawKeyEventType)type, (Key)key, (InputModifiers)modifiers); var args = new RawKeyEventArgs(_keyboard, timeStamp, (RawKeyEventType)type, (Key)key, (RawInputModifiers)modifiers);
Input?.Invoke(args); Input?.Invoke(args);
@ -223,11 +223,11 @@ namespace Avalonia.Native
switch (type) switch (type)
{ {
case AvnRawMouseEventType.Wheel: 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; break;
default: 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; break;
} }
} }

19
src/Avalonia.X11/X11Window.cs

@ -558,24 +558,23 @@ namespace Avalonia.X11
} }
RawInputModifiers TranslateModifiers(XModifierMask state)
InputModifiers TranslateModifiers(XModifierMask state)
{ {
var rv = default(InputModifiers); var rv = default(RawInputModifiers);
if (state.HasFlag(XModifierMask.Button1Mask)) if (state.HasFlag(XModifierMask.Button1Mask))
rv |= InputModifiers.LeftMouseButton; rv |= RawInputModifiers.LeftMouseButton;
if (state.HasFlag(XModifierMask.Button2Mask)) if (state.HasFlag(XModifierMask.Button2Mask))
rv |= InputModifiers.RightMouseButton; rv |= RawInputModifiers.RightMouseButton;
if (state.HasFlag(XModifierMask.Button2Mask)) if (state.HasFlag(XModifierMask.Button2Mask))
rv |= InputModifiers.MiddleMouseButton; rv |= RawInputModifiers.MiddleMouseButton;
if (state.HasFlag(XModifierMask.ShiftMask)) if (state.HasFlag(XModifierMask.ShiftMask))
rv |= InputModifiers.Shift; rv |= RawInputModifiers.Shift;
if (state.HasFlag(XModifierMask.ControlMask)) if (state.HasFlag(XModifierMask.ControlMask))
rv |= InputModifiers.Control; rv |= RawInputModifiers.Control;
if (state.HasFlag(XModifierMask.Mod1Mask)) if (state.HasFlag(XModifierMask.Mod1Mask))
rv |= InputModifiers.Alt; rv |= RawInputModifiers.Alt;
if (state.HasFlag(XModifierMask.Mod4Mask)) if (state.HasFlag(XModifierMask.Mod4Mask))
rv |= InputModifiers.Windows; rv |= RawInputModifiers.Meta;
return rv; return rv;
} }

16
src/Avalonia.X11/XI2Manager.cs

@ -247,7 +247,7 @@ namespace Avalonia.X11
unsafe class ParsedDeviceEvent unsafe class ParsedDeviceEvent
{ {
public XiEventType Type { get; } public XiEventType Type { get; }
public InputModifiers Modifiers { get; } public RawInputModifiers Modifiers { get; }
public ulong Timestamp { get; } public ulong Timestamp { get; }
public Point Position { get; } public Point Position { get; }
public int Button { get; set; } public int Button { get; set; }
@ -260,25 +260,25 @@ namespace Avalonia.X11
Timestamp = (ulong)ev->time.ToInt64(); Timestamp = (ulong)ev->time.ToInt64();
var state = (XModifierMask)ev->mods.Effective; var state = (XModifierMask)ev->mods.Effective;
if (state.HasFlag(XModifierMask.ShiftMask)) if (state.HasFlag(XModifierMask.ShiftMask))
Modifiers |= InputModifiers.Shift; Modifiers |= RawInputModifiers.Shift;
if (state.HasFlag(XModifierMask.ControlMask)) if (state.HasFlag(XModifierMask.ControlMask))
Modifiers |= InputModifiers.Control; Modifiers |= RawInputModifiers.Control;
if (state.HasFlag(XModifierMask.Mod1Mask)) if (state.HasFlag(XModifierMask.Mod1Mask))
Modifiers |= InputModifiers.Alt; Modifiers |= RawInputModifiers.Alt;
if (state.HasFlag(XModifierMask.Mod4Mask)) if (state.HasFlag(XModifierMask.Mod4Mask))
Modifiers |= InputModifiers.Windows; Modifiers |= RawInputModifiers.Meta;
if (ev->buttons.MaskLen > 0) if (ev->buttons.MaskLen > 0)
{ {
var buttons = ev->buttons.Mask; var buttons = ev->buttons.Mask;
if (XIMaskIsSet(buttons, 1)) if (XIMaskIsSet(buttons, 1))
Modifiers |= InputModifiers.LeftMouseButton; Modifiers |= RawInputModifiers.LeftMouseButton;
if (XIMaskIsSet(buttons, 2)) if (XIMaskIsSet(buttons, 2))
Modifiers |= InputModifiers.MiddleMouseButton; Modifiers |= RawInputModifiers.MiddleMouseButton;
if (XIMaskIsSet(buttons, 3)) if (XIMaskIsSet(buttons, 3))
Modifiers |= InputModifiers.RightMouseButton; Modifiers |= RawInputModifiers.RightMouseButton;
} }
Valuators = new Dictionary<int, double>(); Valuators = new Dictionary<int, double>();

6
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_UP ? RawPointerEventType.TouchEnd
: type == LibInputEventType.LIBINPUT_EVENT_TOUCH_MOTION ? RawPointerEventType.TouchUpdate : type == LibInputEventType.LIBINPUT_EVENT_TOUCH_MOTION ? RawPointerEventType.TouchUpdate
: RawPointerEventType.TouchCancel, : 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), _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)); libinput_event_pointer_get_absolute_y_transformed(pev, (int)info.Height));
ScheduleInput(new RawPointerEventArgs(_mouse, ts, _inputRoot, RawPointerEventType.Move, _mousePosition, ScheduleInput(new RawPointerEventArgs(_mouse, ts, _inputRoot, RawPointerEventType.Move, _mousePosition,
InputModifiers.None)); RawInputModifiers.None));
} }
else if (type == LibInputEventType.LIBINPUT_EVENT_POINTER_BUTTON) else if (type == LibInputEventType.LIBINPUT_EVENT_POINTER_BUTTON)
{ {
@ -162,7 +162,7 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
ScheduleInput( ScheduleInput(
new RawPointerEventArgs(_mouse, ts, _inputRoot, evnt, _mousePosition, InputModifiers.None)); new RawPointerEventArgs(_mouse, ts, _inputRoot, evnt, _mousePosition, RawInputModifiers.None));
} }
} }

32
src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs

@ -142,27 +142,33 @@ namespace Avalonia.Win32.Interop.Wpf
protected override void OnLostFocus(RoutedEventArgs e) => LostFocus?.Invoke(); protected override void OnLostFocus(RoutedEventArgs e) => LostFocus?.Invoke();
InputModifiers GetModifiers() RawInputModifiers GetModifiers(MouseEventArgs e)
{ {
var state = Keyboard.Modifiers; var state = Keyboard.Modifiers;
var rv = default(InputModifiers); var rv = default(RawInputModifiers);
if (state.HasFlag(ModifierKeys.Windows)) if (state.HasFlag(ModifierKeys.Windows))
rv |= InputModifiers.Windows; rv |= RawInputModifiers.Meta;
if (state.HasFlag(ModifierKeys.Alt)) if (state.HasFlag(ModifierKeys.Alt))
rv |= InputModifiers.Alt; rv |= RawInputModifiers.Alt;
if (state.HasFlag(ModifierKeys.Control)) if (state.HasFlag(ModifierKeys.Control))
rv |= InputModifiers.Control; rv |= RawInputModifiers.Control;
if (state.HasFlag(ModifierKeys.Shift)) if (state.HasFlag(ModifierKeys.Shift))
rv |= InputModifiers.Shift; rv |= RawInputModifiers.Shift;
//TODO: mouse modifiers if (e != null)
{
if (e.LeftButton == MouseButtonState.Pressed)
rv |= RawInputModifiers.LeftMouseButton;
if (e.RightButton == MouseButtonState.Pressed)
rv |= RawInputModifiers.RightMouseButton;
if (e.MiddleButton == MouseButtonState.Pressed)
rv |= RawInputModifiers.MiddleMouseButton;
}
return rv; return rv;
} }
void MouseEvent(RawPointerEventType type, MouseEventArgs e) void MouseEvent(RawPointerEventType type, MouseEventArgs e)
=> _ttl.Input?.Invoke(new RawPointerEventArgs(_mouse, (uint)e.Timestamp, _inputRoot, type, => _ttl.Input?.Invoke(new RawPointerEventArgs(_mouse, (uint)e.Timestamp, _inputRoot, type,
e.GetPosition(this).ToAvaloniaPoint(), GetModifiers())); e.GetPosition(this).ToAvaloniaPoint(), GetModifiers(e)));
protected override void OnMouseDown(MouseButtonEventArgs e) protected override void OnMouseDown(MouseButtonEventArgs e)
{ {
@ -201,19 +207,19 @@ namespace Avalonia.Win32.Interop.Wpf
protected override void OnMouseWheel(MouseWheelEventArgs e) => protected override void OnMouseWheel(MouseWheelEventArgs e) =>
_ttl.Input?.Invoke(new RawMouseWheelEventArgs(_mouse, (uint) e.Timestamp, _inputRoot, _ttl.Input?.Invoke(new RawMouseWheelEventArgs(_mouse, (uint) e.Timestamp, _inputRoot,
e.GetPosition(this).ToAvaloniaPoint(), new Vector(0, e.Delta), GetModifiers())); e.GetPosition(this).ToAvaloniaPoint(), new Vector(0, e.Delta), GetModifiers(e)));
protected override void OnMouseLeave(MouseEventArgs e) => MouseEvent(RawPointerEventType.LeaveWindow, e); protected override void OnMouseLeave(MouseEventArgs e) => MouseEvent(RawPointerEventType.LeaveWindow, e);
protected override void OnKeyDown(KeyEventArgs e) protected override void OnKeyDown(KeyEventArgs e)
=> _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint) e.Timestamp, RawKeyEventType.KeyDown, => _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint) e.Timestamp, RawKeyEventType.KeyDown,
(Key) e.Key, (Key) e.Key,
GetModifiers())); GetModifiers(null)));
protected override void OnKeyUp(KeyEventArgs e) protected override void OnKeyUp(KeyEventArgs e)
=> _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint)e.Timestamp, RawKeyEventType.KeyUp, => _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint)e.Timestamp, RawKeyEventType.KeyUp,
(Key)e.Key, (Key)e.Key,
GetModifiers())); GetModifiers(null)));
protected override void OnTextInput(TextCompositionEventArgs e) protected override void OnTextInput(TextCompositionEventArgs e)
=> _ttl.Input?.Invoke(new RawTextInputEventArgs(_keyboard, (uint) e.Timestamp, e.Text)); => _ttl.Input?.Invoke(new RawTextInputEventArgs(_keyboard, (uint) e.Timestamp, e.Text));

12
src/Windows/Avalonia.Win32/Input/WindowsKeyboardDevice.cs

@ -14,31 +14,31 @@ namespace Avalonia.Win32.Input
public new static WindowsKeyboardDevice Instance { get; } = new WindowsKeyboardDevice(); public new static WindowsKeyboardDevice Instance { get; } = new WindowsKeyboardDevice();
public InputModifiers Modifiers public RawInputModifiers Modifiers
{ {
get get
{ {
UpdateKeyStates(); UpdateKeyStates();
InputModifiers result = 0; RawInputModifiers result = 0;
if (IsDown(Key.LeftAlt) || IsDown(Key.RightAlt)) if (IsDown(Key.LeftAlt) || IsDown(Key.RightAlt))
{ {
result |= InputModifiers.Alt; result |= RawInputModifiers.Alt;
} }
if (IsDown(Key.LeftCtrl) || IsDown(Key.RightCtrl)) if (IsDown(Key.LeftCtrl) || IsDown(Key.RightCtrl))
{ {
result |= InputModifiers.Control; result |= RawInputModifiers.Control;
} }
if (IsDown(Key.LeftShift) || IsDown(Key.RightShift)) if (IsDown(Key.LeftShift) || IsDown(Key.RightShift))
{ {
result |= InputModifiers.Shift; result |= RawInputModifiers.Shift;
} }
if (IsDown(Key.LWin) || IsDown(Key.RWin)) if (IsDown(Key.LWin) || IsDown(Key.RWin))
{ {
result |= InputModifiers.Windows; result |= RawInputModifiers.Meta;
} }
return result; return result;

18
src/Windows/Avalonia.Win32/OleDropTarget.cs

@ -45,23 +45,23 @@ namespace Avalonia.Win32
return result; return result;
} }
private static InputModifiers ConvertKeyState(int grfKeyState) private static RawInputModifiers ConvertKeyState(int grfKeyState)
{ {
InputModifiers modifiers = InputModifiers.None; var modifiers = RawInputModifiers.None;
var state = (UnmanagedMethods.ModifierKeys)grfKeyState; var state = (UnmanagedMethods.ModifierKeys)grfKeyState;
if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_LBUTTON)) if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_LBUTTON))
modifiers |= InputModifiers.LeftMouseButton; modifiers |= RawInputModifiers.LeftMouseButton;
if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_MBUTTON)) if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_MBUTTON))
modifiers |= InputModifiers.MiddleMouseButton; modifiers |= RawInputModifiers.MiddleMouseButton;
if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_RBUTTON)) if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_RBUTTON))
modifiers |= InputModifiers.RightMouseButton; modifiers |= RawInputModifiers.RightMouseButton;
if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_SHIFT)) if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_SHIFT))
modifiers |= InputModifiers.Shift; modifiers |= RawInputModifiers.Shift;
if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_CONTROL)) if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_CONTROL))
modifiers |= InputModifiers.Control; modifiers |= RawInputModifiers.Control;
if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_ALT)) if (state.HasFlag(UnmanagedMethods.ModifierKeys.MK_ALT))
modifiers |= InputModifiers.Alt; modifiers |= RawInputModifiers.Alt;
return modifiers; return modifiers;
} }
@ -127,7 +127,7 @@ namespace Avalonia.Win32
default(Point), default(Point),
null, null,
DragDropEffects.None, DragDropEffects.None,
InputModifiers.None RawInputModifiers.None
)); ));
return UnmanagedMethods.HRESULT.S_OK; return UnmanagedMethods.HRESULT.S_OK;
} }

8
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -762,16 +762,16 @@ namespace Avalonia.Win32
return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam); return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam);
} }
static InputModifiers GetMouseModifiers(IntPtr wParam) static RawInputModifiers GetMouseModifiers(IntPtr wParam)
{ {
var keys = (UnmanagedMethods.ModifierKeys)ToInt32(wParam); var keys = (UnmanagedMethods.ModifierKeys)ToInt32(wParam);
var modifiers = WindowsKeyboardDevice.Instance.Modifiers; var modifiers = WindowsKeyboardDevice.Instance.Modifiers;
if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_LBUTTON)) if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_LBUTTON))
modifiers |= InputModifiers.LeftMouseButton; modifiers |= RawInputModifiers.LeftMouseButton;
if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_RBUTTON)) if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_RBUTTON))
modifiers |= InputModifiers.RightMouseButton; modifiers |= RawInputModifiers.RightMouseButton;
if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_MBUTTON)) if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_MBUTTON))
modifiers |= InputModifiers.MiddleMouseButton; modifiers |= RawInputModifiers.MiddleMouseButton;
return modifiers; return modifiers;
} }

2
src/iOS/Avalonia.iOS/Specific/KeyboardEventsHelper.cs

@ -76,7 +76,7 @@ namespace Avalonia.iOS.Specific
private void HandleKey(Key key, RawKeyEventType type) private void HandleKey(Key key, RawKeyEventType type)
{ {
var rawKeyEvent = new RawKeyEventArgs(KeyboardDevice.Instance, (uint)DateTime.Now.Ticks, type, key, InputModifiers.None); var rawKeyEvent = new RawKeyEventArgs(KeyboardDevice.Instance, (uint)DateTime.Now.Ticks, type, key, RawInputModifiers.None);
_view.Input(rawKeyEvent); _view.Input(rawKeyEvent);
} }

10
src/iOS/Avalonia.iOS/TopLevelImpl.cs

@ -92,7 +92,7 @@ namespace Avalonia.iOS
_inputRoot, _inputRoot,
RawPointerEventType.LeftButtonUp, RawPointerEventType.LeftButtonUp,
location, location,
InputModifiers.None)); RawInputModifiers.None));
} }
} }
@ -105,10 +105,10 @@ namespace Avalonia.iOS
var location = touch.LocationInView(this).ToAvalonia(); var location = touch.LocationInView(this).ToAvalonia();
_touchLastPoint = location; _touchLastPoint = location;
Input?.Invoke(new RawPointerEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot, Input?.Invoke(new RawPointerEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot,
RawPointerEventType.Move, location, InputModifiers.None)); RawPointerEventType.Move, location, RawInputModifiers.None));
Input?.Invoke(new RawPointerEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot, Input?.Invoke(new RawPointerEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot,
RawPointerEventType.LeftButtonDown, location, InputModifiers.None)); RawPointerEventType.LeftButtonDown, location, RawInputModifiers.None));
} }
} }
@ -120,14 +120,14 @@ namespace Avalonia.iOS
var location = touch.LocationInView(this).ToAvalonia(); var location = touch.LocationInView(this).ToAvalonia();
if (iOSPlatform.MouseDevice.Captured != null) if (iOSPlatform.MouseDevice.Captured != null)
Input?.Invoke(new RawPointerEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot, Input?.Invoke(new RawPointerEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, _inputRoot,
RawPointerEventType.Move, location, InputModifiers.LeftMouseButton)); RawPointerEventType.Move, location, RawInputModifiers.LeftMouseButton));
else else
{ {
//magic number based on test - correction of 0.02 is working perfect //magic number based on test - correction of 0.02 is working perfect
double correction = 0.02; double correction = 0.02;
Input?.Invoke(new RawMouseWheelEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp, Input?.Invoke(new RawMouseWheelEventArgs(iOSPlatform.MouseDevice, (uint)touch.Timestamp,
_inputRoot, location, (location - _touchLastPoint) * correction, InputModifiers.LeftMouseButton)); _inputRoot, location, (location - _touchLastPoint) * correction, RawInputModifiers.LeftMouseButton));
} }
_touchLastPoint = location; _touchLastPoint = location;
} }

6
tests/Avalonia.Controls.UnitTests/Platform/DefaultMenuInteractionHandlerTests.cs

@ -11,14 +11,14 @@ namespace Avalonia.Controls.UnitTests.Platform
public class DefaultMenuInteractionHandlerTests public class DefaultMenuInteractionHandlerTests
{ {
static PointerEventArgs CreateArgs(RoutedEvent ev, IInteractive source) 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, 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); default);
static PointerReleasedEventArgs CreateReleased(IInteractive source) => new PointerReleasedEventArgs(source, 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 public class TopLevel
{ {

30
tests/Avalonia.Controls.UnitTests/TextBoxTests.cs

@ -55,7 +55,7 @@ namespace Avalonia.Controls.UnitTests
Text = "1234" Text = "1234"
}; };
RaiseKeyEvent(target, Key.A, InputModifiers.Control); RaiseKeyEvent(target, Key.A, KeyModifiers.Control);
Assert.Equal(0, target.SelectionStart); Assert.Equal(0, target.SelectionStart);
Assert.Equal(4, target.SelectionEnd); Assert.Equal(4, target.SelectionEnd);
@ -72,7 +72,7 @@ namespace Avalonia.Controls.UnitTests
Template = CreateTemplate() Template = CreateTemplate()
}; };
RaiseKeyEvent(target, Key.A, InputModifiers.Control); RaiseKeyEvent(target, Key.A, KeyModifiers.Control);
Assert.Equal(0, target.SelectionStart); Assert.Equal(0, target.SelectionStart);
Assert.Equal(0, target.SelectionEnd); Assert.Equal(0, target.SelectionEnd);
@ -90,7 +90,7 @@ namespace Avalonia.Controls.UnitTests
Text = "1234" Text = "1234"
}; };
RaiseKeyEvent(target, Key.Z, InputModifiers.Control); RaiseKeyEvent(target, Key.Z, KeyModifiers.Control);
Assert.Equal("1234", target.Text); Assert.Equal("1234", target.Text);
} }
@ -136,29 +136,29 @@ namespace Avalonia.Controls.UnitTests
}; };
// (First| Second Third Fourth) // (First| Second Third Fourth)
RaiseKeyEvent(textBox, Key.Back, InputModifiers.Control); RaiseKeyEvent(textBox, Key.Back, KeyModifiers.Control);
Assert.Equal(" Second Third Fourth", textBox.Text); Assert.Equal(" Second Third Fourth", textBox.Text);
// ( Second |Third Fourth) // ( Second |Third Fourth)
textBox.CaretIndex = 8; textBox.CaretIndex = 8;
RaiseKeyEvent(textBox, Key.Back, InputModifiers.Control); RaiseKeyEvent(textBox, Key.Back, KeyModifiers.Control);
Assert.Equal(" Third Fourth", textBox.Text); Assert.Equal(" Third Fourth", textBox.Text);
// ( Thi|rd Fourth) // ( Thi|rd Fourth)
textBox.CaretIndex = 4; textBox.CaretIndex = 4;
RaiseKeyEvent(textBox, Key.Back, InputModifiers.Control); RaiseKeyEvent(textBox, Key.Back, KeyModifiers.Control);
Assert.Equal(" rd Fourth", textBox.Text); Assert.Equal(" rd Fourth", textBox.Text);
// ( rd F[ou]rth) // ( rd F[ou]rth)
textBox.SelectionStart = 5; textBox.SelectionStart = 5;
textBox.SelectionEnd = 7; textBox.SelectionEnd = 7;
RaiseKeyEvent(textBox, Key.Back, InputModifiers.Control); RaiseKeyEvent(textBox, Key.Back, KeyModifiers.Control);
Assert.Equal(" rd Frth", textBox.Text); Assert.Equal(" rd Frth", textBox.Text);
// ( |rd Frth) // ( |rd Frth)
textBox.CaretIndex = 1; textBox.CaretIndex = 1;
RaiseKeyEvent(textBox, Key.Back, InputModifiers.Control); RaiseKeyEvent(textBox, Key.Back, KeyModifiers.Control);
Assert.Equal("rd Frth", textBox.Text); Assert.Equal("rd Frth", textBox.Text);
} }
} }
@ -175,30 +175,30 @@ namespace Avalonia.Controls.UnitTests
}; };
// (First Second Third |Fourth) // (First Second Third |Fourth)
RaiseKeyEvent(textBox, Key.Delete, InputModifiers.Control); RaiseKeyEvent(textBox, Key.Delete, KeyModifiers.Control);
Assert.Equal("First Second Third ", textBox.Text); Assert.Equal("First Second Third ", textBox.Text);
// (First Second |Third ) // (First Second |Third )
textBox.CaretIndex = 13; textBox.CaretIndex = 13;
RaiseKeyEvent(textBox, Key.Delete, InputModifiers.Control); RaiseKeyEvent(textBox, Key.Delete, KeyModifiers.Control);
Assert.Equal("First Second ", textBox.Text); Assert.Equal("First Second ", textBox.Text);
// (First Sec|ond ) // (First Sec|ond )
textBox.CaretIndex = 9; textBox.CaretIndex = 9;
RaiseKeyEvent(textBox, Key.Delete, InputModifiers.Control); RaiseKeyEvent(textBox, Key.Delete, KeyModifiers.Control);
Assert.Equal("First Sec", textBox.Text); Assert.Equal("First Sec", textBox.Text);
// (Fi[rs]t Sec ) // (Fi[rs]t Sec )
textBox.SelectionStart = 2; textBox.SelectionStart = 2;
textBox.SelectionEnd = 4; textBox.SelectionEnd = 4;
RaiseKeyEvent(textBox, Key.Delete, InputModifiers.Control); RaiseKeyEvent(textBox, Key.Delete, KeyModifiers.Control);
Assert.Equal("Fit Sec", textBox.Text); Assert.Equal("Fit Sec", textBox.Text);
// (Fit Sec| ) // (Fit Sec| )
textBox.Text += " "; textBox.Text += " ";
textBox.CaretIndex = 7; textBox.CaretIndex = 7;
RaiseKeyEvent(textBox, Key.Delete, InputModifiers.Control); RaiseKeyEvent(textBox, Key.Delete, KeyModifiers.Control);
Assert.Equal("Fit Sec", textBox.Text); Assert.Equal("Fit Sec", textBox.Text);
} }
} }
@ -486,12 +486,12 @@ namespace Avalonia.Controls.UnitTests
}.RegisterInNameScope(scope)); }.RegisterInNameScope(scope));
} }
private void RaiseKeyEvent(TextBox textBox, Key key, InputModifiers inputModifiers) private void RaiseKeyEvent(TextBox textBox, Key key, KeyModifiers inputModifiers)
{ {
textBox.RaiseEvent(new KeyEventArgs textBox.RaiseEvent(new KeyEventArgs
{ {
RoutedEvent = InputElement.KeyDownEvent, RoutedEvent = InputElement.KeyDownEvent,
Modifiers = inputModifiers, KeyModifiers = inputModifiers,
Key = key Key = key
}); });
} }

2
tests/Avalonia.Controls.UnitTests/TopLevelTests.cs

@ -183,7 +183,7 @@ namespace Avalonia.Controls.UnitTests
new Mock<IKeyboardDevice>().Object, new Mock<IKeyboardDevice>().Object,
0, 0,
RawKeyEventType.KeyDown, RawKeyEventType.KeyDown,
Key.A, InputModifiers.None); Key.A, RawInputModifiers.None);
impl.Object.Input(input); impl.Object.Input(input);
inputManagerMock.Verify(x => x.ProcessInput(input)); inputManagerMock.Verify(x => x.ProcessInput(input));

6
tests/Avalonia.Controls.UnitTests/TreeViewTests.cs

@ -619,7 +619,7 @@ namespace Avalonia.Controls.UnitTests
{ {
RoutedEvent = InputElement.KeyDownEvent, RoutedEvent = InputElement.KeyDownEvent,
Key = selectAllGesture.Key, Key = selectAllGesture.Key,
Modifiers = selectAllGesture.Modifiers KeyModifiers = selectAllGesture.KeyModifiers
}; };
target.RaiseEvent(keyEvent); target.RaiseEvent(keyEvent);
@ -665,7 +665,7 @@ namespace Avalonia.Controls.UnitTests
{ {
RoutedEvent = InputElement.KeyDownEvent, RoutedEvent = InputElement.KeyDownEvent,
Key = selectAllGesture.Key, Key = selectAllGesture.Key,
Modifiers = selectAllGesture.Modifiers KeyModifiers = selectAllGesture.KeyModifiers
}; };
target.RaiseEvent(keyEvent); target.RaiseEvent(keyEvent);
@ -711,7 +711,7 @@ namespace Avalonia.Controls.UnitTests
{ {
RoutedEvent = InputElement.KeyDownEvent, RoutedEvent = InputElement.KeyDownEvent,
Key = selectAllGesture.Key, Key = selectAllGesture.Key,
Modifiers = selectAllGesture.Modifiers KeyModifiers = selectAllGesture.KeyModifiers
}; };
target.RaiseEvent(keyEvent); target.RaiseEvent(keyEvent);

2
tests/Avalonia.Input.UnitTests/MouseDeviceTests.cs

@ -231,7 +231,7 @@ namespace Avalonia.Input.UnitTests
root, root,
RawPointerEventType.Move, RawPointerEventType.Move,
p, p,
InputModifiers.None)); RawInputModifiers.None));
} }
private void SetHit(Mock<IRenderer> renderer, IControl hit) private void SetHit(Mock<IRenderer> renderer, IControl hit)

23
tests/Avalonia.UnitTests/MouseTestHelper.cs

@ -32,7 +32,8 @@ namespace Avalonia.UnitTests
private MouseButton _pressedButton; 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, public void Down(IInteractive target, MouseButton mouseButton = MouseButton.Left, Point position = default,
InputModifiers modifiers = default, int clickCount = 1) InputModifiers modifiers = default, int clickCount = 1)
@ -44,7 +45,11 @@ namespace Avalonia.UnitTests
Point position = default, InputModifiers modifiers = default, int clickCount = 1) Point position = default, InputModifiers modifiers = default, int clickCount = 1)
{ {
_pressedButtons |= Convert(mouseButton); _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) if (ButtonCount(props) > 1)
Move(target, source, position); Move(target, source, position);
else else
@ -60,7 +65,7 @@ namespace Avalonia.UnitTests
public void Move(IInteractive target, IInteractive source, in Point position, InputModifiers modifiers = default) public void Move(IInteractive target, IInteractive source, in Point position, InputModifiers modifiers = default)
{ {
target.RaiseEvent(new PointerEventArgs(InputElement.PointerMovedEvent, source, _pointer, (IVisual)target, position, 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, public void Up(IInteractive target, MouseButton mouseButton = MouseButton.Left, Point position = default,
@ -72,13 +77,17 @@ namespace Avalonia.UnitTests
{ {
var conv = Convert(mouseButton); var conv = Convert(mouseButton);
_pressedButtons = (_pressedButtons | conv) ^ conv; _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) if (ButtonCount(props) == 0)
{ {
_pointer.Capture(null); _pointer.Capture(null);
target.RaiseEvent(new PointerReleasedEventArgs(source, _pointer, (IVisual)target, position, target.RaiseEvent(new PointerReleasedEventArgs(source, _pointer, (IVisual)target, position,
Timestamp(), props, Timestamp(), props,
GetModifiers(modifiers), _pressedButton)); GetModifiers(modifiers)));
} }
else else
Move(target, source, position); Move(target, source, position);
@ -97,13 +106,13 @@ namespace Avalonia.UnitTests
public void Enter(IInteractive target) public void Enter(IInteractive target)
{ {
target.RaiseEvent(new PointerEventArgs(InputElement.PointerEnterEvent, target, _pointer, (IVisual)target, default, 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) public void Leave(IInteractive target)
{ {
target.RaiseEvent(new PointerEventArgs(InputElement.PointerLeaveEvent, target, _pointer, (IVisual)target, default, 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));
} }
} }

Loading…
Cancel
Save