2023-06-08 13:36:25 -07:00

149 lines
4.2 KiB
C#

using Microsoft.Extensions.Logging;
namespace Barcode.Host.Shared.KeyboardMouse;
public class InputReader : IDisposable
{
private long _Ticks;
private bool _Disposing;
private readonly int _PiOffset;
private const int _BufferLength = 24;
private readonly FileStream? _FileStream;
private readonly ILogger<IDisposable> _Logger;
private readonly byte[] _Buffer = new byte[_BufferLength];
public string Path { get; init; }
public bool Faulted { get; private set; }
public event RaiseKeyPress? OnKeyPress;
public event RaiseMouseMove? OnMouseMove;
public delegate void RaiseKeyPress(KeyPressEvent e);
public delegate void RaiseMouseMove(MouseMoveEvent e);
public InputReader(string path, ILogger<IDisposable> logger)
{
Path = path;
_Logger = logger;
if (RunningOnRaspberryPi())
_PiOffset = -8;
try
{ _FileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); }
catch (UnauthorizedAccessException ex)
{
logger.LogError(ex, "Current user doesn't have permissions to access input data. Add user to input group to correct this error");
Faulted = true;
}
catch (IOException ex)
{
logger.LogWarning(ex, $"Error occurred while trying to build stream for {path}");
Faulted = true;
}
_ = Task.Run(Run);
}
private void Run()
{
while (true)
{
if (_Disposing)
break;
try
{
if (!Faulted && _FileStream is not null)
_ = _FileStream.Read(_Buffer, 0, _BufferLength);
}
catch (IOException ex)
{
_Logger.LogInformation(ex, $"Error occured while trying to read from the stream for {Path}");
Faulted = true;
}
EventType type = GetEventType();
switch (type)
{
case EventType.EV_SYN:
_Ticks = DateTime.Now.Ticks;
break;
case EventType.EV_KEY:
HandleKeyPressEvent();
break;
case EventType.EV_REL:
HandleMouseMoveEvent();
break;
}
}
}
private int GetValue()
{
byte[] valueBits = new[]
{
_Buffer[20 + _PiOffset],
_Buffer[21 + _PiOffset],
_Buffer[22 + _PiOffset],
_Buffer[23 + _PiOffset]
};
int value = BitConverter.ToInt32(valueBits, 0);
return value;
}
private short GetCode()
{
byte[] codeBits = new[]
{
_Buffer[18 + _PiOffset],
_Buffer[19 + _PiOffset]
};
short code = BitConverter.ToInt16(codeBits, 0);
return code;
}
private EventType GetEventType()
{
byte[] typeBits = new[]
{
_Buffer[16 + _PiOffset],
_Buffer[17 + _PiOffset]
};
short type = BitConverter.ToInt16(typeBits, 0);
EventType eventType = (EventType)type;
return eventType;
}
private void HandleKeyPressEvent()
{
short code = GetCode();
int value = GetValue();
DateTime dateTime = DateTime.Now;
KeyState keyState = (KeyState)value;
EventCode eventCode = (EventCode)code;
KeyPressEvent keyPressEvent = new(dateTime, eventCode, keyState, new TimeSpan(dateTime.Ticks - _Ticks));
OnKeyPress?.Invoke(keyPressEvent);
}
private void HandleMouseMoveEvent()
{
short code = GetCode();
int value = GetValue();
MouseAxis axis = (MouseAxis)code;
MouseMoveEvent e = new(axis, value);
OnMouseMove?.Invoke(e);
}
public void Dispose()
{
_Disposing = true;
_FileStream?.Dispose();
GC.SuppressFinalize(this);
}
private static bool RunningOnRaspberryPi()
{
string path = "/proc/cpuinfo";
string[] text = File.ReadAllLines(path);
bool runningOnPi = text.Any(l => l.Contains("Raspberry Pi"));
return runningOnPi;
}
}