Rob van der Woude's Scripting Pages
Powered by GeSHi

Source code for haskeyboard.cs

(view source code of haskeyboard.cs as plain text)

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.InteropServices;
  5.  
  6.  
  7. namespace RobvanderWoude
  8. {
  9. 	internal class HasKeyboard
  10. 	{
  11. 		static readonly string progver = "1.00";
  12.  
  13.  
  14. 		static int Main( string[] args )
  15. 		{
  16. 			bool usbkeyboards = true;
  17. 			bool otherkeyboards = true;
  18. 			bool quietmode = false;
  19.  
  20.  
  21. 			#region Parse Command Line
  22.  
  23. 			foreach ( string arg in args )
  24. 			{
  25. 				switch ( arg.ToUpper( ) )
  26. 				{
  27. 					case "/?":
  28. 						return ShowHelp( );
  29. 					case "/O":
  30. 					case "/OTHER":
  31. 						if ( !usbkeyboards )
  32. 						{
  33. 							return ShowHelp( "Duplicate command line switch /OTHER" );
  34. 						}
  35. 						usbkeyboards = false;
  36. 						break;
  37. 					case "/Q":
  38. 					case "/QUIET":
  39. 						if ( quietmode )
  40. 						{
  41. 							return ShowHelp( "Duplicate command line switch /QUIET" );
  42. 						}
  43. 						quietmode = true;
  44. 						break;
  45. 					case "/U":
  46. 					case "/USB":
  47. 						if ( !otherkeyboards )
  48. 						{
  49. 							return ShowHelp( "Duplicate command line switch /USB" );
  50. 						}
  51. 						otherkeyboards = false;
  52. 						break;
  53. 					default:
  54. 						return ShowHelp( "Invalid command line argument \"{0}\"", arg );
  55. 				}
  56. 				if ( !otherkeyboards && !usbkeyboards )
  57. 				{
  58. 					return ShowHelp( "Command line switches /USB and /OTHER are mutually exclusive" );
  59. 				}
  60. 			}
  61.  
  62. 			#endregion Parse Command Line
  63.  
  64.  
  65. 			#region Enumerate and Count Raw Keyboard Devices
  66.  
  67. 			var rawDeviceEnumerator = new RawInputDeviceEnumerator( );
  68. 			int count = -1;
  69. 			if ( otherkeyboards && usbkeyboards )
  70. 			{
  71. 				count = rawDeviceEnumerator.AllKeyboardsCount;
  72. 				if ( !quietmode )
  73. 				{
  74. 					Console.WriteLine( "Total keyboards count: {0}", count );
  75. 				}
  76. 			}
  77. 			else if ( usbkeyboards )
  78. 			{
  79. 				count = rawDeviceEnumerator.UsbKeyboardsCount;
  80. 				if ( !quietmode )
  81. 				{
  82. 					Console.WriteLine( "USB keyboards count: {0}", count );
  83. 				}
  84. 			}
  85. 			else if ( otherkeyboards )
  86. 			{
  87. 				count = rawDeviceEnumerator.OtherKeyboardsCount;
  88. 				if ( !quietmode )
  89. 				{
  90. 					Console.WriteLine( "Other (non-USB) keyboards count: {0}", count );
  91. 				}
  92. 			}
  93.  
  94. 			#endregion Enumerate and Count Raw Keyboard Devices
  95.  
  96.  
  97. 			return count;
  98. 		}
  99.  
  100.  
  101. 		public static int ShowHelp( params string[] errmsg )
  102. 		{
  103. 			#region Error Message
  104.  
  105. 			if ( errmsg.Length > 0 )
  106. 			{
  107. 				List<string> errargs = new List<string>( errmsg );
  108. 				errargs.RemoveAt( 0 );
  109. 				Console.Error.WriteLine( );
  110. 				Console.ForegroundColor = ConsoleColor.Red;
  111. 				Console.Error.Write( "ERROR:\t" );
  112. 				Console.ForegroundColor = ConsoleColor.White;
  113. 				Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) );
  114. 				Console.ResetColor( );
  115. 			}
  116.  
  117. 			#endregion Error Message
  118.  
  119.  
  120. 			#region Help Text
  121.  
  122. 			/*
  123. 			HasKeyboard.exe,  Version 1.00
  124. 			Count number of keyboards available at this very moment
  125.  
  126. 			Usage:   HasKeyboard.exe  [ /USB | /OTHER ]  [ /Q ]
  127.  
  128. 			Where:   /USB          count USB keyboards only (default: all keybords)
  129. 			         /OTHER        count OTHER (non-USB) keyboards only (default: all)
  130. 			         /QUIET        QUIET mode (no screen output)
  131.  
  132. 			Notes:   By default this program counts ALL keybord types.
  133. 			         Switches may be abbreviated to /U, /O and/or /Q.
  134. 			         The program's return code equals the number of keyboards of the
  135. 			         specified type detected, or -1 in case of (command line) errors.
  136.  
  137. 			Credits: Based on C# wrapper for GetRawInputDeviceList by Pavel Pachobut
  138. 			         https://github.com/PashaPash/RawInput/
  139.  
  140. 			Written by Rob van der Woude
  141. 			https://www.robvanderwoude.com
  142. 			*/
  143.  
  144. 			#endregion Help Text
  145.  
  146.  
  147. 			#region Display Help Text
  148.  
  149. 			Console.Error.WriteLine( );
  150.  
  151. 			Console.Error.WriteLine( "HasKeyboard.exe,  Version {0}", progver );
  152.  
  153. 			Console.Error.WriteLine( "Count number of keyboards available at this very moment" );
  154.  
  155. 			Console.Error.WriteLine( );
  156.  
  157. 			Console.Error.Write( "Usage:   " );
  158. 			Console.ForegroundColor = ConsoleColor.White;
  159. 			Console.Error.WriteLine( "HasKeyboard.exe  [ /USB | /OTHER ]  [ /Q ]" );
  160. 			Console.ResetColor( );
  161.  
  162. 			Console.Error.WriteLine( );
  163.  
  164. 			Console.Error.Write( "Where:   " );
  165. 			Console.ForegroundColor = ConsoleColor.White;
  166. 			Console.Error.Write( "/USB" );
  167. 			Console.ResetColor( );
  168. 			Console.Error.Write( "          count " );
  169. 			Console.ForegroundColor = ConsoleColor.White;
  170. 			Console.Error.Write( "USB" );
  171. 			Console.ResetColor( );
  172. 			Console.Error.WriteLine( " keyboards only (default: all keybords)" );
  173.  
  174. 			Console.ForegroundColor = ConsoleColor.White;
  175. 			Console.Error.Write( "         /OTHER" );
  176. 			Console.ResetColor( );
  177. 			Console.Error.Write( "        count " );
  178. 			Console.ForegroundColor = ConsoleColor.White;
  179. 			Console.Error.Write( "OTHER" );
  180. 			Console.ResetColor( );
  181. 			Console.Error.WriteLine( " (non-USB) keyboards only (default: all)" );
  182.  
  183. 			Console.ForegroundColor = ConsoleColor.White;
  184. 			Console.Error.Write( "         /QUIET        QUIET" );
  185. 			Console.ResetColor( );
  186. 			Console.Error.WriteLine( " mode (no screen output)" );
  187.  
  188. 			Console.Error.WriteLine( );
  189.  
  190. 			Console.Error.Write( "Notes:   By default this program counts " );
  191. 			Console.ForegroundColor = ConsoleColor.White;
  192. 			Console.Error.Write( "ALL" );
  193. 			Console.ResetColor( );
  194. 			Console.Error.WriteLine( " keybord types." );
  195.  
  196. 			Console.Error.Write( "         Switches may be abbreviated to " );
  197. 			Console.ForegroundColor = ConsoleColor.White;
  198. 			Console.Error.Write( "/U" );
  199. 			Console.ResetColor( );
  200. 			Console.Error.Write( ", " );
  201. 			Console.ForegroundColor = ConsoleColor.White;
  202. 			Console.Error.Write( "/O" );
  203. 			Console.ResetColor( );
  204. 			Console.Error.Write( " and/or " );
  205. 			Console.ForegroundColor = ConsoleColor.White;
  206. 			Console.Error.Write( "/Q" );
  207. 			Console.ResetColor( );
  208. 			Console.Error.WriteLine( "." );
  209.  
  210. 			Console.Error.WriteLine( "         The program's return code equals the number of keyboards of the" );
  211.  
  212. 			Console.Error.WriteLine( "         specified type detected, or -1 in case of (command line) errors." );
  213.  
  214. 			Console.Error.WriteLine( );
  215.  
  216. 			Console.Error.WriteLine( "Credits: Based on C# wrapper for GetRawInputDeviceList by Pavel Pachobut" );
  217.  
  218. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  219. 			Console.Error.WriteLine( "         https://github.com/PashaPash/RawInput/" );
  220. 			Console.ResetColor( );
  221.  
  222. 			Console.Error.WriteLine( );
  223.  
  224. 			Console.Error.WriteLine( "Written by Rob van der Woude" );
  225.  
  226. 			Console.Error.WriteLine( "https://www.robvanderwoude.com" );
  227.  
  228. 			#endregion Display Help Text
  229.  
  230.  
  231. 			return -1;
  232. 		}
  233. 	}
  234.  
  235.  
  236. 	// The following code is copied from Pavel Pachobut's C# wrapper for
  237. 	// GetRawInputDeviceList: https://github.com/PashaPash/RawInput/
  238. 	// and modified by Rob van der Woude (added AllKeyboardsCount and
  239. 	// OtherKeyboardsCount properties to RawInputDeviceEnumerator class)
  240. 	public class RawInputDevice
  241. 	{
  242. 		private readonly Win32.RawInputDeviceList _rawInputDeviceList;
  243. 		private readonly string _deviceName;
  244. 		private readonly Win32.DeviceInfo _deviceInfo;
  245.  
  246. 		public IntPtr DeviceHandle
  247. 		{
  248. 			get
  249. 			{
  250. 				return _rawInputDeviceList.DeviceHandle;
  251. 			}
  252. 		}
  253.  
  254. 		public Win32.RawInputDeviceType DeviceType
  255. 		{
  256. 			get
  257. 			{
  258. 				return _rawInputDeviceList.DeviceType;
  259. 			}
  260. 		}
  261.  
  262. 		public string DeviceName
  263. 		{
  264. 			get
  265. 			{
  266. 				return this._deviceName;
  267. 			}
  268. 		}
  269.  
  270. 		public Win32.DeviceInfo DeviceInfo
  271. 		{
  272. 			get
  273. 			{
  274. 				return this._deviceInfo;
  275. 			}
  276. 		}
  277.  
  278. 		public RawInputDevice( Win32.RawInputDeviceList rawInputDeviceList )
  279. 		{
  280. 			this._rawInputDeviceList = rawInputDeviceList;
  281.  
  282. 			_deviceName = GetDeviceName( this._rawInputDeviceList.DeviceHandle );
  283.  
  284. 			_deviceInfo = GetDeviceInfo( this._rawInputDeviceList.DeviceHandle );
  285. 		}
  286.  
  287. 		private static IntPtr GetDeviceData( IntPtr deviceHandle, Win32.RawInputDeviceInfoCommand command )
  288. 		{
  289. 			uint dataSize = 0;
  290. 			var ptrData = IntPtr.Zero;
  291.  
  292. 			Win32.GetRawInputDeviceInfo( deviceHandle, command, ptrData, ref dataSize );
  293.  
  294. 			if ( dataSize == 0 )
  295. 			{
  296. 				return IntPtr.Zero;
  297. 			}
  298.  
  299. 			ptrData = Marshal.AllocHGlobal( (int)dataSize );
  300.  
  301. 			var result = Win32.GetRawInputDeviceInfo( deviceHandle, command, ptrData, ref dataSize );
  302.  
  303. 			if ( result == 0 )
  304. 			{
  305. 				Marshal.FreeHGlobal( ptrData );
  306. 				return IntPtr.Zero;
  307. 			}
  308.  
  309. 			return ptrData;
  310. 		}
  311.  
  312. 		private static string GetDeviceName( IntPtr deviceHandle )
  313. 		{
  314. 			var ptrDeviceName = GetDeviceData( deviceHandle, Win32.RawInputDeviceInfoCommand.DeviceName );
  315.  
  316. 			if ( ptrDeviceName == IntPtr.Zero )
  317. 			{
  318. 				return string.Empty;
  319. 			}
  320.  
  321. 			var deviceName = Marshal.PtrToStringAnsi( ptrDeviceName );
  322. 			Marshal.FreeHGlobal( ptrDeviceName );
  323. 			return deviceName;
  324. 		}
  325.  
  326. 		private static Win32.DeviceInfo GetDeviceInfo( IntPtr deviceHandle )
  327. 		{
  328. 			var ptrDeviceInfo = GetDeviceData( deviceHandle, Win32.RawInputDeviceInfoCommand.DeviceInfo );
  329.  
  330. 			if ( ptrDeviceInfo == IntPtr.Zero )
  331. 			{
  332. 				return new Win32.DeviceInfo( );
  333. 			}
  334.  
  335. 			var deviceInfo = (Win32.DeviceInfo)Marshal.PtrToStructure( ptrDeviceInfo, typeof( Win32.DeviceInfo ) );
  336.  
  337. 			Marshal.FreeHGlobal( ptrDeviceInfo );
  338. 			return deviceInfo;
  339. 		}
  340. 	}
  341.  
  342.  
  343. 	public class RawInputDeviceEnumerator
  344. 	{
  345. 		private readonly RawInputDevice[] _devices;
  346.  
  347. 		public IEnumerable<RawInputDevice> Devices
  348. 		{
  349. 			get
  350. 			{
  351. 				return this._devices;
  352. 			}
  353. 		}
  354.  
  355. 		public RawInputDeviceEnumerator( )
  356. 		{
  357. 			uint deviceCount = 0;
  358. 			var deviceSize = (uint)Marshal.SizeOf( typeof( Win32.RawInputDeviceList ) );
  359.  
  360. 			// first call retrieves the number of raw input devices
  361. 			var result = Win32.GetRawInputDeviceList( IntPtr.Zero, ref deviceCount, deviceSize );
  362.  
  363. 			_devices = new RawInputDevice[deviceCount];
  364.  
  365. 			if ( (int)result == -1 || deviceCount == 0 )
  366. 			{
  367. 				// call failed, or no devices found
  368. 				return;
  369. 			}
  370.  
  371. 			// allocates memory for an array of Win32.RawInputDeviceList
  372. 			IntPtr ptrDeviceList = Marshal.AllocHGlobal( (int)( deviceSize * deviceCount ) );
  373.  
  374. 			result = Win32.GetRawInputDeviceList( ptrDeviceList, ref deviceCount, deviceSize );
  375.  
  376. 			if ( (int)result != -1 )
  377. 			{
  378. 				// enumerates array of Win32.RawInputDeviceList,
  379. 				// and populates array of managed RawInputDevice objects
  380. 				for ( var index = 0; index < deviceCount; index++ )
  381. 				{
  382. 					var rawInputDeviceList = (Win32.RawInputDeviceList)Marshal.PtrToStructure( new IntPtr( ( ptrDeviceList.ToInt32( ) + ( deviceSize * index ) ) ), typeof( Win32.RawInputDeviceList ) );
  383.  
  384. 					_devices[index] = new RawInputDevice( rawInputDeviceList );
  385. 				}
  386. 			}
  387.  
  388. 			Marshal.FreeHGlobal( ptrDeviceList );
  389. 		}
  390.  
  391.  
  392. 		public int AllKeyboardsCount
  393. 		{
  394. 			get
  395. 			{
  396. 				return this.Devices.Count( d => d.DeviceType == Win32.RawInputDeviceType.Keyboard );
  397. 			}
  398. 		}
  399.  
  400.  
  401. 		public int OtherKeyboardsCount
  402. 		{
  403. 			get
  404. 			{
  405. 				return this.Devices.Count( d => d.DeviceType == Win32.RawInputDeviceType.Keyboard && !d.DeviceInfo.KeyboardInfo.IsUSBKeboard );
  406. 			}
  407. 		}
  408.  
  409.  
  410. 		public int UsbKeyboardsCount
  411. 		{
  412. 			get
  413. 			{
  414. 				return this.Devices.Count( d => d.DeviceType == Win32.RawInputDeviceType.Keyboard && d.DeviceInfo.KeyboardInfo.IsUSBKeboard );
  415. 			}
  416. 		}
  417. 	}
  418.  
  419.  
  420. 	public static class Win32
  421. 	{
  422. 		public enum RawInputDeviceType : uint
  423. 		{
  424. 			Mouse = 0,
  425. 			Keyboard = 1,
  426. 			HumanInterfaceDevice = 2
  427. 		}
  428.  
  429. 		public enum RawInputDeviceInfoCommand : uint
  430. 		{
  431. 			PreparsedData = 0x20000005,
  432. 			DeviceName = 0x20000007,
  433. 			DeviceInfo = 0x2000000b,
  434. 		}
  435.  
  436. 		[StructLayout( LayoutKind.Explicit )]
  437. 		public struct DeviceInfo
  438. 		{
  439. 			[FieldOffset( 0 )]
  440. 			public int Size;
  441. 			[FieldOffset( 4 )]
  442. 			public int Type;
  443. 			[FieldOffset( 8 )]
  444. 			public DeviceInfoMouse MouseInfo;
  445. 			[FieldOffset( 8 )]
  446. 			public DeviceInfoKeyboard KeyboardInfo;
  447. 			[FieldOffset( 8 )]
  448. 			public DeviceInfoHID HIDInfo;
  449. 		}
  450.  
  451. 		public struct DeviceInfoMouse
  452. 		{
  453. 			public uint ID;
  454. 			public uint NumberOfButtons;
  455. 			public uint SampleRate;
  456. 		}
  457.  
  458. 		public struct DeviceInfoKeyboard
  459. 		{
  460. 			public uint Type;
  461. 			public uint SubType;
  462. 			public uint KeyboardMode;
  463. 			public uint NumberOfFunctionKeys;
  464. 			public uint NumberOfIndicators;
  465. 			public uint NumberOfKeysTotal;
  466. 			public bool IsUSBKeboard
  467. 			{
  468. 				get
  469. 				{
  470. 					return this.Type == 81; // http://msdn.microsoft.com/en-us/library/windows/desktop/ms724336%28v=vs.85%29.aspx
  471. 				}
  472. 			}
  473. 		}
  474.  
  475. 		public struct DeviceInfoHID
  476. 		{
  477. 			public uint VendorID;
  478. 			public uint ProductID;
  479. 			public uint VersionNumber;
  480. 			public ushort UsagePage;
  481. 			public ushort Usage;
  482. 		}
  483.  
  484. 		[StructLayout( LayoutKind.Sequential )]
  485. 		public struct RawInputDeviceList
  486. 		{
  487. 			public IntPtr DeviceHandle;
  488. 			public RawInputDeviceType DeviceType;
  489. 		}
  490.  
  491. 		[DllImport( "User32.dll", SetLastError = true )]
  492. 		public static extern uint GetRawInputDeviceList( IntPtr pRawInputDeviceList, ref uint uiNumDevices, uint cbSize );
  493.  
  494. 		[DllImport( "user32.dll", SetLastError = true )]
  495. 		public static extern uint GetRawInputDeviceInfo( IntPtr hDevice, RawInputDeviceInfoCommand uiCommand, IntPtr data, ref uint size );
  496. 	}
  497. }

page last modified: 2024-04-16; loaded in 0.0275 seconds