1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Linux - Fixed input provider warnings

This commit is contained in:
Diogo Trindade 2022-08-20 16:48:02 +01:00
parent 090d5b76e8
commit 6fe93ab2f7
10 changed files with 176 additions and 107 deletions

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Artemis.UI.Linux.Providers.Input
{
public class ArtemisLinuxInputProviderException : Exception
{
public ArtemisLinuxInputProviderException() : base()
{
}
public ArtemisLinuxInputProviderException(string? message) : base(message)
{
}
public ArtemisLinuxInputProviderException(string? message, Exception? innerException) : base(message, innerException)
{
}
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Artemis.UI.Linux.Providers.Input
{
public enum LinuxDeviceType
{
Keyboard,
Mouse,
Gamepad
}
}

View File

@ -1,9 +1,6 @@
using System; using Artemis.Core;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection.Metadata;
using Humanizer;
namespace Artemis.UI.Linux.Providers.Input namespace Artemis.UI.Linux.Providers.Input
{ {
@ -12,75 +9,52 @@ namespace Artemis.UI.Linux.Providers.Input
/// </summary> /// </summary>
public class LinuxInputDevice public class LinuxInputDevice
{ {
public string InputId { get; } public LinuxInputId InputId { get; }
public string? Bus { get; } public string Name { get; }
public string? Vendor { get; } public string[] Handlers { get; }
public string? Product { get; } public string EventPath { get; }
public string? Version { get; } public LinuxDeviceType DeviceType { get; }
public string? Name { get; }
public string? Phys { get; }
public string? Sysfs { get; }
public string? Uniq { get; }
public string[]? Handlers { get; }
public bool IsMouse => Handlers.Any(h => h.Contains("mouse"));
public bool IsKeyboard => Handlers.Any(h => h.Contains("kbd"));
public bool IsGamePad => Handlers.Any(h => h.Contains("js"));
public string EventPath => $"/dev/input/{Handlers.First(h => h.Contains("event"))}";
public LinuxInputDevice(IEnumerable<string> lines) public LinuxInputDevice(IEnumerable<string> lines)
{ {
foreach (string line in lines) foreach (string line in lines)
{ {
char dataType = line.First();
string data = line.Substring(3);
//get the first character in each line and set the according property with relevant data //get the first character in each line and set the according property with relevant data
char dataType = line[0];
string data = line[3..];
switch (dataType) switch (dataType)
{ {
case 'I': case 'I':
InputId = data; InputId = new LinuxInputId(data);
foreach (string component in data.Split(" "))
{
string?[] parts = component.Split('=');
switch (parts[0])
{
case "Bus":
Bus = parts[1];
break;
case "Vendor":
Vendor = parts[1];
break;
case "Product":
Product = parts[1];
break;
case "Version":
Version = parts[1];
break;
default:
break;
}
}
break; break;
case 'N': case 'N':
Name = data.Replace("\"", "") Name = data.Replace("\"", "").Replace("Name=", "");
.Replace("Name=", "");
break;
case 'P':
Phys = data.Replace("Phys=", "");
break;
case 'S':
Sysfs = data.Replace("Sysfs=", "");
break; break;
case 'H': case 'H':
Handlers = data.Replace("Handlers=", "").Split(" "); Handlers = data.Replace("Handlers=", "").Split(" ");
break;
case 'U': if (Handlers?.Any(h => h.Contains("mouse")) == true)
Uniq = data.Replace("Uniq=", ""); DeviceType = LinuxDeviceType.Mouse;
else if (Handlers?.Any(h => h.Contains("kbd")) == true)
DeviceType = LinuxDeviceType.Keyboard;
else if (Handlers?.Any(h => h.Contains("js")) == true)
DeviceType = LinuxDeviceType.Gamepad;
var evt = Handlers!.First(h => h.Contains("event"));
EventPath = $"/dev/input/{evt}";
break; break;
default: default:
//do we need any more of this data? //do we need any more of this data?
break; break;
} }
} }
if (InputId is null || Name is null || Handlers is null || EventPath is null)
{
throw new ArtemisLinuxInputProviderException("Linux device definition did not contain necessary data");
}
} }
#region Overrides of Object #region Overrides of Object
@ -89,5 +63,27 @@ namespace Artemis.UI.Linux.Providers.Input
public override string ToString() => $"{Name} - {EventPath}"; public override string ToString() => $"{Name} - {EventPath}";
#endregion #endregion
public class LinuxInputId
{
public string Bus { get; }
public string Vendor { get; }
public string Product { get; }
public string Version { get; }
public LinuxInputId(string line)
{
var components = line.Split(" ")
.Select(c => c.Split('='))
.ToDictionary(c => c[0], c => c[1]);
Bus = components["Bus"];
Vendor = components["Vendor"];
Product = components["Product"];
Version = components["Version"];
}
public override string ToString() => $"Bus={Bus} Vendor={Vendor} Product={Product} Version={Version}";
}
} }
} }

View File

@ -12,7 +12,7 @@ namespace Artemis.UI.Linux.Providers.Input
public static IEnumerable<LinuxInputDevice> Find() public static IEnumerable<LinuxInputDevice> Find()
{ {
return File.ReadAllLines(DEVICES_FILE) return File.ReadAllLines(DEVICES_FILE)
.PartitionBy(s => s == "") //split on empty lines .PartitionBy(s => s?.Length == 0) //split on empty lines
.Select(lineGroup => new LinuxInputDevice(lineGroup)); .Select(lineGroup => new LinuxInputDevice(lineGroup));
} }
@ -33,7 +33,7 @@ namespace Artemis.UI.Linux.Providers.Input
return groupNumber; return groupNumber;
}; };
return a return a
.Select(x => new { Value = x, GroupNumber = getGroupNumber(predicate(x))} ) .Select(x => new { Value = x, GroupNumber = getGroupNumber(predicate(x)) })
.Where(x => x.GroupNumber != null) .Where(x => x.GroupNumber != null)
.GroupBy(x => x.GroupNumber) .GroupBy(x => x.GroupNumber)
.Select(g => g.Select(x => x.Value)); .Select(g => g.Select(x => x.Value));

