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..91e33526d0c 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,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 _onInput; - private Dictionary _pointers = new Dictionary(); + private IScreenInfoProvider? _screen; + private IInputRoot? _inputRoot; + private const string LibInput = nameof(LinuxFramebuffer) + "/" + nameof(Input) + "/" + nameof(LibInput); + private Action? _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 @@ 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); @@ -56,50 +56,24 @@ 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)); - } - } + 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() + { + 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) 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..6df91ad5bb6 --- /dev/null +++ b/src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackendOptions.cs @@ -0,0 +1,15 @@ +#nullable enable +using System.Collections.Generic; + +namespace Avalonia.LinuxFramebuffer.Input.LibInput; + +/// +/// LibInputBackend Options. +/// +public sealed record class LibInputBackendOptions +{ + /// + /// List Events of events handler to monitoring eg: /dev/eventX. + /// + public IReadOnlyList? Events { get; init; } = null; +}