A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

109 lines
3.8 KiB

using System;
using System.Collections.Generic;
using System.Threading;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Threading;
using static Avalonia.LinuxFramebuffer.NativeUnsafeMethods;
namespace Avalonia.LinuxFramebuffer.Input.EvDev
{
public class EvDevBackend : IInputBackend
{
private readonly EvDevDeviceDescription[] _deviceDescriptions;
private readonly List<EvDevDeviceHandler> _handlers = new List<EvDevDeviceHandler>();
private int _epoll;
private bool _isQueueHandlerTriggered;
private object _lock = new object();
private Action<RawInputEventArgs> _onInput;
private IInputRoot _inputRoot;
private RawEventGroupingThreadingHelper _inputQueue;
public EvDevBackend(EvDevDeviceDescription[] devices)
{
_deviceDescriptions = devices;
_inputQueue = new RawEventGroupingThreadingHelper(e => _onInput?.Invoke(e));
}
unsafe void InputThread()
{
const int MaxEvents = 16;
var events = stackalloc epoll_event[MaxEvents];
while (true)
{
var eventCount = Math.Min(MaxEvents, epoll_wait(_epoll, events, MaxEvents, 1000));
for (var c = 0; c < eventCount; c++)
{
try
{
var ev = events[c];
var handler = _handlers[(int)ev.data.u32];
handler.HandleEvents();
}
catch (Exception e)
{
Console.Error.WriteLine(e.ToString());
}
}
}
}
private void OnRawEvent(RawInputEventArgs obj)
{
_inputQueue.OnEvent(obj);
}
public void Initialize(IScreenInfoProvider info, Action<RawInputEventArgs> onInput)
{
_onInput = onInput;
_epoll = epoll_create1(0);
for (var c = 0; c < _deviceDescriptions.Length; c++)
{
var description = _deviceDescriptions[c];
var dev = EvDevDevice.Open(description.Path);
EvDevDeviceHandler handler;
if (description is EvDevTouchScreenDeviceDescription touch)
handler = new EvDevSingleTouchScreen(dev, touch, info) { InputRoot = _inputRoot };
else
throw new Exception("Unknown device description type " + description.GetType().FullName);
handler.OnEvent += OnRawEvent;
_handlers.Add(handler);
var ev = new epoll_event { events = EPOLLIN, data = { u32 = (uint)c } };
epoll_ctl(_epoll, EPOLL_CTL_ADD, dev.Fd, ref ev);
}
new Thread(InputThread) { IsBackground = true }.Start();
}
public void SetInputRoot(IInputRoot root)
{
_inputRoot = root;
foreach (var h in _handlers)
h.InputRoot = root;
}
public static EvDevBackend CreateFromEnvironment()
{
var env = Environment.GetEnvironmentVariables();
var deviceDescriptions = new List<EvDevDeviceDescription>();
foreach (string key in env.Keys)
{
if (key.StartsWith("AVALONIA_EVDEV_DEVICE_"))
{
var value = (string)env[key];
deviceDescriptions.Add(EvDevDeviceDescription.ParseFromEnv(value));
}
}
if (deviceDescriptions.Count == 0)
throw new Exception(
"No device device description found, specify devices by adding AVALONIA_EVDEV_DEVICE_{name} environment variables");
return new EvDevBackend(deviceDescriptions.ToArray());
}
}
}