View File

@ -3,7 +3,6 @@ using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Artemis.UI.Linux.Utilities;
namespace Artemis.UI.Linux.Providers.Input namespace Artemis.UI.Linux.Providers.Input
{ {

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Artemis.Core;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.Linux.Utilities; using Artemis.UI.Linux.Utilities;
using Serilog; using Serilog;
@ -20,7 +21,7 @@ namespace Artemis.UI.Linux.Providers.Input
foreach (LinuxInputDevice deviceDefinition in LinuxInputDeviceFinder.Find()) foreach (LinuxInputDevice deviceDefinition in LinuxInputDeviceFinder.Find())
{ {
LinuxInputDeviceReader? reader = new LinuxInputDeviceReader(deviceDefinition); LinuxInputDeviceReader? reader = new(deviceDefinition);
reader.InputEvent += OnInputEvent; reader.InputEvent += OnInputEvent;
_readers.Add(reader); _readers.Add(reader);
} }
@ -30,68 +31,103 @@ namespace Artemis.UI.Linux.Providers.Input
{ {
if (sender is not LinuxInputDeviceReader reader) if (sender is not LinuxInputDeviceReader reader)
return; return;
switch (reader.InputDevice.DeviceType)
if (reader.InputDevice.IsKeyboard)
{ {
HandleKeyboardData(reader.InputDevice, e); case LinuxDeviceType.Keyboard:
} HandleKeyboardData(reader.InputDevice, e);
else if (reader.InputDevice.IsMouse) break;
{ case LinuxDeviceType.Mouse:
HandleMouseData(reader.InputDevice, e); HandleMouseData(reader.InputDevice, e);
} break;
else if (reader.InputDevice.IsGamePad) case LinuxDeviceType.Gamepad:
{ break;
//TODO: handle game pad input?
} }
} }
private void HandleKeyboardData(LinuxInputDevice keyboard, LinuxInputEventArgs e) private void HandleKeyboardData(LinuxInputDevice keyboard, LinuxInputEventArgs args)
{ {
switch (e.Type) switch (args.Type)
{ {
case LinuxInputEventType.KEY: case LinuxInputEventType.KEY:
KeyboardKey key = InputUtilities.KeyFromKeyCode((LinuxKeyboardKeyCodes) e.Code); KeyboardKey key = InputUtilities.KeyFromKeyCode((LinuxKeyboardKeyCodes)args.Code);
bool isDown = e.Value != 0; bool isDown = args.Value != 0;
_logger.Verbose($"Keyboard Key: {(LinuxKeyboardKeyCodes) e.Code} | Down: {isDown}"); _logger.Verbose($"Keyboard Key: {(LinuxKeyboardKeyCodes)args.Code} | Down: {isDown}");
//TODO: identify var identifier = keyboard.InputId;
OnKeyboardDataReceived(null, key, isDown); OnIdentifierReceived(identifier, InputDeviceType.Keyboard);
ArtemisDevice? device = null;
try
{
device = _inputService.GetDeviceByIdentifier(this, identifier, InputDeviceType.Keyboard);
}
catch (Exception e)
{
_logger.Warning(e, "Failed to retrieve input device by its identifier");
}
OnKeyboardDataReceived(device, key, isDown);
break; break;
default: default:
_logger.Verbose($"Unknown keyboard event type: {e.Type}"); _logger.Verbose($"Unknown keyboard event type: {args.Type}");
break; break;
} }
} }
private void HandleMouseData(LinuxInputDevice mouse, LinuxInputEventArgs e) private void HandleMouseData(LinuxInputDevice mouse, LinuxInputEventArgs args)
{ {
switch (e.Type) var identifier = mouse.InputId;
OnIdentifierReceived(identifier, InputDeviceType.Mouse);
ArtemisDevice? device = null;
try
{
device = _inputService.GetDeviceByIdentifier(this, identifier, InputDeviceType.Mouse);
}
catch (Exception e)
{
_logger.Warning(e, "Failed to retrieve input device by its identifier");
}
switch (args.Type)
{ {
case LinuxInputEventType.KEY: case LinuxInputEventType.KEY:
bool isDown = e.Value != 0; bool isDown = args.Value != 0;
MouseButton button = InputUtilities.MouseButtonFromButtonCode((LinuxKeyboardKeyCodes)e.Code); MouseButton button = InputUtilities.MouseButtonFromButtonCode((LinuxKeyboardKeyCodes)args.Code);
_logger.Verbose($"Mouse Button: {(LinuxKeyboardKeyCodes) e.Code} | Down: {isDown}"); _logger.Verbose($"Mouse Button: {(LinuxKeyboardKeyCodes)args.Code} | Down: {isDown}");
//TODO: identify OnMouseButtonDataReceived(device, button, isDown);
OnMouseButtonDataReceived(null, button, isDown);
break; break;
case LinuxInputEventType.ABS:
LinuxAbsoluteAxis absoluteAxis = (LinuxAbsoluteAxis) e.Code;
_logger.Verbose($"Absolute mouse: axis={absoluteAxis} | value={e.Value}");
break;
case LinuxInputEventType.REL: case LinuxInputEventType.REL:
LinuxRelativeAxis relativeAxis = (LinuxRelativeAxis) e.Code; LinuxRelativeAxis relativeAxis = (LinuxRelativeAxis)args.Code;
_logger.Verbose($"Relative mouse: axis={relativeAxis} | value={e.Value}");
//TODO: handle mouse movement _logger.Verbose($"Relative mouse: axis={relativeAxis} | value={args.Value}");
switch (relativeAxis)
{
case LinuxRelativeAxis.REL_WHEEL:
OnMouseScrollDataReceived(device, MouseScrollDirection.Vertical, args.Value);
break;
case LinuxRelativeAxis.REL_HWHEEL:
OnMouseScrollDataReceived(device, MouseScrollDirection.Horizontal, args.Value);
break;
case LinuxRelativeAxis.REL_X:
OnMouseMoveDataReceived(device, 0, 0, args.Value, 0);
break;
case LinuxRelativeAxis.REL_Y:
OnMouseMoveDataReceived(device, 0, 0, 0, args.Value);
break;
}
break; break;
default: default:
_logger.Verbose($"Unknown mouse event type: {e.Type}"); _logger.Verbose($"Unknown mouse event type: {args.Type}");
break; break;
} }
} }