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:
parent
090d5b76e8
commit
6fe93ab2f7
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -9,57 +9,57 @@ namespace Artemis.UI.Linux.Providers.Input
|
||||
/// Used as markers to separate events. Events may be separated in time or in space, such as with the multitouch protocol.
|
||||
/// </summary>
|
||||
SYN = 0x00,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used to describe state changes of keyboards, buttons, or other key-like devices.
|
||||
/// </summary>
|
||||
KEY = 0x01,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used to describe relative axis value changes, e.g. moving the mouse 5 units to the left.
|
||||
/// </summary>
|
||||
REL = 0x02,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used to describe absolute axis value changes, e.g. describing the coordinates of a touch on a touchscreen.
|
||||
/// </summary>
|
||||
ABS = 0x03,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used to describe miscellaneous input data that do not fit into other types.
|
||||
/// </summary>
|
||||
MSC = 0x04,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used to describe binary state input switches.
|
||||
/// </summary>
|
||||
SW = 0x05,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used to turn LEDs on devices on and off.
|
||||
/// </summary>
|
||||
LED = 0x11,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used to output sound to devices.
|
||||
/// </summary>
|
||||
SND = 0x12,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used for autorepeating devices.
|
||||
/// </summary>
|
||||
REP = 0x14,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used to send force feedback commands to an input device.
|
||||
/// </summary>
|
||||
FF = 0x15,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A special type for power button and switch input.
|
||||
/// </summary>
|
||||
PWR = 0x16,
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used to receive force feedback device status.
|
||||
/// </summary>
|
||||
@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Artemis.Core;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
using Humanizer;
|
||||
|
||||
namespace Artemis.UI.Linux.Providers.Input
|
||||
{
|
||||
@ -12,82 +9,81 @@ namespace Artemis.UI.Linux.Providers.Input
|
||||
/// </summary>
|
||||
public class LinuxInputDevice
|
||||
{
|
||||
public string InputId { get; }
|
||||
public string? Bus { get; }
|
||||
public string? Vendor { get; }
|
||||
public string? Product { get; }
|
||||
public string? Version { 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 LinuxInputId InputId { get; }
|
||||
public string Name { get; }
|
||||
public string[] Handlers { get; }
|
||||
public string EventPath { get; }
|
||||
public LinuxDeviceType DeviceType { get; }
|
||||
|
||||
public LinuxInputDevice(IEnumerable<string> 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
|
||||
|
||||
char dataType = line[0];
|
||||
string data = line[3..];
|
||||
switch (dataType)
|
||||
{
|
||||
case 'I':
|
||||
InputId = 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;
|
||||
}
|
||||
}
|
||||
InputId = new LinuxInputId(data);
|
||||
break;
|
||||
case 'N':
|
||||
Name = data.Replace("\"", "")
|
||||
.Replace("Name=", "");
|
||||
break;
|
||||
case 'P':
|
||||
Phys = data.Replace("Phys=", "");
|
||||
break;
|
||||
case 'S':
|
||||
Sysfs = data.Replace("Sysfs=", "");
|
||||
Name = data.Replace("\"", "").Replace("Name=", "");
|
||||
break;
|
||||
case 'H':
|
||||
Handlers = data.Replace("Handlers=", "").Split(" ");
|
||||
break;
|
||||
case 'U':
|
||||
Uniq = data.Replace("Uniq=", "");
|
||||
|
||||
if (Handlers?.Any(h => h.Contains("mouse")) == true)
|
||||
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;
|
||||
default:
|
||||
//do we need any more of this data?
|
||||
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
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString() => $"{Name} - {EventPath}";
|
||||
|
||||
#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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,11 +8,11 @@ namespace Artemis.UI.Linux.Providers.Input
|
||||
public static class LinuxInputDeviceFinder
|
||||
{
|
||||
private const string DEVICES_FILE = "/proc/bus/input/devices";
|
||||
|
||||
|
||||
public static IEnumerable<LinuxInputDevice> Find()
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
@ -33,10 +33,10 @@ namespace Artemis.UI.Linux.Providers.Input
|
||||
return groupNumber;
|
||||
};
|
||||
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)
|
||||
.GroupBy(x => x.GroupNumber)
|
||||
.Select(g => g.Select(x => x.Value));
|
||||
.Select(g => g.Select(x => x.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,6 @@ using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.UI.Linux.Utilities;
|
||||
|
||||
namespace Artemis.UI.Linux.Providers.Input
|
||||
{
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Linux.Utilities;
|
||||
using Serilog;
|
||||
@ -20,7 +21,7 @@ namespace Artemis.UI.Linux.Providers.Input
|
||||
|
||||
foreach (LinuxInputDevice deviceDefinition in LinuxInputDeviceFinder.Find())
|
||||
{
|
||||
LinuxInputDeviceReader? reader = new LinuxInputDeviceReader(deviceDefinition);
|
||||
LinuxInputDeviceReader? reader = new(deviceDefinition);
|
||||
reader.InputEvent += OnInputEvent;
|
||||
_readers.Add(reader);
|
||||
}
|
||||
@ -30,68 +31,103 @@ namespace Artemis.UI.Linux.Providers.Input
|
||||
{
|
||||
if (sender is not LinuxInputDeviceReader reader)
|
||||
return;
|
||||
|
||||
if (reader.InputDevice.IsKeyboard)
|
||||
switch (reader.InputDevice.DeviceType)
|
||||
{
|
||||
HandleKeyboardData(reader.InputDevice, e);
|
||||
}
|
||||
else if (reader.InputDevice.IsMouse)
|
||||
{
|
||||
HandleMouseData(reader.InputDevice, e);
|
||||
}
|
||||
else if (reader.InputDevice.IsGamePad)
|
||||
{
|
||||
//TODO: handle game pad input?
|
||||
case LinuxDeviceType.Keyboard:
|
||||
HandleKeyboardData(reader.InputDevice, e);
|
||||
break;
|
||||
case LinuxDeviceType.Mouse:
|
||||
HandleMouseData(reader.InputDevice, e);
|
||||
break;
|
||||
case LinuxDeviceType.Gamepad:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleKeyboardData(LinuxInputDevice keyboard, LinuxInputEventArgs e)
|
||||
private void HandleKeyboardData(LinuxInputDevice keyboard, LinuxInputEventArgs args)
|
||||
{
|
||||
switch (e.Type)
|
||||
switch (args.Type)
|
||||
{
|
||||
case LinuxInputEventType.KEY:
|
||||
KeyboardKey key = InputUtilities.KeyFromKeyCode((LinuxKeyboardKeyCodes) e.Code);
|
||||
bool isDown = e.Value != 0;
|
||||
KeyboardKey key = InputUtilities.KeyFromKeyCode((LinuxKeyboardKeyCodes)args.Code);
|
||||
bool isDown = args.Value != 0;
|
||||
|
||||
_logger.Verbose($"Keyboard Key: {(LinuxKeyboardKeyCodes) e.Code} | Down: {isDown}");
|
||||
|
||||
//TODO: identify
|
||||
_logger.Verbose($"Keyboard Key: {(LinuxKeyboardKeyCodes)args.Code} | Down: {isDown}");
|
||||
|
||||
OnKeyboardDataReceived(null, key, isDown);
|
||||
var identifier = keyboard.InputId;
|
||||
|
||||
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;
|
||||
default:
|
||||
_logger.Verbose($"Unknown keyboard event type: {e.Type}");
|
||||
_logger.Verbose($"Unknown keyboard event type: {args.Type}");
|
||||
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:
|
||||
bool isDown = e.Value != 0;
|
||||
MouseButton button = InputUtilities.MouseButtonFromButtonCode((LinuxKeyboardKeyCodes)e.Code);
|
||||
bool isDown = args.Value != 0;
|
||||
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(null, button, isDown);
|
||||
OnMouseButtonDataReceived(device, button, isDown);
|
||||
break;
|
||||
|
||||
case LinuxInputEventType.ABS:
|
||||
LinuxAbsoluteAxis absoluteAxis = (LinuxAbsoluteAxis) e.Code;
|
||||
_logger.Verbose($"Absolute mouse: axis={absoluteAxis} | value={e.Value}");
|
||||
break;
|
||||
case LinuxInputEventType.REL:
|
||||
LinuxRelativeAxis relativeAxis = (LinuxRelativeAxis) e.Code;
|
||||
_logger.Verbose($"Relative mouse: axis={relativeAxis} | value={e.Value}");
|
||||
LinuxRelativeAxis relativeAxis = (LinuxRelativeAxis)args.Code;
|
||||
|
||||
//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;
|
||||
default:
|
||||
_logger.Verbose($"Unknown mouse event type: {e.Type}");
|
||||
_logger.Verbose($"Unknown mouse event type: {args.Type}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user