Visual Basic Console Application Keyboard Hook

Hello, I'm looking for an example on how to implement a keyboard hook to capture certain keys in my CONSOLE app, not forms,

For example: F1 to Help or F10 to exit the app from anywhere.

I found C# examples and Form examples. Can anyone help?

Thanks

Alex
Alexandre FernandesAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

it_saigeDeveloperCommented:
Here is an implementation I have used before (Don't forget to include the reference to System.Windows.Forms):
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Windows.Forms

Module Module1
	Friend fProcDelegate As NativeMethods.LowLevelKeyboardProcDelegate
	Friend fKeyboardHook As IntPtr

	Sub Main()
		Hook()
		Application.Run()
		Unhook()
	End Sub

	Private Sub Hook()
		If fProcDelegate IsNot Nothing Then
			Throw New InvalidOperationException("Cannot hook more than once")
		End If

		Using current As Process = Process.GetCurrentProcess()
			Using [module] As ProcessModule = current.MainModule
				fProcDelegate = AddressOf NativeMethods.LowLevelKeyboardProc
				fKeyboardHook = NativeMethods.SetWindowsHookEx(NativeMethods.WH_KEYBOARD_LL, fProcDelegate, NativeMethods.GetModuleHandle([module].ModuleName), 0)
			End Using
		End Using

		If fKeyboardHook = IntPtr.Zero Then
			Throw New Win32Exception()
		End If
	End Sub

	Private Sub Unhook()
		If fProcDelegate Is Nothing Then
			Return
		End If

		Dim ok As Boolean = NativeMethods.UnhookWindowsHookEx(fKeyboardHook)
		If Not ok Then
			Throw New Win32Exception()
		End If

		fProcDelegate = Nothing
	End Sub
End Module

Class NativeMethods
	Public Const WH_KEYBOARD_LL As Integer = 13

	''' <summary>Determines whether a key is up or down at the time the function is called, and whether the key was pressed after a previous call to GetAsyncKeyState.</summary>
	''' <param name="vKey">The virtual-key code. For more information, see Virtual Key Codes.</param>
	''' <returns>If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState. However, you should not rely on this last behavior; for more information, see the Remarks. The return value is zero for the following cases:<para> The current desktop is not the active desktop.</para><para>The foreground thread belongs to another process and the desktop does not allow the hook or the journal record.</para></returns>
	Public Declare Auto Function GetAsyncKeyState Lib "user32" (vKey As VirtualKeys) As Short

	''' <summary>Retrieves a module handle for the specified module. The module must have been loaded by the calling process.</summary>
	''' <param name="lpModuleName">The name of the loaded module (either a .dll or .exe file). If the file name extension is omitted, the default library extension .dll is appended. The file name string can include a trailing point character (.) to indicate that the module name has no extension. The string does not have to specify a path. When specifying a path, be sure to use backslashes (\), not forward slashes (/). The name is compared (case independently) to the names of modules currently mapped into the address space of the calling process. If this parameter is NULL, GetModuleHandle returns a handle to the file used to create the calling process (.exe file).</param>
	''' <returns>If the function succeeds, the return value is a handle to the specified module. If the function fails, the return value is NULL. To get extended error information, call GetLastError.</returns>
	''' <remarks>The GetModuleHandle function does not retrieve handles for modules that were loaded using the LOAD_LIBRARY_AS_DATAFILE flag.</remarks>
	<DllImport("kernel32", CharSet:=CharSet.Auto, SetLastError:=True)> _
	Public Shared Function GetModuleHandle(lpModuleName As String) As IntPtr
	End Function

	''' <summary>Installs an application-defined hook procedure into a hook chain.</summary>
	''' <param name="idHook">The type of hook procedure to be installed.</param>
	''' <param name="lpfn">A pointer to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a thread created by a different process, the lpfn parameter must point to a hook procedure in a DLL. Otherwise, lpfn can point to a hook procedure in the code associated with the current process.</param>
	''' <param name="hMod">A handle to the DLL containing the hook procedure pointed to by the lpfn parameter. The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.</param>
	''' <param name="dwThreadId">The identifier of the thread with which the hook procedure is to be associated. For desktop apps, if this parameter is zero, the hook procedure is associated with all existing threads running in the same desktop as the calling thread.</param>
	''' <returns>If the function succeeds, the return value is the handle to the hook procedure. If the function fails, the return value is NULL. To get extended error information, call GetLastError.</returns>
	''' <remarks>You would install a hook procedure to monitor the system for certain types of events. These events are associated either with a specific thread or with all threads in the same desktop as the calling thread.</remarks>
	<DllImport("user32", EntryPoint:="SetWindowsHookEx", SetLastError:=True)> _
	Public Shared Function SetWindowsHookEx(idHook As Integer, lpfn As LowLevelKeyboardProcDelegate, hMod As IntPtr, dwThreadId As UInteger) As IntPtr
	End Function

	''' <summary>Removes a hook procedure installed in a hook chain by the SetWindowsHookEx function.</summary>
	''' <param name="hHook">A handle to the hook to be removed. This parameter is a hook handle obtained by a previous call to SetWindowsHookEx.</param>
	''' <returns>If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError.</returns>
	<DllImport("user32", EntryPoint:="UnhookWindowsHookEx", SetLastError:=True)> _
	Public Shared Function UnhookWindowsHookEx(hHook As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
	End Function

	''' <summary>Passes the hook information to the next hook procedure in the current hook chain. A hook procedure can call this function either before or after processing the hook information.</summary>
	''' <param name="hHook">This parameter is ignored.</param>
	''' <param name="nCode">The hook code passed to the current hook procedure. The next hook procedure uses this code to determine how to process the hook information.</param>
	''' <param name="wParam">The wParam value passed to the current hook procedure. The meaning of this parameter depends on the type of hook associated with the current hook chain.</param>
	''' <param name="lParam">The lParam value passed to the current hook procedure. The meaning of this parameter depends on the type of hook associated with the current hook chain.</param>
	''' <returns>This value is returned by the next hook procedure in the chain. The current hook procedure must also return this value. The meaning of the return value depends on the hook type. For more information, see the descriptions of the individual hook procedures.</returns>
	<DllImport("user32", EntryPoint:="CallNextHookEx", SetLastError:=True)> _
	Public Shared Function CallNextHookEx(hHook As IntPtr, nCode As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr
	End Function

	''' <summary>Application-defined callback function used with the SetWindowsHookEx function. The system calls this function every time a new keyboard input event is about to be posted into a thread input queue. The keyboard input can come from the local keyboard driver or from calls to the keybd_event function. If the input comes from a call to keybd_event, the input was "injected".</summary>
	''' <param name="nCode">A code the hook procedure uses to determine how to process the message. If nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.</param>
	''' <param name="wParam">The identifier of the keyboard message. This parameter can be one of the following messages: WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP.</param>
	''' <param name="lParam">A pointer to a KBDLLHOOKSTRUCT structure.</param>
	''' <returns>If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. If nCode is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_KEYBOARD_LL hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the rest of the hook chain or the target window procedure.</returns>
	Public Shared Function LowLevelKeyboardProc(nCode As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr
		Dim blnEat As Boolean = False

		Try
			Dim [structure] As LowLevelKeyboardHookStructure = CType(Marshal.PtrToStructure(lParam, GetType(LowLevelKeyboardHookStructure)), LowLevelKeyboardHookStructure)
			'Select Case DirectCast(wParam, Integer)
			'	Case 256, 257, 260, 261
			'		'' alt+tab, alt+esc, ctrl+esc, windows key,
			'		blnEat = (([structure].vkCode = VirtualKeys.Tab) AndAlso ([structure].flags = LowLevelKeyboardHookFlags.AltPressed)) _
			'		 Or (([structure].vkCode = VirtualKeys.Escape) AndAlso ([structure].flags = LowLevelKeyboardHookFlags.AltPressed)) _
			'		 Or (([structure].vkCode = VirtualKeys.Escape) AndAlso (Convert.ToBoolean(GetAsyncKeyState(VirtualKeys.Control)))) _
			'		 Or (([structure].vkCode = VirtualKeys.LeftWindows) AndAlso ([structure].flags = LowLevelKeyboardHookFlags.Extended)) _
			'		 Or (([structure].vkCode = VirtualKeys.RightWindows) AndAlso ([structure].flags = LowLevelKeyboardHookFlags.Extended))
			'		Exit Select
			'	Case Else
			'		Exit Select
			'End Select
			Console.WriteLine("KeyCode = {0}; KeyFlag = {1}; Message = {2}", [structure].vkCode, [structure].flags, CType(wParam, LowLevelKeyboardMessageType))
			'MessageBox.Show(ex.Message);
			'Squelched
		Catch generatedExceptionName As Exception
		End Try

		'if (blnEat == true)
		'     return new IntPtr(1);
		'else
		'     return CallNextHookEx((IntPtr)0, nCode, wParam, lParam);
		Return CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam)
	End Function

	''' <summary>Structure that contains information about a low-level keyboard input event</summary>
	<StructLayout(LayoutKind.Sequential)> _
	Public Structure LowLevelKeyboardHookStructure
		''' <summary>The virtual key code</summary>
		<MarshalAs(UnmanagedType.U4)> _
		Public vkCode As VirtualKeys
		''' <summary>The hardware scan code for the key</summary>
		<MarshalAs(UnmanagedType.U4)> _
		Public scanCode As UInteger
		''' <summary>The extended-key flags, event-injected flags, context code and transition-state flag.</summary>
		<MarshalAs(UnmanagedType.U4)> _
		Public flags As LowLevelKeyboardHookFlags
		''' <summary>The time stamp for this message.</summary>
		<MarshalAs(UnmanagedType.U4)> _
		Public time As UInteger
		''' <summary>The additional information field</summary>
		Public dwExtraInfo As UIntPtr
	End Structure

	''' <summary>Enum that contains the low-level keyboard flags</summary>
	<Flags()> _
	Public Enum LowLevelKeyboardHookFlags As UInteger
		''' <summary>No flags set</summary>
		None = &H0
		''' <summary>The extended-key flag</summary>
		Extended = &H1
		''' <summary>The event-injected flag</summary>
		Injected = &H10
		''' <summary>The context key flag</summary>
		AltPressed = &H20
		''' <summary>The transition-state flag</summary>
		Released = &H80
	End Enum

	''' <summary>Enum that contains the low-level keyboard message types</summary>
	Public Enum LowLevelKeyboardMessageType As UInteger
		''' <summary>The keydown message</summary>
		''' <remarks>Posted to the window with the keyboard focus when a nonsystem key is pressed. A nonsystem key is a key that is pressed when the ALT key is not pressed.</remarks>
		KeyPressed = &H100
		''' <summary>The keyup message</summary>
		''' <remarks>Posted to the window with the keyboard focus when a nonsystem key is released. A nonsystem key is a key that is pressed when the ALT key is not pressed, or a keyboard key that is pressed when a window has the keyboard focus.</remarks>
		KeyReleased = &H101
		''' <summary>The syskeydown message</summary>
		''' <remarks>Posted to the window with the keyboard focus when the user presses the F10 key (which activates the menu bar) or holds down the ALT key and then presses another key. It also occurs when no window currently has the keyboard focus; in this case, the WM_SYSKEYDOWN message is sent to the active window. The window that receives the message can distinguish between these two contexts by checking the context code in the lParam parameter.</remarks>
		SystemKeyPressed = &H104
		''' <summary>The syskeyup message</summary>
		''' <remarks>Posted to the window with the keyboard focus when the user releases a key that was pressed while the ALT key was held down. It also occurs when no window currently has the keyboard focus; in this case, the WM_SYSKEYUP message is sent to the active window. The window that receives the message can distinguish between these two contexts by checking the context code in the lParam parameter.</remarks>
		SystemKeyReleased = &H105
	End Enum

	''' <summary>
	''' Enumeration for virtual keys.
	''' </summary>
	Public Enum VirtualKeys As UInteger
		''' <summary></summary>
		LeftButton = &H1
		''' <summary></summary>
		RightButton = &H2
		''' <summary></summary>
		Cancel = &H3
		''' <summary></summary>
		MiddleButton = &H4
		''' <summary></summary>
		ExtraButton1 = &H5
		''' <summary></summary>
		ExtraButton2 = &H6
		''' <summary></summary>
		Back = &H8
		''' <summary></summary>
		Tab = &H9
		''' <summary></summary>
		Clear = &HC
		''' <summary></summary>
		[Return] = &HD
		''' <summary></summary>
		Shift = &H10
		''' <summary></summary>
		Control = &H11
		''' <summary></summary>
		Menu = &H12
		''' <summary></summary>
		Pause = &H13
		''' <summary></summary>
		CapsLock = &H14
		''' <summary></summary>
		Kana = &H15
		''' <summary></summary>
		Hangeul = &H15
		''' <summary></summary>
		Hangul = &H15
		''' <summary></summary>
		Junja = &H17
		''' <summary></summary>
		Final = &H18
		''' <summary></summary>
		Hanja = &H19
		''' <summary></summary>
		Kanji = &H19
		''' <summary></summary>
		Escape = &H1B
		''' <summary></summary>
		Convert = &H1C
		''' <summary></summary>
		NonConvert = &H1D
		''' <summary></summary>
		Accept = &H1E
		''' <summary></summary>
		ModeChange = &H1F
		''' <summary></summary>
		Space = &H20
		''' <summary></summary>
		Prior = &H21
		''' <summary></summary>
		[Next] = &H22
		''' <summary></summary>
		[End] = &H23
		''' <summary></summary>
		Home = &H24
		''' <summary></summary>
		Left = &H25
		''' <summary></summary>
		Up = &H26
		''' <summary></summary>
		Right = &H27
		''' <summary></summary>
		Down = &H28
		''' <summary></summary>
		[Select] = &H29
		''' <summary></summary>
		Print = &H2A
		''' <summary></summary>
		Execute = &H2B
		''' <summary></summary>
		Snapshot = &H2C
		''' <summary></summary>
		Insert = &H2D
		''' <summary></summary>
		Delete = &H2E
		''' <summary></summary>
		Help = &H2F
		''' <summary></summary>
		N0 = &H30
		''' <summary></summary>
		N1 = &H31
		''' <summary></summary>
		N2 = &H32
		''' <summary></summary>
		N3 = &H33
		''' <summary></summary>
		N4 = &H34
		''' <summary></summary>
		N5 = &H35
		''' <summary></summary>
		N6 = &H36
		''' <summary></summary>
		N7 = &H37
		''' <summary></summary>
		N8 = &H38
		''' <summary></summary>
		N9 = &H39
		''' <summary></summary>
		A = &H41
		''' <summary></summary>
		B = &H42
		''' <summary></summary>
		C = &H43
		''' <summary></summary>
		D = &H44
		''' <summary></summary>
		E = &H45
		''' <summary></summary>
		F = &H46
		''' <summary></summary>
		G = &H47
		''' <summary></summary>
		H = &H48
		''' <summary></summary>
		I = &H49
		''' <summary></summary>
		J = &H4A
		''' <summary></summary>
		K = &H4B
		''' <summary></summary>
		L = &H4C
		''' <summary></summary>
		M = &H4D
		''' <summary></summary>
		N = &H4E
		''' <summary></summary>
		O = &H4F
		''' <summary></summary>
		P = &H50
		''' <summary></summary>
		Q = &H51
		''' <summary></summary>
		R = &H52
		''' <summary></summary>
		S = &H53
		''' <summary></summary>
		T = &H54
		''' <summary></summary>
		U = &H55
		''' <summary></summary>
		V = &H56
		''' <summary></summary>
		W = &H57
		''' <summary></summary>
		X = &H58
		''' <summary></summary>
		Y = &H59
		''' <summary></summary>
		Z = &H5A
		''' <summary></summary>
		LeftWindows = &H5B
		''' <summary></summary>
		RightWindows = &H5C
		''' <summary></summary>
		Application = &H5D
		''' <summary></summary>
		Sleep = &H5F
		''' <summary></summary>
		Numpad0 = &H60
		''' <summary></summary>
		Numpad1 = &H61
		''' <summary></summary>
		Numpad2 = &H62
		''' <summary></summary>
		Numpad3 = &H63
		''' <summary></summary>
		Numpad4 = &H64
		''' <summary></summary>
		Numpad5 = &H65
		''' <summary></summary>
		Numpad6 = &H66
		''' <summary></summary>
		Numpad7 = &H67
		''' <summary></summary>
		Numpad8 = &H68
		''' <summary></summary>
		Numpad9 = &H69
		''' <summary></summary>
		Multiply = &H6A
		''' <summary></summary>
		Add = &H6B
		''' <summary></summary>
		Separator = &H6C
		''' <summary></summary>
		Subtract = &H6D
		''' <summary></summary>
		[Decimal] = &H6E
		''' <summary></summary>
		Divide = &H6F
		''' <summary></summary>
		F1 = &H70
		''' <summary></summary>
		F2 = &H71
		''' <summary></summary>
		F3 = &H72
		''' <summary></summary>
		F4 = &H73
		''' <summary></summary>
		F5 = &H74
		''' <summary></summary>
		F6 = &H75
		''' <summary></summary>
		F7 = &H76
		''' <summary></summary>
		F8 = &H77
		''' <summary></summary>
		F9 = &H78
		''' <summary></summary>
		F10 = &H79
		''' <summary></summary>
		F11 = &H7A
		''' <summary></summary>
		F12 = &H7B
		''' <summary></summary>
		F13 = &H7C
		''' <summary></summary>
		F14 = &H7D
		''' <summary></summary>
		F15 = &H7E
		''' <summary></summary>
		F16 = &H7F
		''' <summary></summary>
		F17 = &H80
		''' <summary></summary>
		F18 = &H81
		''' <summary></summary>
		F19 = &H82
		''' <summary></summary>
		F20 = &H83
		''' <summary></summary>
		F21 = &H84
		''' <summary></summary>
		F22 = &H85
		''' <summary></summary>
		F23 = &H86
		''' <summary></summary>
		F24 = &H87
		''' <summary></summary>
		NumLock = &H90
		''' <summary></summary>
		ScrollLock = &H91
		''' <summary></summary>
		NEC_Equal = &H92
		''' <summary></summary>
		Fujitsu_Jisho = &H92
		''' <summary></summary>
		Fujitsu_Masshou = &H93
		''' <summary></summary>
		Fujitsu_Touroku = &H94
		''' <summary></summary>
		Fujitsu_Loya = &H95
		''' <summary></summary>
		Fujitsu_Roya = &H96
		''' <summary></summary>
		LeftShift = &HA0
		''' <summary></summary>
		RightShift = &HA1
		''' <summary></summary>
		LeftControl = &HA2
		''' <summary></summary>
		RightControl = &HA3
		''' <summary></summary>
		LeftMenu = &HA4
		''' <summary></summary>
		RightMenu = &HA5
		''' <summary></summary>
		BrowserBack = &HA6
		''' <summary></summary>
		BrowserForward = &HA7
		''' <summary></summary>
		BrowserRefresh = &HA8
		''' <summary></summary>
		BrowserStop = &HA9
		''' <summary></summary>
		BrowserSearch = &HAA
		''' <summary></summary>
		BrowserFavorites = &HAB
		''' <summary></summary>
		BrowserHome = &HAC
		''' <summary></summary>
		VolumeMute = &HAD
		''' <summary></summary>
		VolumeDown = &HAE
		''' <summary></summary>
		VolumeUp = &HAF
		''' <summary></summary>
		MediaNextTrack = &HB0
		''' <summary></summary>
		MediaPrevTrack = &HB1
		''' <summary></summary>
		MediaStop = &HB2
		''' <summary></summary>
		MediaPlayPause = &HB3
		''' <summary></summary>
		LaunchMail = &HB4
		''' <summary></summary>
		LaunchMediaSelect = &HB5
		''' <summary></summary>
		LaunchApplication1 = &HB6
		''' <summary></summary>
		LaunchApplication2 = &HB7
		''' <summary></summary>
		OEM1 = &HBA
		''' <summary></summary>
		OEMPlus = &HBB
		''' <summary></summary>
		OEMComma = &HBC
		''' <summary></summary>
		OEMMinus = &HBD
		''' <summary></summary>
		OEMPeriod = &HBE
		''' <summary></summary>
		OEM2 = &HBF
		''' <summary></summary>
		OEM3 = &HC0
		''' <summary></summary>
		OEM4 = &HDB
		''' <summary></summary>
		OEM5 = &HDC
		''' <summary></summary>
		OEM6 = &HDD
		''' <summary></summary>
		OEM7 = &HDE
		''' <summary></summary>
		OEM8 = &HDF
		''' <summary></summary>
		OEMAX = &HE1
		''' <summary></summary>
		OEM102 = &HE2
		''' <summary></summary>
		ICOHelp = &HE3
		''' <summary></summary>
		ICO00 = &HE4
		''' <summary></summary>
		ProcessKey = &HE5
		''' <summary></summary>
		ICOClear = &HE6
		''' <summary></summary>
		Packet = &HE7
		''' <summary></summary>
		OEMReset = &HE9
		''' <summary></summary>
		OEMJump = &HEA
		''' <summary></summary>
		OEMPA1 = &HEB
		''' <summary></summary>
		OEMPA2 = &HEC
		''' <summary></summary>
		OEMPA3 = &HED
		''' <summary></summary>
		OEMWSCtrl = &HEE
		''' <summary></summary>
		OEMCUSel = &HEF
		''' <summary></summary>
		OEMATTN = &HF0
		''' <summary></summary>
		OEMFinish = &HF1
		''' <summary></summary>
		OEMCopy = &HF2
		''' <summary></summary>
		OEMAuto = &HF3
		''' <summary></summary>
		OEMENLW = &HF4
		''' <summary></summary>
		OEMBackTab = &HF5
		''' <summary></summary>
		ATTN = &HF6
		''' <summary></summary>
		CRSel = &HF7
		''' <summary></summary>
		EXSel = &HF8
		''' <summary></summary>
		EREOF = &HF9
		''' <summary></summary>
		Play = &HFA
		''' <summary></summary>
		Zoom = &HFB
		''' <summary></summary>
		Noname = &HFC
		''' <summary></summary>
		PA1 = &HFD
		''' <summary></summary>
		OEMClear = &HFE
	End Enum

	''' <summary>Delegate for the low level keyboard hook</summary>
	''' <param name="nCode">A code the hook procedure uses to determine how to process the message. If nCode is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.</param>
	''' <param name="wParam">The identifier of the keyboard message. This parameter can be one of the following messages: WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP.</param>
	''' <param name="lParam">A pointer to a KBDLLHOOKSTRUCT structure.</param>
	''' <returns>If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. If nCode is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_KEYBOARD_LL hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the rest of the hook chain or the target window procedure.</returns>
	Public Delegate Function LowLevelKeyboardProcDelegate(nCode As Integer, wParam As IntPtr, <[In]()> lParam As IntPtr) As IntPtr
End Class

Open in new window

Which produces the following output -Capture.JPG-saige-

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Alexandre FernandesAuthor Commented:
Excelent! Thanks
ste5anSenior DeveloperCommented:
Caveat: a console has not necessarily a keyboard associated. Because it has also not always a window associated

See How To Obtain a Console Window Handle (HWND), GetConsoleWindow function.

You need to "hook" into stdin instead to be save.

See Console Handles.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.