From 6a88bcaaaa8a4b4372fb8bfdedadc98440cce8a8 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 15 Mar 2024 11:08:47 +0100 Subject: [PATCH 1/5] refactor(LibInputBackend): Move HandleTouch in `LibInputBackend.Tocuch.cs` --- .../Input/LibInput/LibInputBackend.Touch.cs | 51 +++++++++++++++++++ .../Input/LibInput/LibInputBackend.cs | 40 --------------- 2 files changed, 51 insertions(+), 40 deletions(-) create mode 100644 src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.Touch.cs diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.Touch.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.Touch.cs new file mode 100644 index 00000000000..7a791247122 --- /dev/null +++ b/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 _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)); + } + } +} diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs index 1a22bf06e05..6839479072b 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs @@ -11,10 +11,8 @@ 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 _onInput; - private Dictionary _pointers = new Dictionary(); public LibInputBackend() { @@ -58,44 +56,6 @@ private unsafe void InputThread(IntPtr ctx) 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)); - } - } - public void Initialize(IScreenInfoProvider screen, Action onInput) { _screen = screen; From f77be425f31c7e71dd0a4262b2a26988425848cf Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 15 Mar 2024 11:36:32 +0100 Subject: [PATCH 2/5] 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 --- .../Input/LibInput/LibInputBackend.cs | 44 +++++++++++++------ .../Input/LibInput/LibInputBackendOptions.cs | 20 +++++++++ 2 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackendOptions.cs diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs index 6839479072b..0e60a3e0c20 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs +++ b/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,25 +9,30 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput { public partial class LibInputBackend : IInputBackend { - private IScreenInfoProvider _screen; - private IInputRoot _inputRoot; + private IScreenInfoProvider? _screen; + private IInputRoot? _inputRoot; private const string LibInput = nameof(Avalonia.LinuxFramebuffer) + "/" + nameof(Avalonia.LinuxFramebuffer.Input) + "/" + nameof(LibInput); - private Action _onInput; + private Action? _onInput; + private readonly LibInputBackendOptions? _options; public LibInputBackend() { - var ctx = libinput_path_create_context(); - new Thread(() => InputThread(ctx)) - { - IsBackground = true - }.Start(); + _options = default; } - private unsafe void InputThread(IntPtr ctx) + public LibInputBackend(LibInputBackendOptions options) + { + _options = options; + } + + + private unsafe void InputThread(object? state) { + var options = (LibInputBackendOptions)state!; + var ctx = options.LibInputContext; 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) { @@ -35,8 +40,8 @@ private unsafe void InputThread(IntPtr ctx) 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); @@ -54,12 +59,25 @@ private unsafe void InputThread(IntPtr ctx) } } - private void ScheduleInput(RawInputEventArgs ev) => _onInput.Invoke(ev); + private void ScheduleInput(RawInputEventArgs ev) => _onInput?.Invoke(ev); public void Initialize(IScreenInfoProvider screen, Action onInput) { _screen = screen; _onInput = onInput; + var ctx = libinput_path_create_context(); + var options = new LibInputBackendOptions() + { + LibInputContext = ctx, + Events = _options is null + ? Directory.GetFiles("/dev/input", "event*") + : _options.Events, + }; + new Thread(InputThread) + { + Name = "Input Manager Worker", + IsBackground = true + }.Start(options); } public void SetInputRoot(IInputRoot root) diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackendOptions.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackendOptions.cs new file mode 100644 index 00000000000..d9b9b628ffb --- /dev/null +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackendOptions.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; + +namespace Avalonia.LinuxFramebuffer.Input.LibInput; + +/// +/// LibInputBackend Options. +/// +public sealed record class LibInputBackendOptions +{ + /// + /// Used internally to pass libinput context to . + /// + internal IntPtr LibInputContext { get; init; } + + /// + /// List Events of events handler to monitoring eg: /dev/eventX. + /// + public IReadOnlyList Events { get; init; } = Array.Empty(); +} From 1f926acd56a474ba90c8cec89ef04f224a6a07f6 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 15 Mar 2024 15:44:49 +0100 Subject: [PATCH 3/5] fix: nits --- .../Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs index 0e60a3e0c20..ba034a4850f 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs @@ -25,7 +25,6 @@ public LibInputBackend(LibInputBackendOptions options) _options = options; } - private unsafe void InputThread(object? state) { var options = (LibInputBackendOptions)state!; From d697a72114f36df62f0b0d7d45106e7acf8a9b80 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Fri, 22 Mar 2024 16:51:45 +0100 Subject: [PATCH 4/5] fix: Address review --- .../Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs | 2 +- .../Input/LibInput/LibInputBackendOptions.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs index ba034a4850f..018bc0bdf46 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs @@ -68,7 +68,7 @@ public void Initialize(IScreenInfoProvider screen, Action onI var options = new LibInputBackendOptions() { LibInputContext = ctx, - Events = _options is null + Events = _options?.Events is null ? Directory.GetFiles("/dev/input", "event*") : _options.Events, }; diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackendOptions.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackendOptions.cs index d9b9b628ffb..bc04e02ccc0 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackendOptions.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackendOptions.cs @@ -16,5 +16,5 @@ public sealed record class LibInputBackendOptions /// /// List Events of events handler to monitoring eg: /dev/eventX. /// - public IReadOnlyList Events { get; init; } = Array.Empty(); + public IReadOnlyList Events { get; init; } = null; } From 247b77f1acd5b06bc85a15a47be4f5697d055e87 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Mon, 25 Mar 2024 09:29:21 +0100 Subject: [PATCH 5/5] fix: Address review --- .../Input/LibInput/LibInputBackend.cs | 13 +++++-------- .../Input/LibInput/LibInputBackendOptions.cs | 9 ++------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs index 018bc0bdf46..91e33526d0c 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs @@ -11,7 +11,7 @@ public partial class LibInputBackend : IInputBackend { private IScreenInfoProvider? _screen; private IInputRoot? _inputRoot; - private const string LibInput = nameof(Avalonia.LinuxFramebuffer) + "/" + nameof(Avalonia.LinuxFramebuffer.Input) + "/" + nameof(LibInput); + private const string LibInput = nameof(LinuxFramebuffer) + "/" + nameof(Input) + "/" + nameof(LibInput); private Action? _onInput; private readonly LibInputBackendOptions? _options; @@ -25,13 +25,11 @@ public LibInputBackend(LibInputBackendOptions options) _options = options; } - private unsafe void InputThread(object? state) + private unsafe void InputThread(IntPtr ctx, LibInputBackendOptions options) { - var options = (LibInputBackendOptions)state!; - var ctx = options.LibInputContext; var fd = libinput_get_fd(ctx); - foreach (var f in options.Events) + foreach (var f in options.Events!) libinput_path_add_device(ctx, f); while (true) { @@ -67,16 +65,15 @@ public void Initialize(IScreenInfoProvider screen, Action onI var ctx = libinput_path_create_context(); var options = new LibInputBackendOptions() { - LibInputContext = ctx, Events = _options?.Events is null ? Directory.GetFiles("/dev/input", "event*") : _options.Events, }; - new Thread(InputThread) + new Thread(() => InputThread(ctx, options)) { Name = "Input Manager Worker", IsBackground = true - }.Start(options); + }.Start(); } public void SetInputRoot(IInputRoot root) diff --git a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackendOptions.cs b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackendOptions.cs index bc04e02ccc0..6df91ad5bb6 100644 --- a/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackendOptions.cs +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackendOptions.cs @@ -1,4 +1,4 @@ -using System; +#nullable enable using System.Collections.Generic; namespace Avalonia.LinuxFramebuffer.Input.LibInput; @@ -8,13 +8,8 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput; /// public sealed record class LibInputBackendOptions { - /// - /// Used internally to pass libinput context to . - /// - internal IntPtr LibInputContext { get; init; } - /// /// List Events of events handler to monitoring eg: /dev/eventX. /// - public IReadOnlyList Events { get; init; } = null; + public IReadOnlyList? Events { get; init; } = null; }