Rob van der Woude's Scripting Pages
Powered by GeSHi

Source code for mause.cs

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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using System.Threading;
  5. using static ConsoleLib.NativeMethods;
  6.  
  7.  
  8. namespace RobvanderWoude
  9. {
  10. 	class Mause
  11. 	{
  12. 		static string progver = "1.06";
  13.  
  14. 		const string defaultprompt = "Press any key or mouse button or wheel to continue . . .";
  15. 		const int defaulttimeout = 0;
  16.  
  17. 		static IntPtr inHandle = IntPtr.Zero;
  18. 		static uint initialmode = 0;
  19. 		static string prompt = defaultprompt;
  20. 		static int timeout = defaulttimeout;
  21. 		static bool flushkeyboardbuffer = true;
  22. 		private static System.Timers.Timer timer;
  23.  
  24.  
  25. 		static void Main( string[] args )
  26. 		{
  27. 			foreach ( string arg in args )
  28. 			{
  29. 				if ( arg == "/?" )
  30. 				{
  31. 					ShowHelp( );
  32. 				}
  33. 				if ( arg.Length > 3 && arg.ToUpper( ).Substring( 0, 3 ) == "/T:" )
  34. 				{
  35. 					if ( timeout != defaulttimeout )
  36. 					{
  37. 						ShowHelp( "Duplicate timeout switch /T" );
  38. 					}
  39. 					try
  40. 					{
  41. 						timeout = Convert.ToInt32( arg.Substring( 3 ) );
  42. 						if ( timeout < 1 || timeout > 3600 )
  43. 						{
  44. 							ShowHelp( "Specified timeout out of 1..3600 seconds range" );
  45. 						}
  46. 					}
  47. 					catch
  48. 					{
  49. 						ShowHelp( "Invalid timeout \"{0}\"", arg );
  50. 					}
  51. 				}
  52. 				else if ( arg.ToUpper( ) == "/N" )
  53. 				{
  54. 					if ( !flushkeyboardbuffer )
  55. 					{
  56. 						ShowHelp( "Duplicate timeout switch /N" );
  57. 					}
  58. 					flushkeyboardbuffer = false;
  59. 				}
  60. 				else
  61. 				{
  62. 					if ( prompt != defaultprompt )
  63. 					{
  64. 						ShowHelp( "Too many command line arguments" );
  65. 					}
  66. 					prompt = arg;
  67. 				}
  68. 			}
  69.  
  70. 			// Flush keyboard buffer unless /N switch is used
  71. 			if ( flushkeyboardbuffer )
  72. 			{
  73. 				FlushKeyboardBuffer( );
  74. 			}
  75.  
  76. 			// Temporarily enable mouse input and disable Quick-Edit mode
  77. 			inHandle = GetStdHandle( STD_INPUT_HANDLE );
  78. 			GetConsoleMode( inHandle, ref initialmode );
  79. 			uint tempmode = initialmode | ENABLE_EXTENDED_FLAGS; // enable
  80. 			tempmode |= ENABLE_MOUSE_INPUT; // enable
  81. 			tempmode &= ~ENABLE_QUICK_EDIT_MODE; // disable
  82. 			tempmode &= ~ENABLE_LINE_INPUT; // disable
  83. 			tempmode &= ~ENABLE_ECHO_INPUT; // disable
  84. 			tempmode &= ~ENABLE_WINDOW_INPUT; // disable
  85. 			SetConsoleMode( inHandle, tempmode );
  86.  
  87. 			// Set event listeners for keyboard and mouse input
  88. 			ConsoleLib.ConsoleListener.MouseEvent += ConsoleListener_MouseEvent;
  89. 			ConsoleLib.ConsoleListener.KeyEvent += ConsoleListener_KeyEvent;
  90. 			ConsoleLib.ConsoleListener.Start( );
  91.  
  92. 			// Start timeout timer if requested
  93. 			if ( timeout > 0 )
  94. 			{
  95. 				timer = new System.Timers.Timer( );
  96. 				timer.Interval = 1000 * timeout;
  97. 				timer.Elapsed += Timer_Elapsed;
  98. 				timer.Start( );
  99. 			}
  100.  
  101. 			// Show the prompt
  102. 			if ( !string.IsNullOrWhiteSpace( prompt ) )
  103. 			{
  104. 				Console.Write( prompt );
  105. 			}
  106.  
  107. 			// Temporarily hide the cursor
  108. 			Console.CursorVisible = false;
  109. 		}
  110.  
  111.  
  112. 		static void FlushKeyboardBuffer( )
  113. 		{
  114. 			// Code to flush keyboard buffer by gandjustas
  115. 			// https://stackoverflow.com/a/3769828
  116. 			bool hidekey = true;
  117. 			while ( Console.KeyAvailable )
  118. 			{
  119. 				Console.ReadKey( hidekey );
  120. 			}
  121. 		}
  122.  
  123.  
  124. 		static void Quit( int rc )
  125. 		{
  126. 			// If a prompt was shown, append a newline
  127. 			if ( !string.IsNullOrWhiteSpace( prompt ) )
  128. 			{
  129. 				Console.WriteLine( );
  130. 			}
  131. 			// Stop the timeout timer, if active
  132. 			if ( timeout > 0 )
  133. 			{
  134. 				timer.Stop( );
  135. 				timer.Dispose( );
  136. 			}
  137. 			// Restore the cursor
  138. 			Console.CursorVisible = true;
  139. 			// Restore the console's initial Quick-Edit mode
  140. 			SetConsoleMode( inHandle, initialmode );
  141. 			// Exit with appropriate return code
  142. 			Environment.Exit( rc );
  143. 		}
  144.  
  145.  
  146. 		private static void ConsoleListener_KeyEvent( KEY_EVENT_RECORD r )
  147. 		{
  148. 			// Keyboard input
  149. 			Quit( 1 );
  150. 		}
  151.  
  152.  
  153. 		private static void ConsoleListener_MouseEvent( MOUSE_EVENT_RECORD r )
  154. 		{
  155. 			if ( r.dwEventFlags != 1 ) // ignore mouse movement events
  156. 			{
  157. 				// Mouse input
  158. 				Quit( 2 );
  159. 			}
  160. 		}
  161.  
  162.  
  163. 		private static void Timer_Elapsed( object sender, System.Timers.ElapsedEventArgs e )
  164. 		{
  165. 			// Timeout elapsed
  166. 			Quit( 3 );
  167. 		}
  168.  
  169.  
  170. 		#region Error handling
  171.  
  172. 		static void ShowHelp( params string[] errmsg )
  173. 		{
  174. 			#region Error Message
  175.  
  176. 			if ( errmsg.Length > 0 )
  177. 			{
  178. 				List<string> errargs = new List<string>( errmsg );
  179. 				errargs.RemoveAt( 0 );
  180. 				Console.Error.WriteLine( );
  181. 				Console.ForegroundColor = ConsoleColor.Red;
  182. 				Console.Error.Write( "ERROR:\t" );
  183. 				Console.ForegroundColor = ConsoleColor.White;
  184. 				Console.Error.WriteLine( errmsg[0], errargs.ToArray( ) );
  185. 				Console.ResetColor( );
  186. 			}
  187.  
  188. 			#endregion Error Message
  189.  
  190.  
  191. 			#region Help Text
  192.  
  193. 			/*
  194. 			Mause.exe,  Version 1.06
  195. 			Mouse enabled pAUSE command
  196.  
  197. 			Usage:    Mause.exe  [ prompt ]  [ /T:seconds ]  [ /N ]
  198.  
  199. 			Where:    prompt      is the prompt to be displayed (default: "Press any key
  200. 			                      or mouse button or wheel to continue . . ."; use "" to
  201. 			                      show no prompt)
  202. 			          /N          do Not flush the keyboard buffer
  203. 			                      (default: flush keyboard buffer when program is started)
  204. 			          /T:seconds  timeout in seconds (1..3600; default: wait forever)
  205.  
  206. 			Notes:    Return code 1 for key, 2 for mouse, 3 for timeout or -1 for errors.
  207. 			          While Mause is running, the console's Quick-Edit mode will be
  208. 			          temporarily disabled; before exiting, the console's initial
  209. 			          Quick-Edit state will be restored.
  210.  
  211. 			Credits:  ConsoleListener class by SWdV on StackOverflow.com
  212. 			          https://stackoverflow.com/a/29971246
  213. 			          Code to flush keyboard buffer by gandjustas on StackOverflow.com
  214. 			          https://stackoverflow.com/a/3769828
  215.  
  216. 			Written by Rob van der Woude
  217. 			https://www.robvanderwoude.com
  218. 			*/
  219.  
  220. 			#endregion Help Text
  221.  
  222.  
  223. 			#region Display Help Text
  224.  
  225. 			Console.Error.WriteLine( );
  226.  
  227. 			Console.Error.WriteLine( "Mause.exe,  Version {0}", progver );
  228.  
  229. 			Console.ForegroundColor = ConsoleColor.White;
  230. 			Console.Error.Write( "M" );
  231. 			Console.ResetColor( );
  232. 			Console.Error.Write( "ouse enabled p" );
  233. 			Console.ForegroundColor = ConsoleColor.White;
  234. 			Console.Error.Write( "AUSE" );
  235. 			Console.ResetColor( );
  236. 			Console.Error.WriteLine( " command" );
  237.  
  238. 			Console.Error.WriteLine( );
  239.  
  240. 			Console.Error.Write( "Usage:    " );
  241. 			Console.ForegroundColor = ConsoleColor.White;
  242. 			Console.Error.WriteLine( "Mause.exe  [ prompt ]  [ /T:timeout ]  [ /N ]" );
  243. 			Console.ResetColor( );
  244.  
  245. 			Console.Error.WriteLine( );
  246.  
  247. 			Console.Error.Write( "Where:    " );
  248. 			Console.ForegroundColor = ConsoleColor.White;
  249. 			Console.Error.Write( "prompt" );
  250. 			Console.ResetColor( );
  251. 			Console.Error.WriteLine( "      is the prompt to be displayed (default: \"Press any key" );
  252.  
  253. 			Console.Error.WriteLine( "                      or mouse button or wheel to continue . . .\"; use \"\" to" );
  254.  
  255. 			Console.Error.WriteLine( "                      show no prompt)" );
  256.  
  257. 			Console.ForegroundColor = ConsoleColor.White;
  258. 			Console.Error.Write( "          /N" );
  259. 			Console.ResetColor( );
  260. 			Console.Error.Write( "          do " );
  261. 			Console.ForegroundColor = ConsoleColor.White;
  262. 			Console.Error.Write( "N" );
  263. 			Console.ResetColor( );
  264. 			Console.Error.WriteLine( "ot flush the keyboard buffer" );
  265.  
  266. 			Console.Error.WriteLine( "                      (default: flush keyboard buffer when program is started)" );
  267.  
  268. 			Console.ForegroundColor = ConsoleColor.White;
  269. 			Console.Error.Write( "          /T:seconds" );
  270. 			Console.ResetColor( );
  271. 			Console.Error.WriteLine( "  timeout in seconds (1..3600; default: wait forever)" );
  272.  
  273. 			Console.Error.WriteLine( );
  274.  
  275. 			Console.Error.WriteLine( "Notes:    Return code 1 for key, 2 for mouse, 3 for timeout or -1 for errors." );
  276.  
  277. 			Console.Error.WriteLine( "          While Mause is running, the console's Quick-Edit mode will be" );
  278.  
  279. 			Console.Error.WriteLine( "          temporarily disabled; before exiting, the console's initial" );
  280.  
  281. 			Console.Error.WriteLine( "          Quick-Edit state will be restored." );
  282.  
  283. 			Console.Error.WriteLine( );
  284.  
  285. 			Console.Error.WriteLine( "Credits:  ConsoleListener class by SWdV on StackOverflow.com" );
  286.  
  287. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  288. 			Console.Error.WriteLine( "          https://stackoverflow.com/a/29971246" );
  289. 			Console.ResetColor( );
  290.  
  291. 			Console.Error.WriteLine( "          Code to flush keyboard buffer by gandjustas on StackOverflow.com" );
  292.  
  293. 			Console.ForegroundColor = ConsoleColor.DarkGray;
  294. 			Console.Error.WriteLine( "          https://stackoverflow.com/a/3769828" );
  295. 			Console.ResetColor( );
  296.  
  297. 			Console.Error.WriteLine( );
  298.  
  299. 			Console.Error.WriteLine( "Written by Rob van der Woude" );
  300.  
  301. 			Console.Error.WriteLine( "https://www.robvanderwoude.com" );
  302.  
  303. 			#endregion Display Help Text
  304.  
  305.  
  306. 			Environment.Exit( -1 );
  307. 		}
  308.  
  309. 		#endregion Error handling
  310. 	}
  311. }
  312.  
  313.  
  314.  
  315. // ConsoleListener class by SWdV on StackOverflow.com
  316. // https://stackoverflow.com/a/29971246
  317. namespace ConsoleLib
  318. {
  319. 	public static class ConsoleListener
  320. 	{
  321. 		public static event ConsoleMouseEvent MouseEvent;
  322.  
  323. 		public static event ConsoleKeyEvent KeyEvent;
  324.  
  325. 		public static event ConsoleWindowBufferSizeEvent WindowBufferSizeEvent;
  326.  
  327. 		private static bool Run = false;
  328.  
  329.  
  330. 		public static void Start( )
  331. 		{
  332. 			if ( !Run )
  333. 			{
  334. 				Run = true;
  335. 				IntPtr handleIn = GetStdHandle( STD_INPUT_HANDLE );
  336. 				new Thread( ( ) =>
  337. 				{
  338. 					while ( true )
  339. 					{
  340. 						uint numRead = 0;
  341. 						INPUT_RECORD[] record = new INPUT_RECORD[1];
  342. 						record[0] = new INPUT_RECORD( );
  343. 						ReadConsoleInput( handleIn, record, 1, ref numRead );
  344. 						if ( Run )
  345. 							switch ( record[0].EventType )
  346. 							{
  347. 								case INPUT_RECORD.MOUSE_EVENT:
  348. 									MouseEvent?.Invoke( record[0].MouseEvent );
  349. 									break;
  350. 								case INPUT_RECORD.KEY_EVENT:
  351. 									KeyEvent?.Invoke( record[0].KeyEvent );
  352. 									break;
  353. 								case INPUT_RECORD.WINDOW_BUFFER_SIZE_EVENT:
  354. 									WindowBufferSizeEvent?.Invoke( record[0].WindowBufferSizeEvent );
  355. 									break;
  356. 							}
  357. 						else
  358. 						{
  359. 							uint numWritten = 0;
  360. 							WriteConsoleInput( handleIn, record, 1, ref numWritten );
  361. 							return;
  362. 						}
  363. 					}
  364. 				} ).Start( );
  365. 			}
  366. 		}
  367.  
  368.  
  369. 		public static void Stop( ) => Run = false;
  370.  
  371.  
  372. 		public delegate void ConsoleMouseEvent( MOUSE_EVENT_RECORD r );
  373.  
  374.  
  375. 		public delegate void ConsoleKeyEvent( KEY_EVENT_RECORD r );
  376.  
  377.  
  378. 		public delegate void ConsoleWindowBufferSizeEvent( WINDOW_BUFFER_SIZE_RECORD r );
  379. 	}
  380.  
  381.  
  382. 	public static class NativeMethods
  383. 	{
  384. 		public struct COORD
  385. 		{
  386. 			public short X;
  387. 			public short Y;
  388.  
  389.  
  390. 			public COORD( short x, short y )
  391. 			{
  392. 				X = x;
  393. 				Y = y;
  394. 			}
  395. 		}
  396.  
  397.  
  398. 		[StructLayout( LayoutKind.Explicit )]
  399. 		public struct INPUT_RECORD
  400. 		{
  401. 			public const ushort KEY_EVENT = 0x0001,
  402. 				MOUSE_EVENT = 0x0002,
  403. 				WINDOW_BUFFER_SIZE_EVENT = 0x0004; //more
  404.  
  405. 			[FieldOffset( 0 )]
  406. 			public ushort EventType;
  407.  
  408. 			[FieldOffset( 4 )]
  409. 			public KEY_EVENT_RECORD KeyEvent;
  410.  
  411. 			[FieldOffset( 4 )]
  412. 			public MOUSE_EVENT_RECORD MouseEvent;
  413.  
  414. 			[FieldOffset( 4 )]
  415. 			public WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
  416. 			/*
  417.             and:
  418.              MENU_EVENT_RECORD MenuEvent;
  419.              FOCUS_EVENT_RECORD FocusEvent;
  420.              */
  421. 		}
  422.  
  423.  
  424. 		public struct MOUSE_EVENT_RECORD
  425. 		{
  426. 			public COORD dwMousePosition;
  427.  
  428. 			public const uint FROM_LEFT_1ST_BUTTON_PRESSED = 0x0001,
  429. 				FROM_LEFT_2ND_BUTTON_PRESSED = 0x0004,
  430. 				FROM_LEFT_3RD_BUTTON_PRESSED = 0x0008,
  431. 				FROM_LEFT_4TH_BUTTON_PRESSED = 0x0010,
  432. 				RIGHTMOST_BUTTON_PRESSED = 0x0002;
  433.  
  434. 			public uint dwButtonState;
  435.  
  436. 			public const int CAPSLOCK_ON = 0x0080,
  437. 				ENHANCED_KEY = 0x0100,
  438. 				LEFT_ALT_PRESSED = 0x0002,
  439. 				LEFT_CTRL_PRESSED = 0x0008,
  440. 				NUMLOCK_ON = 0x0020,
  441. 				RIGHT_ALT_PRESSED = 0x0001,
  442. 				RIGHT_CTRL_PRESSED = 0x0004,
  443. 				SCROLLLOCK_ON = 0x0040,
  444. 				SHIFT_PRESSED = 0x0010;
  445.  
  446. 			public uint dwControlKeyState;
  447.  
  448. 			public const int DOUBLE_CLICK = 0x0002,
  449. 				MOUSE_HWHEELED = 0x0008,
  450. 				MOUSE_MOVED = 0x0001,
  451. 				MOUSE_WHEELED = 0x0004;
  452.  
  453. 			public uint dwEventFlags;
  454. 		}
  455.  
  456. 		[StructLayout( LayoutKind.Explicit, CharSet = CharSet.Unicode )]
  457. 		public struct KEY_EVENT_RECORD
  458. 		{
  459. 			[FieldOffset( 0 )]
  460. 			public bool bKeyDown;
  461.  
  462. 			[FieldOffset( 4 )]
  463. 			public ushort wRepeatCount;
  464.  
  465. 			[FieldOffset( 6 )]
  466. 			public ushort wVirtualKeyCode;
  467.  
  468. 			[FieldOffset( 8 )]
  469. 			public ushort wVirtualScanCode;
  470.  
  471. 			[FieldOffset( 10 )]
  472. 			public char UnicodeChar;
  473.  
  474. 			[FieldOffset( 10 )]
  475. 			public byte AsciiChar;
  476.  
  477. 			public const int CAPSLOCK_ON = 0x0080,
  478. 				ENHANCED_KEY = 0x0100,
  479. 				LEFT_ALT_PRESSED = 0x0002,
  480. 				LEFT_CTRL_PRESSED = 0x0008,
  481. 				NUMLOCK_ON = 0x0020,
  482. 				RIGHT_ALT_PRESSED = 0x0001,
  483. 				RIGHT_CTRL_PRESSED = 0x0004,
  484. 				SCROLLLOCK_ON = 0x0040,
  485. 				SHIFT_PRESSED = 0x0010;
  486.  
  487. 			[FieldOffset( 12 )]
  488. 			public uint dwControlKeyState;
  489. 		}
  490.  
  491. 		public struct WINDOW_BUFFER_SIZE_RECORD
  492. 		{
  493. 			public COORD dwSize;
  494. 		}
  495.  
  496. 		public const uint STD_INPUT_HANDLE = unchecked((uint) -10),
  497. 			STD_OUTPUT_HANDLE = unchecked((uint) -11),
  498. 			STD_ERROR_HANDLE = unchecked((uint) -12);
  499.  
  500. 		[DllImport( "kernel32.dll" )]
  501. 		public static extern IntPtr GetStdHandle( uint nStdHandle );
  502.  
  503. 		public const uint ENABLE_MOUSE_INPUT = 0x0010,
  504. 			ENABLE_QUICK_EDIT_MODE = 0x0040,
  505. 			ENABLE_EXTENDED_FLAGS = 0x0080,
  506. 			ENABLE_ECHO_INPUT = 0x0004,
  507. 			ENABLE_WINDOW_INPUT = 0x0008,
  508. 			ENABLE_INSERT_MODE = 0x0020,
  509. 			ENABLE_LINE_INPUT = 0x0002,
  510. 			ENABLE_PROCESSED_INPUT = 0x0001,
  511. 			ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200;
  512.  
  513. 		[DllImportAttribute( "kernel32.dll" )]
  514. 		public static extern bool GetConsoleMode( IntPtr hConsoleInput, ref uint lpMode );
  515.  
  516. 		[DllImportAttribute( "kernel32.dll" )]
  517. 		public static extern bool SetConsoleMode( IntPtr hConsoleInput, uint dwMode );
  518.  
  519. 		[DllImportAttribute( "kernel32.dll", CharSet = CharSet.Unicode )]
  520. 		public static extern bool ReadConsoleInput( IntPtr hConsoleInput, [Out] INPUT_RECORD[] lpBuffer, uint nLength, ref uint lpNumberOfEventsRead );
  521.  
  522. 		[DllImportAttribute( "kernel32.dll", CharSet = CharSet.Unicode )]
  523. 		public static extern bool WriteConsoleInput( IntPtr hConsoleInput, INPUT_RECORD[] lpBuffer, uint nLength, ref uint lpNumberOfEventsWritten );
  524. 	}
  525. }

page last uploaded: 2021-01-27