diff --git a/src/Artemis.UI.Linux/Providers/Input/ArtemisLinuxInputProviderException.cs b/src/Artemis.UI.Linux/Providers/Input/ArtemisLinuxInputProviderException.cs
new file mode 100644
index 000000000..6642c17de
--- /dev/null
+++ b/src/Artemis.UI.Linux/Providers/Input/ArtemisLinuxInputProviderException.cs
@@ -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)
+ {
+ }
+ }
+}
diff --git a/src/Artemis.UI.Linux/Providers/Input/LinuxAbsoluteAxis.cs b/src/Artemis.UI.Linux/Providers/Input/Enums/LinuxAbsoluteAxis.cs
similarity index 100%
rename from src/Artemis.UI.Linux/Providers/Input/LinuxAbsoluteAxis.cs
rename to src/Artemis.UI.Linux/Providers/Input/Enums/LinuxAbsoluteAxis.cs
diff --git a/src/Artemis.UI.Linux/Providers/Input/Enums/LinuxDeviceType.cs b/src/Artemis.UI.Linux/Providers/Input/Enums/LinuxDeviceType.cs
new file mode 100644
index 000000000..22e956420
--- /dev/null
+++ b/src/Artemis.UI.Linux/Providers/Input/Enums/LinuxDeviceType.cs
@@ -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
+ }
+}
diff --git a/src/Artemis.UI.Linux/Providers/Input/LinuxInputEventType.cs b/src/Artemis.UI.Linux/Providers/Input/Enums/LinuxInputEventType.cs
similarity index 93%
rename from src/Artemis.UI.Linux/Providers/Input/LinuxInputEventType.cs
rename to src/Artemis.UI.Linux/Providers/Input/Enums/LinuxInputEventType.cs
index dadeb76aa..9701e1717 100644
--- a/src/Artemis.UI.Linux/Providers/Input/LinuxInputEventType.cs
+++ b/src/Artemis.UI.Linux/Providers/Input/Enums/LinuxInputEventType.cs
@@ -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.
///
SYN = 0x00,
-
+
///
/// Used to describe state changes of keyboards, buttons, or other key-like devices.
///
KEY = 0x01,
-
+
///
/// Used to describe relative axis value changes, e.g. moving the mouse 5 units to the left.
///
REL = 0x02,
-
+
///
/// Used to describe absolute axis value changes, e.g. describing the coordinates of a touch on a touchscreen.
///
ABS = 0x03,
-
+
///
/// Used to describe miscellaneous input data that do not fit into other types.
///
MSC = 0x04,
-
+
///
/// Used to describe binary state input switches.
///
SW = 0x05,
-
+
///
/// Used to turn LEDs on devices on and off.
///
LED = 0x11,
-
+
///
/// Used to output sound to devices.
///
SND = 0x12,
-
+
///
/// Used for autorepeating devices.
///
REP = 0x14,
-
+
///
/// Used to send force feedback commands to an input device.
///
FF = 0x15,
-
+
///
/// A special type for power button and switch input.
///
PWR = 0x16,
-
+
///
/// Used to receive force feedback device status.
///
diff --git a/src/Artemis.UI.Linux/Providers/Input/LinuxKeyboardKeyCodes.cs b/src/Artemis.UI.Linux/Providers/Input/Enums/LinuxKeyboardKeyCodes.cs
similarity index 100%
rename from src/Artemis.UI.Linux/Providers/Input/LinuxKeyboardKeyCodes.cs
rename to src/Artemis.UI.Linux/Providers/Input/Enums/LinuxKeyboardKeyCodes.cs
diff --git a/src/Artemis.UI.Linux/Providers/Input/LinuxRelativeAxis.cs b/src/Artemis.UI.Linux/Providers/Input/Enums/LinuxRelativeAxis.cs
similarity index 100%
rename from src/Artemis.UI.Linux/Providers/Input/LinuxRelativeAxis.cs
rename to src/Artemis.UI.Linux/Providers/Input/Enums/LinuxRelativeAxis.cs
diff --git a/src/Artemis.UI.Linux/Providers/Input/LinuxInputDevice.cs b/src/Artemis.UI.Linux/Providers/Input/LinuxInputDevice.cs
index b944da4d4..9fae6eee2 100644
--- a/src/Artemis.UI.Linux/Providers/Input/LinuxInputDevice.cs
+++ b/src/Artemis.UI.Linux/Providers/Input/LinuxInputDevice.cs
@@ -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
///
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 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
///
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}";
+ }
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI.Linux/Providers/Input/LinuxInputDeviceFinder.cs b/src/Artemis.UI.Linux/Providers/Input/LinuxInputDeviceFinder.cs
index 7268b1ee4..60082f2f3 100644
--- a/src/Artemis.UI.Linux/Providers/Input/LinuxInputDeviceFinder.cs
+++ b/src/Artemis.UI.Linux/Providers/Input/LinuxInputDeviceFinder.cs
@@ -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 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));
}
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI.Linux/Providers/Input/LinuxInputDeviceReader.cs b/src/Artemis.UI.Linux/Providers/Input/LinuxInputDeviceReader.cs
index 81e4bd6c2..827f49510 100644
--- a/src/Artemis.UI.Linux/Providers/Input/LinuxInputDeviceReader.cs
+++ b/src/Artemis.UI.Linux/Providers/Input/LinuxInputDeviceReader.cs
@@ -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
{
diff --git a/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs b/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs
index ea8baa816..65422712d 100644
--- a/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs
+++ b/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs
@@ -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;
}
}