private void OnDeviceEvent()

in src/Avalonia.X11/XI2Manager.cs [271:422]


        private void OnDeviceEvent(IXI2Client client, ParsedDeviceEvent ev)
        {
            if (ev.Type == XiEventType.XI_TouchBegin 
                || ev.Type == XiEventType.XI_TouchUpdate 
                || ev.Type == XiEventType.XI_TouchEnd)
            {
                var type = ev.Type == XiEventType.XI_TouchBegin ?
                    RawPointerEventType.TouchBegin :
                    (ev.Type == XiEventType.XI_TouchUpdate ?
                        RawPointerEventType.TouchUpdate :
                        RawPointerEventType.TouchEnd);

                var rawPointerPoint = new RawPointerPoint()
                {
                    Position = ev.Position
                };

                if (_pointerDevice.PressureXIValuatorClassInfo is {} valuatorClassInfo)
                {
                    if (ev.Valuators.TryGetValue(valuatorClassInfo.Number, out var pressureValue))
                    {
                        // In our API we use range from 0.0 to 1.0.
                        var pressure = (pressureValue - valuatorClassInfo.Min) / (valuatorClassInfo.Max - valuatorClassInfo.Min);
                        rawPointerPoint.Pressure = (float)pressure;
                    }
                }

                if(_pointerDevice.TouchMajorXIValuatorClassInfo is {} touchMajorXIValuatorClassInfo)
                {
                    double? touchMajor = null;
                    double? touchMinor = null;
                    PixelRect screenBounds = default;
                    if (ev.Valuators.TryGetValue(touchMajorXIValuatorClassInfo.Number, out var touchMajorValue))
                    {
                        var pixelPoint = new PixelPoint((int)ev.RootPosition.X, (int)ev.RootPosition.Y);
                        var screen = _platform.Screens.ScreenFromPoint(pixelPoint);
                        if (screen?.Bounds is { } screenBoundsFromPoint)
                        {
                            screenBounds = screenBoundsFromPoint;

                            // As https://www.kernel.org/doc/html/latest/input/multi-touch-protocol.html says, using `screenBounds.Width` is not accurate enough.
                            touchMajor = (touchMajorValue - touchMajorXIValuatorClassInfo.Min) /
                                (touchMajorXIValuatorClassInfo.Max - touchMajorXIValuatorClassInfo.Min) * screenBounds.Width;
                        }
                    }

                    if (touchMajor != null)
                    {
                        if(_pointerDevice.TouchMinorXIValuatorClassInfo is {} touchMinorXIValuatorClassInfo)
                        {
                            if (ev.Valuators.TryGetValue(touchMinorXIValuatorClassInfo.Number, out var touchMinorValue))
                            {
                                touchMinor = (touchMinorValue - touchMinorXIValuatorClassInfo.Min) /
                                             (touchMinorXIValuatorClassInfo.Max - touchMinorXIValuatorClassInfo.Min) * screenBounds.Height;
                            }
                        }

                        if (touchMinor == null)
                        {
                            touchMinor = touchMajor;
                        }

                        var center = ev.Position;
                        var leftX = center.X - touchMajor.Value / 2;
                        var topY = center.Y - touchMinor.Value / 2;

                        rawPointerPoint.ContactRect = new Rect
                        (
                            leftX,
                            topY,
                            touchMajor.Value,
                            touchMinor.Value
                        );
                    }
                }

                client.ScheduleXI2Input(new RawTouchEventArgs(client.TouchDevice,
                    ev.Timestamp, client.InputRoot, type, rawPointerPoint, ev.Modifiers, ev.Detail));
                return;
            }

            if (!client.IsEnabled || (_multitouch && ev.Emulated))
                return;
            
            if (ev.Type == XiEventType.XI_Motion)
            {
                Vector scrollDelta = default;
                foreach (var v in ev.Valuators)
                {
                    foreach (var scroller in _pointerDevice.Scrollers)
                    {
                        if (scroller.Number == v.Key)
                        {
                            var old = _pointerDevice.Valuators[scroller.Number].Value;
                            // Value was zero after reset, ignore the event and use it as a reference next time
                            if (old == 0)
                                continue;
                            var diff = (old - v.Value) / scroller.Increment;
                            if (scroller.ScrollType == XiScrollType.Horizontal)
                                scrollDelta = scrollDelta.WithX(scrollDelta.X + diff);
                            else
                                scrollDelta = scrollDelta.WithY(scrollDelta.Y + diff);

                        }
                    }


                }

                if (scrollDelta != default)
                    client.ScheduleXI2Input(new RawMouseWheelEventArgs(client.MouseDevice, ev.Timestamp,
                        client.InputRoot, ev.Position, scrollDelta, ev.Modifiers));
                if (_pointerDevice.HasMotion(ev))
                    client.ScheduleXI2Input(new RawPointerEventArgs(client.MouseDevice, ev.Timestamp, client.InputRoot,
                        RawPointerEventType.Move, ev.Position, ev.Modifiers));
            }

            if (ev.Type == XiEventType.XI_ButtonPress && ev.Button >= 4 && ev.Button <= 7 && !ev.Emulated)
            {
                var scrollDelta = ev.Button switch
                {
                    4 => new Vector(0, 1),
                    5 => new Vector(0, -1),
                    6 => new Vector(1, 0),
                    7 => new Vector(-1, 0),
                    _ => (Vector?)null
                };

                if (scrollDelta.HasValue)
                    client.ScheduleXI2Input(new RawMouseWheelEventArgs(client.MouseDevice, ev.Timestamp,
                        client.InputRoot, ev.Position, scrollDelta.Value, ev.Modifiers));
            }

            if (ev.Type == XiEventType.XI_ButtonPress || ev.Type == XiEventType.XI_ButtonRelease)
            {
                var down = ev.Type == XiEventType.XI_ButtonPress;
                var type = ev.Button switch
                {
                    1 => down ? RawPointerEventType.LeftButtonDown : RawPointerEventType.LeftButtonUp,
                    2 => down ? RawPointerEventType.MiddleButtonDown : RawPointerEventType.MiddleButtonUp,
                    3 => down ? RawPointerEventType.RightButtonDown : RawPointerEventType.RightButtonUp,
                    8 => down ? RawPointerEventType.XButton1Down : RawPointerEventType.XButton1Up,
                    9 => down ? RawPointerEventType.XButton2Down : RawPointerEventType.XButton2Up,
                    _ => (RawPointerEventType?)null
                };
                if (type.HasValue)
                    client.ScheduleXI2Input(new RawPointerEventArgs(client.MouseDevice, ev.Timestamp, client.InputRoot,
                        type.Value, ev.Position, ev.Modifiers));
            }
            
            _pointerDevice.UpdateValuators(ev.Valuators);
        }