using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; namespace RobvanderWoude { internal class HasKeyboard { static readonly string progver = "1.00"; static int Main( string[] args ) { bool usbkeyboards = true; bool otherkeyboards = true; bool quietmode = false; #region Parse Command Line foreach ( string arg in args ) { switch ( arg.ToUpper( ) ) { case "/?": return ShowHelp( ); case "/O": case "/OTHER": if ( !usbkeyboards ) { return ShowHelp( "Duplicate command line switch /OTHER" ); } usbkeyboards = false; break; case "/Q": case "/QUIET": if ( quietmode ) { return ShowHelp( "Duplicate command line switch /QUIET" ); } quietmode = true; break; case "/U": case "/USB": if ( !otherkeyboards ) { return ShowHelp( "Duplicate command line switch /USB" ); } otherkeyboards = false; break; default: return ShowHelp( "Invalid command line argument \"{0}\"", arg ); } if ( !otherkeyboards && !usbkeyboards ) { return ShowHelp( "Command line switches /USB and /OTHER are mutually exclusive" ); } } #endregion Parse Command Line #region Enumerate and Count Raw Keyboard Devices var rawDeviceEnumerator = new RawInputDeviceEnumerator( ); int count = -1; if ( otherkeyboards && usbkeyboards ) { count = rawDeviceEnumerator.AllKeyboardsCount; if ( !quietmode ) { Console.WriteLine( "Total keyboards count: {0}", count ); } } else if ( usbkeyboards ) { count = rawDeviceEnumerator.UsbKeyboardsCount; if ( !quietmode ) { Console.WriteLine( "USB keyboards count: {0}", count ); } } else if ( otherkeyboards ) { count = rawDeviceEnumerator.OtherKeyboardsCount; if ( !quietmode ) { Console.WriteLine( "Other (non-USB) keyboards count: {0}", count ); } } #endregion Enumerate and Count Raw Keyboard Devices return count; } public static int ShowHelp( params string[] errmsg ) { #region Error Message if ( errmsg.Length > 0 ) { List errargs = new List( errmsg ); errargs.RemoveAt( 0 ); Console.Error.WriteLine( ); Console.ForegroundColor = ConsoleColor.Red; Console.Error.Write( "ERROR:\t" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) ); Console.ResetColor( ); } #endregion Error Message #region Help Text /* HasKeyboard.exe, Version 1.00 Count number of keyboards available at this very moment Usage: HasKeyboard.exe [ /USB | /OTHER ] [ /Q ] Where: /USB count USB keyboards only (default: all keybords) /OTHER count OTHER (non-USB) keyboards only (default: all) /QUIET QUIET mode (no screen output) Notes: By default this program counts ALL keybord types. Switches may be abbreviated to /U, /O and/or /Q. The program's return code equals the number of keyboards of the specified type detected, or -1 in case of (command line) errors. Credits: Based on C# wrapper for GetRawInputDeviceList by Pavel Pachobut https://github.com/PashaPash/RawInput/ Written by Rob van der Woude https://www.robvanderwoude.com */ #endregion Help Text #region Display Help Text Console.Error.WriteLine( ); Console.Error.WriteLine( "HasKeyboard.exe, Version {0}", progver ); Console.Error.WriteLine( "Count number of keyboards available at this very moment" ); Console.Error.WriteLine( ); Console.Error.Write( "Usage: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.WriteLine( "HasKeyboard.exe [ /USB | /OTHER ] [ /Q ]" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.Write( "Where: " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/USB" ); Console.ResetColor( ); Console.Error.Write( " count " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "USB" ); Console.ResetColor( ); Console.Error.WriteLine( " keyboards only (default: all keybords)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /OTHER" ); Console.ResetColor( ); Console.Error.Write( " count " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "OTHER" ); Console.ResetColor( ); Console.Error.WriteLine( " (non-USB) keyboards only (default: all)" ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( " /QUIET QUIET" ); Console.ResetColor( ); Console.Error.WriteLine( " mode (no screen output)" ); Console.Error.WriteLine( ); Console.Error.Write( "Notes: By default this program counts " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "ALL" ); Console.ResetColor( ); Console.Error.WriteLine( " keybord types." ); Console.Error.Write( " Switches may be abbreviated to " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/U" ); Console.ResetColor( ); Console.Error.Write( ", " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/O" ); Console.ResetColor( ); Console.Error.Write( " and/or " ); Console.ForegroundColor = ConsoleColor.White; Console.Error.Write( "/Q" ); Console.ResetColor( ); Console.Error.WriteLine( "." ); Console.Error.WriteLine( " The program's return code equals the number of keyboards of the" ); Console.Error.WriteLine( " specified type detected, or -1 in case of (command line) errors." ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Credits: Based on C# wrapper for GetRawInputDeviceList by Pavel Pachobut" ); Console.ForegroundColor = ConsoleColor.DarkGray; Console.Error.WriteLine( " https://github.com/PashaPash/RawInput/" ); Console.ResetColor( ); Console.Error.WriteLine( ); Console.Error.WriteLine( "Written by Rob van der Woude" ); Console.Error.WriteLine( "https://www.robvanderwoude.com" ); #endregion Display Help Text return -1; } } // The following code is copied from Pavel Pachobut's C# wrapper for // GetRawInputDeviceList: https://github.com/PashaPash/RawInput/ // and modified by Rob van der Woude (added AllKeyboardsCount and // OtherKeyboardsCount properties to RawInputDeviceEnumerator class) public class RawInputDevice { private readonly Win32.RawInputDeviceList _rawInputDeviceList; private readonly string _deviceName; private readonly Win32.DeviceInfo _deviceInfo; public IntPtr DeviceHandle { get { return _rawInputDeviceList.DeviceHandle; } } public Win32.RawInputDeviceType DeviceType { get { return _rawInputDeviceList.DeviceType; } } public string DeviceName { get { return this._deviceName; } } public Win32.DeviceInfo DeviceInfo { get { return this._deviceInfo; } } public RawInputDevice( Win32.RawInputDeviceList rawInputDeviceList ) { this._rawInputDeviceList = rawInputDeviceList; _deviceName = GetDeviceName( this._rawInputDeviceList.DeviceHandle ); _deviceInfo = GetDeviceInfo( this._rawInputDeviceList.DeviceHandle ); } private static IntPtr GetDeviceData( IntPtr deviceHandle, Win32.RawInputDeviceInfoCommand command ) { uint dataSize = 0; var ptrData = IntPtr.Zero; Win32.GetRawInputDeviceInfo( deviceHandle, command, ptrData, ref dataSize ); if ( dataSize == 0 ) { return IntPtr.Zero; } ptrData = Marshal.AllocHGlobal( (int)dataSize ); var result = Win32.GetRawInputDeviceInfo( deviceHandle, command, ptrData, ref dataSize ); if ( result == 0 ) { Marshal.FreeHGlobal( ptrData ); return IntPtr.Zero; } return ptrData; } private static string GetDeviceName( IntPtr deviceHandle ) { var ptrDeviceName = GetDeviceData( deviceHandle, Win32.RawInputDeviceInfoCommand.DeviceName ); if ( ptrDeviceName == IntPtr.Zero ) { return string.Empty; } var deviceName = Marshal.PtrToStringAnsi( ptrDeviceName ); Marshal.FreeHGlobal( ptrDeviceName ); return deviceName; } private static Win32.DeviceInfo GetDeviceInfo( IntPtr deviceHandle ) { var ptrDeviceInfo = GetDeviceData( deviceHandle, Win32.RawInputDeviceInfoCommand.DeviceInfo ); if ( ptrDeviceInfo == IntPtr.Zero ) { return new Win32.DeviceInfo( ); } var deviceInfo = (Win32.DeviceInfo)Marshal.PtrToStructure( ptrDeviceInfo, typeof( Win32.DeviceInfo ) ); Marshal.FreeHGlobal( ptrDeviceInfo ); return deviceInfo; } } public class RawInputDeviceEnumerator { private readonly RawInputDevice[] _devices; public IEnumerable Devices { get { return this._devices; } } public RawInputDeviceEnumerator( ) { uint deviceCount = 0; var deviceSize = (uint)Marshal.SizeOf( typeof( Win32.RawInputDeviceList ) ); // first call retrieves the number of raw input devices var result = Win32.GetRawInputDeviceList( IntPtr.Zero, ref deviceCount, deviceSize ); _devices = new RawInputDevice[deviceCount]; if ( (int)result == -1 || deviceCount == 0 ) { // call failed, or no devices found return; } // allocates memory for an array of Win32.RawInputDeviceList IntPtr ptrDeviceList = Marshal.AllocHGlobal( (int)( deviceSize * deviceCount ) ); result = Win32.GetRawInputDeviceList( ptrDeviceList, ref deviceCount, deviceSize ); if ( (int)result != -1 ) { // enumerates array of Win32.RawInputDeviceList, // and populates array of managed RawInputDevice objects for ( var index = 0; index < deviceCount; index++ ) { var rawInputDeviceList = (Win32.RawInputDeviceList)Marshal.PtrToStructure( new IntPtr( ( ptrDeviceList.ToInt32( ) + ( deviceSize * index ) ) ), typeof( Win32.RawInputDeviceList ) ); _devices[index] = new RawInputDevice( rawInputDeviceList ); } } Marshal.FreeHGlobal( ptrDeviceList ); } public int AllKeyboardsCount { get { return this.Devices.Count( d => d.DeviceType == Win32.RawInputDeviceType.Keyboard ); } } public int OtherKeyboardsCount { get { return this.Devices.Count( d => d.DeviceType == Win32.RawInputDeviceType.Keyboard && !d.DeviceInfo.KeyboardInfo.IsUSBKeboard ); } } public int UsbKeyboardsCount { get { return this.Devices.Count( d => d.DeviceType == Win32.RawInputDeviceType.Keyboard && d.DeviceInfo.KeyboardInfo.IsUSBKeboard ); } } } public static class Win32 { public enum RawInputDeviceType : uint { Mouse = 0, Keyboard = 1, HumanInterfaceDevice = 2 } public enum RawInputDeviceInfoCommand : uint { PreparsedData = 0x20000005, DeviceName = 0x20000007, DeviceInfo = 0x2000000b, } [StructLayout( LayoutKind.Explicit )] public struct DeviceInfo { [FieldOffset( 0 )] public int Size; [FieldOffset( 4 )] public int Type; [FieldOffset( 8 )] public DeviceInfoMouse MouseInfo; [FieldOffset( 8 )] public DeviceInfoKeyboard KeyboardInfo; [FieldOffset( 8 )] public DeviceInfoHID HIDInfo; } public struct DeviceInfoMouse { public uint ID; public uint NumberOfButtons; public uint SampleRate; } public struct DeviceInfoKeyboard { public uint Type; public uint SubType; public uint KeyboardMode; public uint NumberOfFunctionKeys; public uint NumberOfIndicators; public uint NumberOfKeysTotal; public bool IsUSBKeboard { get { return this.Type == 81; // http://msdn.microsoft.com/en-us/library/windows/desktop/ms724336%28v=vs.85%29.aspx } } } public struct DeviceInfoHID { public uint VendorID; public uint ProductID; public uint VersionNumber; public ushort UsagePage; public ushort Usage; } [StructLayout( LayoutKind.Sequential )] public struct RawInputDeviceList { public IntPtr DeviceHandle; public RawInputDeviceType DeviceType; } [DllImport( "User32.dll", SetLastError = true )] public static extern uint GetRawInputDeviceList( IntPtr pRawInputDeviceList, ref uint uiNumDevices, uint cbSize ); [DllImport( "user32.dll", SetLastError = true )] public static extern uint GetRawInputDeviceInfo( IntPtr hDevice, RawInputDeviceInfoCommand uiCommand, IntPtr data, ref uint size ); } }