LibInputBackend.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Threading;
  5. using Avalonia.Input;
  6. using Avalonia.Input.Raw;
  7. using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods;
  8. namespace Avalonia.LinuxFramebuffer.Input.LibInput
  9. {
  10. public partial class LibInputBackend : IInputBackend
  11. {
  12. private IScreenInfoProvider _screen;
  13. private IInputRoot _inputRoot;
  14. private TouchDevice _touch = new TouchDevice();
  15. private const string LibInput = nameof(Avalonia.LinuxFramebuffer) + "/" + nameof(Avalonia.LinuxFramebuffer.Input) + "/" + nameof(LibInput);
  16. private Action<RawInputEventArgs> _onInput;
  17. private Dictionary<int, Point> _pointers = new Dictionary<int, Point>();
  18. public LibInputBackend()
  19. {
  20. var ctx = libinput_path_create_context();
  21. new Thread(() => InputThread(ctx))
  22. {
  23. IsBackground = true
  24. }.Start();
  25. }
  26. private unsafe void InputThread(IntPtr ctx)
  27. {
  28. var fd = libinput_get_fd(ctx);
  29. var timeval = stackalloc IntPtr[2];
  30. foreach (var f in Directory.GetFiles("/dev/input", "event*"))
  31. libinput_path_add_device(ctx, f);
  32. while (true)
  33. {
  34. IntPtr ev;
  35. libinput_dispatch(ctx);
  36. while ((ev = libinput_get_event(ctx)) != IntPtr.Zero)
  37. {
  38. var type = libinput_event_get_type(ev);
  39. if (type >= LibInputEventType.LIBINPUT_EVENT_TOUCH_DOWN &&
  40. type <= LibInputEventType.LIBINPUT_EVENT_TOUCH_CANCEL)
  41. HandleTouch(ev, type);
  42. if (type >= LibInputEventType.LIBINPUT_EVENT_POINTER_MOTION
  43. && type <= LibInputEventType.LIBINPUT_EVENT_POINTER_AXIS)
  44. HandlePointer(ev, type);
  45. libinput_event_destroy(ev);
  46. libinput_dispatch(ctx);
  47. }
  48. pollfd pfd = new pollfd { fd = fd, events = 1 };
  49. NativeUnsafeMethods.poll(&pfd, new IntPtr(1), 10);
  50. }
  51. }
  52. private void ScheduleInput(RawInputEventArgs ev) => _onInput.Invoke(ev);
  53. private void HandleTouch(IntPtr ev, LibInputEventType type)
  54. {
  55. var tev = libinput_event_get_touch_event(ev);
  56. if (tev == IntPtr.Zero)
  57. return;
  58. if (type < LibInputEventType.LIBINPUT_EVENT_TOUCH_FRAME)
  59. {
  60. var info = _screen.ScaledSize;
  61. var slot = libinput_event_touch_get_slot(tev);
  62. Point pt;
  63. if (type == LibInputEventType.LIBINPUT_EVENT_TOUCH_DOWN
  64. || type == LibInputEventType.LIBINPUT_EVENT_TOUCH_MOTION)
  65. {
  66. var x = libinput_event_touch_get_x_transformed(tev, (int)info.Width);
  67. var y = libinput_event_touch_get_y_transformed(tev, (int)info.Height);
  68. pt = new Point(x, y);
  69. _pointers[slot] = pt;
  70. }
  71. else
  72. {
  73. _pointers.TryGetValue(slot, out pt);
  74. _pointers.Remove(slot);
  75. }
  76. var ts = libinput_event_touch_get_time_usec(tev) / 1000;
  77. if (_inputRoot == null)
  78. return;
  79. ScheduleInput(new RawTouchEventArgs(_touch, ts,
  80. _inputRoot,
  81. type == LibInputEventType.LIBINPUT_EVENT_TOUCH_DOWN ? RawPointerEventType.TouchBegin
  82. : type == LibInputEventType.LIBINPUT_EVENT_TOUCH_UP ? RawPointerEventType.TouchEnd
  83. : type == LibInputEventType.LIBINPUT_EVENT_TOUCH_MOTION ? RawPointerEventType.TouchUpdate
  84. : RawPointerEventType.TouchCancel,
  85. pt, RawInputModifiers.None, slot));
  86. }
  87. }
  88. public void Initialize(IScreenInfoProvider screen, Action<RawInputEventArgs> onInput)
  89. {
  90. _screen = screen;
  91. _onInput = onInput;
  92. }
  93. public void SetInputRoot(IInputRoot root)
  94. {
  95. _inputRoot = root;
  96. }
  97. }
  98. }