| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.IO;
- using System.Threading;
- using Avalonia.Input;
- using Avalonia.Input.Raw;
- using Avalonia.Threading;
- using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods;
- namespace Avalonia.LinuxFramebuffer.Input.LibInput
- {
- public class LibInputBackend : IInputBackend
- {
- private IScreenInfoProvider _screen;
- private IInputRoot _inputRoot;
- private readonly Queue<Action> _inputThreadActions = new Queue<Action>();
- private TouchDevice _touch = new TouchDevice();
- private MouseDevice _mouse = new MouseDevice();
- private Point _mousePosition;
-
- private readonly Queue<RawInputEventArgs> _inputQueue = new Queue<RawInputEventArgs>();
- private Action<RawInputEventArgs> _onInput;
- private Dictionary<int, Point> _pointers = new Dictionary<int, Point>();
- public LibInputBackend()
- {
- var ctx = libinput_path_create_context();
-
- new Thread(()=>InputThread(ctx)).Start();
- }
-
-
- private unsafe void InputThread(IntPtr ctx)
- {
- var fd = libinput_get_fd(ctx);
-
- var timeval = stackalloc IntPtr[2];
- foreach (var f in Directory.GetFiles("/dev/input", "event*"))
- libinput_path_add_device(ctx, f);
- while (true)
- {
-
- IntPtr ev;
- 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);
- if (type >= LibInputEventType.LIBINPUT_EVENT_POINTER_MOTION
- && type <= LibInputEventType.LIBINPUT_EVENT_POINTER_AXIS)
- HandlePointer(ev, type);
-
- libinput_event_destroy(ev);
- libinput_dispatch(ctx);
- }
- pollfd pfd = new pollfd {fd = fd, events = 1};
- NativeUnsafeMethods.poll(&pfd, new IntPtr(1), 10);
- }
- }
- private void ScheduleInput(RawInputEventArgs ev)
- {
- lock (_inputQueue)
- {
- _inputQueue.Enqueue(ev);
- if (_inputQueue.Count == 1)
- {
- Dispatcher.UIThread.Post(() =>
- {
- while (true)
- {
- Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1);
- RawInputEventArgs dequeuedEvent = null;
- lock(_inputQueue)
- if (_inputQueue.Count != 0)
- dequeuedEvent = _inputQueue.Dequeue();
- if (dequeuedEvent == null)
- return;
- _onInput?.Invoke(dequeuedEvent);
- }
- }, DispatcherPriority.Input);
- }
- }
- }
- 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, InputModifiers.None, slot));
- }
- }
- private void HandlePointer(IntPtr ev, LibInputEventType type)
- {
- //TODO: support input modifiers
- var pev = libinput_event_get_pointer_event(ev);
- var info = _screen.ScaledSize;
- var ts = libinput_event_pointer_get_time_usec(pev) / 1000;
- if (type == LibInputEventType.LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE)
- {
- _mousePosition = new Point(libinput_event_pointer_get_absolute_x_transformed(pev, (int)info.Width),
- libinput_event_pointer_get_absolute_y_transformed(pev, (int)info.Height));
- ScheduleInput(new RawPointerEventArgs(_mouse, ts, _inputRoot, RawPointerEventType.Move, _mousePosition,
- InputModifiers.None));
- }
- else if (type == LibInputEventType.LIBINPUT_EVENT_POINTER_BUTTON)
- {
- var button = (EvKey)libinput_event_pointer_get_button(pev);
- var buttonState = libinput_event_pointer_get_button_state(pev);
- var evnt = button == EvKey.BTN_LEFT ?
- (buttonState == 1 ? RawPointerEventType.LeftButtonDown : RawPointerEventType.LeftButtonUp) :
- button == EvKey.BTN_MIDDLE ?
- (buttonState == 1 ? RawPointerEventType.MiddleButtonDown : RawPointerEventType.MiddleButtonUp) :
- button == EvKey.BTN_RIGHT ?
- (buttonState == 1 ?
- RawPointerEventType.RightButtonDown :
- RawPointerEventType.RightButtonUp) :
- (RawPointerEventType)(-1);
- if (evnt == (RawPointerEventType)(-1))
- return;
-
- ScheduleInput(
- new RawPointerEventArgs(_mouse, ts, _inputRoot, evnt, _mousePosition, InputModifiers.None));
- }
-
- }
-
-
- public void Initialize(IScreenInfoProvider screen, Action<RawInputEventArgs> onInput)
- {
- _screen = screen;
- _onInput = onInput;
- }
- public void SetInputRoot(IInputRoot root)
- {
- _inputRoot = root;
- }
- }
- }
|