diff --git a/src/Avalonia.Controls/Platform/InProcessDragSource.cs b/src/Avalonia.Controls/Platform/InProcessDragSource.cs index 6eb056bb32..9d644aaa00 100644 --- a/src/Avalonia.Controls/Platform/InProcessDragSource.cs +++ b/src/Avalonia.Controls/Platform/InProcessDragSource.cs @@ -21,7 +21,7 @@ namespace Avalonia.Platform private DragDropEffects _allowedEffects; private IDataObject _draggedData; - private IInputElement _lastRoot; + private IInputRoot _lastRoot; private Point _lastPosition; private StandardCursorType _lastCursorType; private object _originalCursor; @@ -56,7 +56,7 @@ namespace Avalonia.Platform return DragDropEffects.None; } - private DragDropEffects RaiseEventAndUpdateCursor(RawDragEventType type, IInputElement root, Point pt, RawInputModifiers modifiers) + private DragDropEffects RaiseEventAndUpdateCursor(RawDragEventType type, IInputRoot root, Point pt, RawInputModifiers modifiers) { _lastPosition = pt; @@ -91,7 +91,7 @@ namespace Avalonia.Platform return StandardCursorType.No; } - private void UpdateCursor(IInputElement root, DragDropEffects effect) + private void UpdateCursor(IInputRoot root, DragDropEffects effect) { if (_lastRoot != root) { diff --git a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs index be24f22e20..9d70fbcf31 100644 --- a/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs +++ b/src/Avalonia.Controls/Remote/Server/RemoteServerTopLevelImpl.cs @@ -227,6 +227,7 @@ namespace Avalonia.Controls.Remote.Server Input?.Invoke(new RawKeyEventArgs( KeyboardDevice, 0, + InputRoot, key.IsDown ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp, (Key)key.Key, GetAvaloniaRawInputModifiers(key.Modifiers))); @@ -241,6 +242,7 @@ namespace Avalonia.Controls.Remote.Server Input?.Invoke(new RawTextInputEventArgs( KeyboardDevice, 0, + InputRoot, text.Text)); }, DispatcherPriority.Input); } diff --git a/src/Avalonia.Input/DragDropDevice.cs b/src/Avalonia.Input/DragDropDevice.cs index 0b9f09b224..25d3b6887f 100644 --- a/src/Avalonia.Input/DragDropDevice.cs +++ b/src/Avalonia.Input/DragDropDevice.cs @@ -11,7 +11,7 @@ namespace Avalonia.Input private Interactive _lastTarget = null; - private Interactive GetTarget(IInputElement root, Point local) + private Interactive GetTarget(IInputRoot root, Point local) { var target = root.InputHitTest(local)?.GetSelfAndVisualAncestors()?.OfType()?.FirstOrDefault(); if (target != null && DragDrop.GetAllowDrop(target)) @@ -19,7 +19,7 @@ namespace Avalonia.Input return null; } - private DragDropEffects RaiseDragEvent(Interactive target, IInputElement inputRoot, Point point, RoutedEvent routedEvent, DragDropEffects operation, IDataObject data, InputModifiers modifiers) + private DragDropEffects RaiseDragEvent(Interactive target, IInputRoot inputRoot, Point point, RoutedEvent routedEvent, DragDropEffects operation, IDataObject data, InputModifiers modifiers) { if (target == null) return DragDropEffects.None; @@ -38,13 +38,13 @@ namespace Avalonia.Input return args.DragEffects; } - private DragDropEffects DragEnter(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects, InputModifiers modifiers) + private DragDropEffects DragEnter(IInputRoot inputRoot, Point point, IDataObject data, DragDropEffects effects, InputModifiers modifiers) { _lastTarget = GetTarget(inputRoot, point); return RaiseDragEvent(_lastTarget, inputRoot, point, DragDrop.DragEnterEvent, effects, data, modifiers); } - private DragDropEffects DragOver(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects, InputModifiers modifiers) + private DragDropEffects DragOver(IInputRoot inputRoot, Point point, IDataObject data, DragDropEffects effects, InputModifiers modifiers) { var target = GetTarget(inputRoot, point); @@ -77,7 +77,7 @@ namespace Avalonia.Input } } - private DragDropEffects Drop(IInputElement inputRoot, Point point, IDataObject data, DragDropEffects effects, InputModifiers modifiers) + private DragDropEffects Drop(IInputRoot inputRoot, Point point, IDataObject data, DragDropEffects effects, InputModifiers modifiers) { try { @@ -100,16 +100,16 @@ namespace Avalonia.Input switch (e.Type) { case RawDragEventType.DragEnter: - e.Effects = DragEnter(e.InputRoot, e.Location, e.Data, e.Effects, e.Modifiers); + e.Effects = DragEnter(e.Root, e.Location, e.Data, e.Effects, e.Modifiers); break; case RawDragEventType.DragOver: - e.Effects = DragOver(e.InputRoot, e.Location, e.Data, e.Effects, e.Modifiers); + e.Effects = DragOver(e.Root, e.Location, e.Data, e.Effects, e.Modifiers); break; case RawDragEventType.DragLeave: - DragLeave(e.InputRoot); + DragLeave(e.Root); break; case RawDragEventType.Drop: - e.Effects = Drop(e.InputRoot, e.Location, e.Data, e.Effects, e.Modifiers); + e.Effects = Drop(e.Root, e.Location, e.Data, e.Effects, e.Modifiers); break; } } diff --git a/src/Avalonia.Input/KeyboardDevice.cs b/src/Avalonia.Input/KeyboardDevice.cs index a02c580ad2..9db8525591 100644 --- a/src/Avalonia.Input/KeyboardDevice.cs +++ b/src/Avalonia.Input/KeyboardDevice.cs @@ -70,66 +70,60 @@ namespace Avalonia.Input { if(e.Handled) return; - IInputElement element = FocusedElement; - if (element != null) - { - var keyInput = e as RawKeyEventArgs; + var element = FocusedElement ?? e.Root; - if (keyInput != null) + if (e is RawKeyEventArgs keyInput) + { + switch (keyInput.Type) { - switch (keyInput.Type) - { - case RawKeyEventType.KeyDown: - case RawKeyEventType.KeyUp: - var routedEvent = keyInput.Type == RawKeyEventType.KeyDown - ? InputElement.KeyDownEvent - : InputElement.KeyUpEvent; - - KeyEventArgs ev = new KeyEventArgs - { - RoutedEvent = routedEvent, - Device = this, - Key = keyInput.Key, - KeyModifiers = KeyModifiersUtils.ConvertToKey(keyInput.Modifiers), - Source = element, - }; - - IVisual currentHandler = element; - while (currentHandler != null && !ev.Handled && keyInput.Type == RawKeyEventType.KeyDown) - { - var bindings = (currentHandler as IInputElement)?.KeyBindings; - if(bindings!=null) - foreach (var binding in bindings) - { - if(ev.Handled) - break; - binding.TryHandle(ev); - } - currentHandler = currentHandler.VisualParent; - } - - element.RaiseEvent(ev); - e.Handled = ev.Handled; - break; - } + case RawKeyEventType.KeyDown: + case RawKeyEventType.KeyUp: + var routedEvent = keyInput.Type == RawKeyEventType.KeyDown + ? InputElement.KeyDownEvent + : InputElement.KeyUpEvent; + + KeyEventArgs ev = new KeyEventArgs + { + RoutedEvent = routedEvent, + Device = this, + Key = keyInput.Key, + KeyModifiers = KeyModifiersUtils.ConvertToKey(keyInput.Modifiers), + Source = element, + }; + + IVisual currentHandler = element; + while (currentHandler != null && !ev.Handled && keyInput.Type == RawKeyEventType.KeyDown) + { + var bindings = (currentHandler as IInputElement)?.KeyBindings; + if (bindings != null) + foreach (var binding in bindings) + { + if (ev.Handled) + break; + binding.TryHandle(ev); + } + currentHandler = currentHandler.VisualParent; + } + + element.RaiseEvent(ev); + e.Handled = ev.Handled; + break; } + } - var text = e as RawTextInputEventArgs; - - if (text != null) + if (e is RawTextInputEventArgs text) + { + var ev = new TextInputEventArgs() { - var ev = new TextInputEventArgs() - { - Device = this, - Text = text.Text, - Source = element, - RoutedEvent = InputElement.TextInputEvent - }; - - element.RaiseEvent(ev); - e.Handled = ev.Handled; - } + Device = this, + Text = text.Text, + Source = element, + RoutedEvent = InputElement.TextInputEvent + }; + + element.RaiseEvent(ev); + e.Handled = ev.Handled; } } } diff --git a/src/Avalonia.Input/Raw/RawDragEvent.cs b/src/Avalonia.Input/Raw/RawDragEvent.cs index 1480f92f03..5722e17593 100644 --- a/src/Avalonia.Input/Raw/RawDragEvent.cs +++ b/src/Avalonia.Input/Raw/RawDragEvent.cs @@ -2,7 +2,6 @@ { public class RawDragEvent : RawInputEventArgs { - public IInputElement InputRoot { get; } public Point Location { get; set; } public IDataObject Data { get; } public DragDropEffects Effects { get; set; } @@ -10,11 +9,10 @@ public InputModifiers Modifiers { get; } public RawDragEvent(IDragDropDevice inputDevice, RawDragEventType type, - IInputElement inputRoot, Point location, IDataObject data, DragDropEffects effects, RawInputModifiers modifiers) - :base(inputDevice, 0) + IInputRoot root, Point location, IDataObject data, DragDropEffects effects, RawInputModifiers modifiers) + :base(inputDevice, 0, root) { Type = type; - InputRoot = inputRoot; Location = location; Data = data; Effects = effects; diff --git a/src/Avalonia.Input/Raw/RawInputEventArgs.cs b/src/Avalonia.Input/Raw/RawInputEventArgs.cs index 78c1b58624..6a488c4cc7 100644 --- a/src/Avalonia.Input/Raw/RawInputEventArgs.cs +++ b/src/Avalonia.Input/Raw/RawInputEventArgs.cs @@ -21,12 +21,14 @@ namespace Avalonia.Input.Raw /// /// The associated device. /// The event timestamp. - public RawInputEventArgs(IInputDevice device, ulong timestamp) + /// The root from which the event originates. + public RawInputEventArgs(IInputDevice device, ulong timestamp, IInputRoot root) { Contract.Requires(device != null); Device = device; Timestamp = timestamp; + Root = root; } /// @@ -34,6 +36,11 @@ namespace Avalonia.Input.Raw /// public IInputDevice Device { get; } + /// + /// Gets the root from which the event originates. + /// + public IInputRoot Root { get; } + /// /// Gets or sets a value indicating whether the event was handled. /// diff --git a/src/Avalonia.Input/Raw/RawKeyEventArgs.cs b/src/Avalonia.Input/Raw/RawKeyEventArgs.cs index cd8b2eacf7..c720cf11f8 100644 --- a/src/Avalonia.Input/Raw/RawKeyEventArgs.cs +++ b/src/Avalonia.Input/Raw/RawKeyEventArgs.cs @@ -14,9 +14,10 @@ namespace Avalonia.Input.Raw public RawKeyEventArgs( IKeyboardDevice device, ulong timestamp, + IInputRoot root, RawKeyEventType type, Key key, RawInputModifiers modifiers) - : base(device, timestamp) + : base(device, timestamp, root) { Key = key; Type = type; diff --git a/src/Avalonia.Input/Raw/RawPointerEventArgs.cs b/src/Avalonia.Input/Raw/RawPointerEventArgs.cs index 88f6daf11f..56854c7d29 100644 --- a/src/Avalonia.Input/Raw/RawPointerEventArgs.cs +++ b/src/Avalonia.Input/Raw/RawPointerEventArgs.cs @@ -44,22 +44,16 @@ namespace Avalonia.Input.Raw RawPointerEventType type, Point position, RawInputModifiers inputModifiers) - : base(device, timestamp) + : base(device, timestamp, root) { Contract.Requires(device != null); Contract.Requires(root != null); - Root = root; Position = position; Type = type; InputModifiers = inputModifiers; } - /// - /// Gets the root from which the event originates. - /// - public IInputRoot Root { get; } - /// /// Gets the mouse position, in client DIPs. /// diff --git a/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs b/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs index 0d1e5d2422..010342da15 100644 --- a/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs +++ b/src/Avalonia.Input/Raw/RawTextInputEventArgs.cs @@ -5,11 +5,16 @@ namespace Avalonia.Input.Raw { public class RawTextInputEventArgs : RawInputEventArgs { - public string Text { get; set; } - - public RawTextInputEventArgs(IKeyboardDevice device, ulong timestamp, string text) : base(device, timestamp) + public RawTextInputEventArgs( + IKeyboardDevice device, + ulong timestamp, + IInputRoot root, + string text) + : base(device, timestamp, root) { Text = text; } + + public string Text { get; set; } } } diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index 209e1bc7ea..fe7458d583 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -204,7 +204,7 @@ namespace Avalonia.Native { Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1); - var args = new RawTextInputEventArgs(_keyboard, timeStamp, text); + var args = new RawTextInputEventArgs(_keyboard, timeStamp, _inputRoot, text); Input?.Invoke(args); @@ -215,7 +215,7 @@ namespace Avalonia.Native { Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1); - var args = new RawKeyEventArgs(_keyboard, timeStamp, (RawKeyEventType)type, (Key)key, (RawInputModifiers)modifiers); + var args = new RawKeyEventArgs(_keyboard, timeStamp, _inputRoot, (RawKeyEventType)type, (Key)key, (RawInputModifiers)modifiers); Input?.Invoke(args); diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs index 2630f9cf96..17471fad10 100644 --- a/src/Avalonia.X11/X11Window.cs +++ b/src/Avalonia.X11/X11Window.cs @@ -455,7 +455,7 @@ namespace Avalonia.X11 key = (X11Key)XKeycodeToKeysym(_x11.Display, ev.KeyEvent.keycode, index ? 0 : 1).ToInt32(); - ScheduleInput(new RawKeyEventArgs(_keyboard, (ulong)ev.KeyEvent.time.ToInt64(), + ScheduleInput(new RawKeyEventArgs(_keyboard, (ulong)ev.KeyEvent.time.ToInt64(), _inputRoot, ev.type == XEventName.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp, X11KeyTransform.ConvertKey(key), TranslateModifiers(ev.KeyEvent.state)), ref ev); @@ -470,7 +470,7 @@ namespace Avalonia.X11 if (text[0] < ' ' || text[0] == 0x7f) //Control codes or DEL return; } - ScheduleInput(new RawTextInputEventArgs(_keyboard, (ulong)ev.KeyEvent.time.ToInt64(), text), + ScheduleInput(new RawTextInputEventArgs(_keyboard, (ulong)ev.KeyEvent.time.ToInt64(), _inputRoot, text), ref ev); } } diff --git a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs index 71c398481b..2887468046 100644 --- a/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs +++ b/src/Windows/Avalonia.Win32.Interop/Wpf/WpfTopLevelImpl.cs @@ -212,17 +212,17 @@ namespace Avalonia.Win32.Interop.Wpf protected override void OnMouseLeave(MouseEventArgs e) => MouseEvent(RawPointerEventType.LeaveWindow, 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, _inputRoot, RawKeyEventType.KeyDown, (Key) e.Key, GetModifiers(null))); 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, _inputRoot, RawKeyEventType.KeyUp, (Key)e.Key, GetModifiers(null))); 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, _inputRoot, e.Text)); void ITopLevelImpl.SetCursor(IPlatformHandle cursor) { diff --git a/src/Windows/Avalonia.Win32/OleDropTarget.cs b/src/Windows/Avalonia.Win32/OleDropTarget.cs index 8ac0f25598..b17e0d6c09 100644 --- a/src/Windows/Avalonia.Win32/OleDropTarget.cs +++ b/src/Windows/Avalonia.Win32/OleDropTarget.cs @@ -8,13 +8,13 @@ namespace Avalonia.Win32 { class OleDropTarget : IDropTarget { - private readonly IInputElement _target; + private readonly IInputRoot _target; private readonly ITopLevelImpl _tl; private readonly IDragDropDevice _dragDevice; private IDataObject _currentDrag = null; - public OleDropTarget(ITopLevelImpl tl, IInputElement target) + public OleDropTarget(ITopLevelImpl tl, IInputRoot target) { _dragDevice = AvaloniaLocator.Current.GetService(); _tl = tl; diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs index 4f4c9852e8..04a9303d53 100644 --- a/src/Windows/Avalonia.Win32/WindowImpl.cs +++ b/src/Windows/Avalonia.Win32/WindowImpl.cs @@ -508,6 +508,7 @@ namespace Avalonia.Win32 e = new RawKeyEventArgs( WindowsKeyboardDevice.Instance, timestamp, + _owner, RawKeyEventType.KeyDown, KeyInterop.KeyFromVirtualKey(ToInt32(wParam)), WindowsKeyboardDevice.Instance.Modifiers); break; @@ -521,6 +522,7 @@ namespace Avalonia.Win32 e = new RawKeyEventArgs( WindowsKeyboardDevice.Instance, timestamp, + _owner, RawKeyEventType.KeyUp, KeyInterop.KeyFromVirtualKey(ToInt32(wParam)), WindowsKeyboardDevice.Instance.Modifiers); break; @@ -528,7 +530,7 @@ namespace Avalonia.Win32 // Ignore control chars if (ToInt32(wParam) >= 32) { - e = new RawTextInputEventArgs(WindowsKeyboardDevice.Instance, timestamp, + e = new RawTextInputEventArgs(WindowsKeyboardDevice.Instance, timestamp, _owner, new string((char)ToInt32(wParam), 1)); } diff --git a/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs b/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs index 645f87163a..72c81659c3 100644 --- a/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TopLevelTests.cs @@ -182,6 +182,7 @@ namespace Avalonia.Controls.UnitTests var input = new RawKeyEventArgs( new Mock().Object, 0, + target, RawKeyEventType.KeyDown, Key.A, RawInputModifiers.None); impl.Object.Input(input);