Просмотр исходного кода

feat(LibInputBackend) Handle events only from specific input handler devices (#15001)

* refactor(LibInputBackend): Move HandleTouch in `LibInputBackend.Tocuch.cs`

* feat(LibInputBackend) Handle events only from specific input handler devices

- Added LibInputBackendOptions
- Added LibInputBackend ctor overload that accepts LibInputBackendOptions
- Moved input thread initialization from ctor to the Initialize method

* fix: nits

* fix: Address review

* fix: Address review
workgroupengineering 1 год назад
Родитель
Сommit
40c630b7b5

+ 51 - 0
src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.Touch.cs

@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods;
+
+namespace Avalonia.LinuxFramebuffer.Input.LibInput;
+
+public partial class LibInputBackend
+{
+    private readonly Dictionary<int, Point> _pointers = new();
+    private readonly TouchDevice _touch = new();
+
+    private void HandleTouch(IntPtr ev, LibInputEventType type)
+    {
+        var tev = libinput_event_get_touch_event(ev);
+        if (tev == IntPtr.Zero)
+            return;
+        if (type < LibInputEventType.LIBINPUT_EVENT_TOUCH_FRAME)
+        {
+            var info = _screen.ScaledSize;
+            var slot = libinput_event_touch_get_slot(tev);
+            Point pt;
+
+            if (type == LibInputEventType.LIBINPUT_EVENT_TOUCH_DOWN
+                || type == LibInputEventType.LIBINPUT_EVENT_TOUCH_MOTION)
+            {
+                var x = libinput_event_touch_get_x_transformed(tev, (int)info.Width);
+                var y = libinput_event_touch_get_y_transformed(tev, (int)info.Height);
+                pt = new Point(x, y);
+                _pointers[slot] = pt;
+            }
+            else
+            {
+                _pointers.TryGetValue(slot, out pt);
+                _pointers.Remove(slot);
+            }
+
+            var ts = libinput_event_touch_get_time_usec(tev) / 1000;
+            if (_inputRoot == null)
+                return;
+            ScheduleInput(new RawTouchEventArgs(_touch, ts,
+                _inputRoot,
+                type == LibInputEventType.LIBINPUT_EVENT_TOUCH_DOWN ? RawPointerEventType.TouchBegin
+                : type == LibInputEventType.LIBINPUT_EVENT_TOUCH_UP ? RawPointerEventType.TouchEnd
+                : type == LibInputEventType.LIBINPUT_EVENT_TOUCH_MOTION ? RawPointerEventType.TouchUpdate
+                : RawPointerEventType.TouchCancel,
+                pt, RawInputModifiers.None, slot));
+        }
+    }
+}

+ 28 - 54
src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs

@@ -1,5 +1,5 @@
+#nullable enable
 using System;
-using System.Collections.Generic;
 using System.IO;
 using System.Threading;
 using Avalonia.Input;
@@ -9,27 +9,27 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
 {
     public partial class LibInputBackend : IInputBackend
     {
-        private IScreenInfoProvider _screen;
-        private IInputRoot _inputRoot;
-        private TouchDevice _touch = new TouchDevice();
-        private const string LibInput = nameof(Avalonia.LinuxFramebuffer) + "/" + nameof(Avalonia.LinuxFramebuffer.Input) + "/" + nameof(LibInput);
-        private Action<RawInputEventArgs> _onInput;
-        private Dictionary<int, Point> _pointers = new Dictionary<int, Point>();
+        private IScreenInfoProvider? _screen;
+        private IInputRoot? _inputRoot;
+        private const string LibInput = nameof(LinuxFramebuffer) + "/" + nameof(Input) + "/" + nameof(LibInput);
+        private Action<RawInputEventArgs>? _onInput;
+        private readonly LibInputBackendOptions? _options;
 
         public LibInputBackend()
         {
-            var ctx = libinput_path_create_context();
-            new Thread(() => InputThread(ctx))
-            {
-                IsBackground = true
-            }.Start();
+            _options = default;
+        }
+
+        public LibInputBackend(LibInputBackendOptions options)
+        {
+            _options = options;
         }
 
-        private unsafe void InputThread(IntPtr ctx)
+        private unsafe void InputThread(IntPtr ctx, LibInputBackendOptions options)
         {
             var fd = libinput_get_fd(ctx);
 
-            foreach (var f in Directory.GetFiles("/dev/input", "event*"))
+            foreach (var f in options.Events!)
                 libinput_path_add_device(ctx, f);
             while (true)
             {
@@ -37,8 +37,8 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
                 libinput_dispatch(ctx);
                 while ((ev = libinput_get_event(ctx)) != IntPtr.Zero)
                 {
-
                     var type = libinput_event_get_type(ev);
+
                     if (type >= LibInputEventType.LIBINPUT_EVENT_TOUCH_DOWN &&
                         type <= LibInputEventType.LIBINPUT_EVENT_TOUCH_CANCEL)
                         HandleTouch(ev, type);
@@ -56,50 +56,24 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
             }
         }
 
-        private void ScheduleInput(RawInputEventArgs ev) => _onInput.Invoke(ev);
-
-        private void HandleTouch(IntPtr ev, LibInputEventType type)
-        {
-            var tev = libinput_event_get_touch_event(ev);
-            if (tev == IntPtr.Zero)
-                return;
-            if (type < LibInputEventType.LIBINPUT_EVENT_TOUCH_FRAME)
-            {
-                var info = _screen.ScaledSize;
-                var slot = libinput_event_touch_get_slot(tev);
-                Point pt;
-
-                if (type == LibInputEventType.LIBINPUT_EVENT_TOUCH_DOWN
-                    || type == LibInputEventType.LIBINPUT_EVENT_TOUCH_MOTION)
-                {
-                    var x = libinput_event_touch_get_x_transformed(tev, (int)info.Width);
-                    var y = libinput_event_touch_get_y_transformed(tev, (int)info.Height);
-                    pt = new Point(x, y);
-                    _pointers[slot] = pt;
-                }
-                else
-                {
-                    _pointers.TryGetValue(slot, out pt);
-                    _pointers.Remove(slot);
-                }
-
-                var ts = libinput_event_touch_get_time_usec(tev) / 1000;
-                if (_inputRoot == null)
-                    return;
-                ScheduleInput(new RawTouchEventArgs(_touch, ts,
-                    _inputRoot,
-                    type == LibInputEventType.LIBINPUT_EVENT_TOUCH_DOWN ? RawPointerEventType.TouchBegin
-                    : type == LibInputEventType.LIBINPUT_EVENT_TOUCH_UP ? RawPointerEventType.TouchEnd
-                    : type == LibInputEventType.LIBINPUT_EVENT_TOUCH_MOTION ? RawPointerEventType.TouchUpdate
-                    : RawPointerEventType.TouchCancel,
-                    pt, RawInputModifiers.None, slot));
-            }
-        }
+        private void ScheduleInput(RawInputEventArgs ev) => _onInput?.Invoke(ev);
 
         public void Initialize(IScreenInfoProvider screen, Action<RawInputEventArgs> onInput)
         {
             _screen = screen;
             _onInput = onInput;
+            var ctx = libinput_path_create_context();
+            var options = new LibInputBackendOptions()
+            {
+                Events = _options?.Events is null
+                    ? Directory.GetFiles("/dev/input", "event*")
+                    : _options.Events,
+            };
+            new Thread(() => InputThread(ctx, options))
+            {
+                Name = "Input Manager Worker",
+                IsBackground = true
+            }.Start();
         }
 
         public void SetInputRoot(IInputRoot root)

+ 15 - 0
src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackendOptions.cs

@@ -0,0 +1,15 @@
+#nullable enable
+using System.Collections.Generic;
+
+namespace Avalonia.LinuxFramebuffer.Input.LibInput;
+
+/// <summary>
+/// LibInputBackend Options.
+/// </summary>
+public sealed record class LibInputBackendOptions
+{
+    /// <summary>
+    /// List Events of events handler to monitoring eg: /dev/eventX.
+    /// </summary>
+    public IReadOnlyList<string>? Events { get; init; } = null;
+}