Listing Input Devices with C# in Linux

I’m going on a journey to build a remote hub for my home theater using an Arduino and my C# programming skills. Part of that story is I wanted to be able to get input from a wireless USB remote that I purchased on amazon.

I’m still not entirely certain that this is even possible, but one part of the process is being able to list the devices that Linux has connected as input devices.

The first step was finding out that there is a file located at: “/proc/bus/input/devices” which contains a list of devices and details about how to connect to them.

Here is the screen of the output when I run the command: “sudo cat /proc/bus/input/devices”

My response from here is to build out the code to map this data to a c# class so that I can use it in other places. I was able to get a really good breakdown of the construction of the data here based on this stack overflow posting.

To start this, I built out a POCO objects:

public class LinuxDeviceIdentifier
 {
     public string Bus { get; set; }
     public string Vendor { get; set; }
     public string Product { get; set; }
     public string Version { get; set; }
 } 

public class LinuxDevice
 {
     public LinuxDeviceIdentifier Identifier = new();
     public string Name { get; set; }
     public string PhysicalPath { get; set; }
     public string SysFsPath { get; set; }
     public string UniqueIdentificationCode { get; set; }
     public List<string> Handlers = new();
     public List<string> Bitmaps = new();
 }

Now that I have the objects to map to I’m able to build out the functionality to read the file. This is what I came up with:

public class DeviceManager
    {
        public static IEnumerable<LinuxDevice> Get(string path = "/proc/bus/input/devices")
        {
            var devices = new List<LinuxDevice>();

            using var filestream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            using var reader = new StreamReader(filestream);
            
            var linuxDevice = new LinuxDevice();
            while (!reader.EndOfStream)
            {
                var line = reader.ReadLine();

                if (string.IsNullOrWhiteSpace(line))
                {
                    if (!string.IsNullOrWhiteSpace(linuxDevice.Name))
                    {
                        devices.Add(linuxDevice);
                        linuxDevice = new LinuxDevice();    
                    }
                    
                    continue;
                }

                if (line.StartsWith("I"))
                    ApplyIdentifier(line, linuxDevice);
                    
                else if (line.StartsWith("N")) 
                    linuxDevice.Name = line.Substring(9, line.Length - 9 - 1);
                    
                else if (line.StartsWith("P"))
                    linuxDevice.PhysicalPath = line[8..];
                
                else if (line.StartsWith("S")) 
                    linuxDevice.SysFsPath = line[9..];
                
                else if (line.StartsWith("U")) 
                    linuxDevice.UniqueIdentificationCode = line[8..];
                
                else if (line.StartsWith("H")) 
                    linuxDevice.Handlers = line[12..]
                        .Split(" ")
                        .Where(h => !string.IsNullOrWhiteSpace(h))
                        .ToList();
                
                else if (line.StartsWith("B"))
                    linuxDevice.Bitmaps.Add(line[3..]);
            }

            return devices;
        }

        private static void ApplyIdentifier(string line, LinuxDevice linuxDevice)
        {
            var values = line[3..]
                .Split(" ");

            foreach (var v in values)
            {
                var kvp = v.Split("=");

                switch (kvp[0])
                {
                    case "Bus":
                        linuxDevice.Identifier.Bus = kvp[1];
                        break;
                    case "Vendor":
                        linuxDevice.Identifier.Vendor = kvp[1];
                        break;
                    case "Product":
                        linuxDevice.Identifier.Product = kvp[1];
                        break;
                    case "Version":
                        linuxDevice.Identifier.Version = kvp[1];
                        break;
                }
            }
        }
    }

Please Note: In order to run this code you either need to run as Root or run as a user who is in the input group in linux for security reasons.

Thanks for checking this post out. I hope it helped you out!

Leave a Reply

Your email address will not be published. Required fields are marked *