using System.Runtime.InteropServices; namespace RobotNet10.RobotApp.Natives; /// /// Native declarations for Linux evdev (event device) input subsystem. /// Used for low-latency keyboard input reading from /dev/input/event* devices. /// internal static partial class EvdevNative { // Event types public const ushort EV_SYN = 0x00; public const ushort EV_KEY = 0x01; public const ushort EV_REL = 0x02; public const ushort EV_ABS = 0x03; // Key event values public const int KEY_RELEASE = 0; public const int KEY_PRESS = 1; public const int KEY_REPEAT = 2; // Linux key codes (from input-event-codes.h) public const ushort KEY_ESC = 1; public const ushort KEY_MINUS = 12; public const ushort KEY_EQUAL = 13; public const ushort KEY_Q = 16; public const ushort KEY_W = 17; public const ushort KEY_E = 18; public const ushort KEY_A = 30; public const ushort KEY_S = 31; public const ushort KEY_D = 32; public const ushort KEY_Z = 44; public const ushort KEY_C = 46; public const ushort KEY_SPACE = 57; public const ushort KEY_KPMINUS = 74; public const ushort KEY_KPPLUS = 78; // ioctl constants for evdev // EVIOCGNAME(len): Get device name // Calculated as: _IOC(_IOC_READ, 'E', 0x06, len) // where _IOC_READ=2, 'E'=0x45 // Formula: (2<<30) | (0x45<<8) | (0x06) | (256<<16) = 0x80FF4506 public const uint EVIOCGNAME_256 = 0x80FF4506; // File open flags public const int O_RDONLY = 0x0000; public const int O_NONBLOCK = 0x0800; // Error codes public const int EAGAIN = 11; public const int EACCES = 13; /// /// Linux input event structure (24 bytes on 64-bit systems) /// Represents a single input event from evdev /// [StructLayout(LayoutKind.Sequential)] public struct input_event { public long tv_sec; // timestamp seconds public long tv_usec; // timestamp microseconds public ushort type; // event type (EV_KEY, EV_REL, etc.) public ushort code; // event code (KEY_W, KEY_A, etc.) public int value; // event value (0=release, 1=press, 2=repeat) } // File operations for evdev /// /// Open a file and return a file descriptor /// [LibraryImport("libc", SetLastError = true, StringMarshalling = StringMarshalling.Utf8)] public static partial int open(string pathname, int flags); /// /// Close a file descriptor /// [LibraryImport("libc", SetLastError = true)] public static partial int close(int fd); /// /// Read from a file descriptor into input_event buffer /// [LibraryImport("libc", SetLastError = true)] public static partial int read(int fd, ref input_event buf, int count); /// /// ioctl system call for device control /// Used to query device name via EVIOCGNAME /// [LibraryImport("libc", SetLastError = true)] public static partial int ioctl(int fd, uint request, byte[] argp); // Error handling /// /// Get pointer to errno location /// [LibraryImport("libc")] public static partial IntPtr __errno_location(); /// /// Get last error number (errno) /// public static int GetLastError() { IntPtr errnoPtr = __errno_location(); if (errnoPtr == IntPtr.Zero) { return 0; } return Marshal.ReadInt32(errnoPtr); } }