diff --git a/src/iOS/Avalonia.iOS/InputHandler.cs b/src/iOS/Avalonia.iOS/InputHandler.cs index 7057f5a84d..ff074cfe12 100644 --- a/src/iOS/Avalonia.iOS/InputHandler.cs +++ b/src/iOS/Avalonia.iOS/InputHandler.cs @@ -15,7 +15,9 @@ internal sealed class InputHandler private readonly AvaloniaView _view; private readonly ITopLevelImpl _tl; - public TouchDevice _device = new(); + public TouchDevice _touchDevice = new(); + public MouseDevice _mouseDevice = new(); + public PenDevice _penDevice = new(); private static long _nextTouchPointId = 1; private readonly Dictionary _knownTouches = new Dictionary(); @@ -32,23 +34,54 @@ internal sealed class InputHandler { foreach (UITouch t in touches) { - var pt = t.LocationInView(_view).ToAvalonia(); + if (t.Type == UITouchType.Indirect) + { + // Ignore Indirect input, like remote controller trackpad. + // For Avalonia we handle it independently with gestures. + continue; + } + if (!_knownTouches.TryGetValue(t, out var id)) _knownTouches[t] = id = _nextTouchPointId++; - var ev = new RawTouchEventArgs(_device, Ts(evt), Root, - t.Phase switch + var point = new RawPointerPoint + { + Position = t.LocationInView(_view).ToAvalonia(), + // in iOS "1.0 represents the force of an average touch", when Avalonia expects 0.5 for "average" + Pressure = (float)t.Force / 2 + }; + + IInputDevice device = t.Type switch + { + UITouchType.Stylus => _penDevice, + UITouchType.IndirectPointer => _mouseDevice, + _ => _touchDevice + }; + + var ev = new RawTouchEventArgs(device, Ts(evt), Root, + (device, t.Phase) switch { - UITouchPhase.Began => RawPointerEventType.TouchBegin, - UITouchPhase.Ended => RawPointerEventType.TouchEnd, - UITouchPhase.Cancelled => RawPointerEventType.TouchCancel, - _ => RawPointerEventType.TouchUpdate - }, pt, RawInputModifiers.None, id); + (TouchDevice, UITouchPhase.Began) => RawPointerEventType.TouchBegin, + (TouchDevice, UITouchPhase.Ended) => RawPointerEventType.TouchEnd, + (TouchDevice, UITouchPhase.Cancelled) => RawPointerEventType.TouchCancel, + (TouchDevice, _) => RawPointerEventType.TouchUpdate, + + (_, UITouchPhase.Began) => IsRightClick() ? RawPointerEventType.RightButtonDown : RawPointerEventType.LeftButtonDown, + (_, UITouchPhase.Ended or UITouchPhase.Cancelled) => IsRightClick() ? RawPointerEventType.RightButtonUp : RawPointerEventType.RightButtonDown, + (_, _) => RawPointerEventType.Move, + }, point, ConvertModifierKeys(evt?.ModifierFlags), id); _tl.Input?.Invoke(ev); if (t.Phase == UITouchPhase.Cancelled || t.Phase == UITouchPhase.Ended) _knownTouches.Remove(t); + + bool IsRightClick() +#if !TVOS + => evt?.ButtonMask.HasFlag(UIEventButtonMask.Secondary) ?? false; +#else + => false; +#endif } } @@ -65,15 +98,7 @@ internal sealed class InputHandler if (_supportsKey && p.Key is { } uiKey && s_keys.TryGetValue(uiKey.KeyCode, out physicalKey)) { - var uiModifier = uiKey.ModifierFlags; - if (uiModifier.HasFlag(UIKeyModifierFlags.Shift)) - modifier |= RawInputModifiers.Shift; - if (uiModifier.HasFlag(UIKeyModifierFlags.Alternate)) - modifier |= RawInputModifiers.Alt; - if (uiModifier.HasFlag(UIKeyModifierFlags.Control)) - modifier |= RawInputModifiers.Control; - if (uiModifier.HasFlag(UIKeyModifierFlags.Command)) - modifier |= RawInputModifiers.Meta; + modifier = ConvertModifierKeys(uiKey.ModifierFlags); keyDeviceType = KeyDeviceType.Keyboard; // very likely @@ -171,6 +196,24 @@ internal sealed class InputHandler } } + private static RawInputModifiers ConvertModifierKeys(UIKeyModifierFlags? uiModifier) + { + RawInputModifiers modifier = default; + if (uiModifier is { } flags) + { + if (flags.HasFlag(UIKeyModifierFlags.Shift)) + modifier |= RawInputModifiers.Shift; + if (flags.HasFlag(UIKeyModifierFlags.Alternate)) + modifier |= RawInputModifiers.Alt; + if (flags.HasFlag(UIKeyModifierFlags.Control)) + modifier |= RawInputModifiers.Control; + if (flags.HasFlag(UIKeyModifierFlags.Command)) + modifier |= RawInputModifiers.Meta; + } + + return modifier; + } + private static Dictionary s_keys = new() { //[UIKeyboardHidUsage.KeyboardErrorRollOver] = PhysicalKey.None,