Low-Level Keyboard Hook in C#

I answered a question today where someone asked for an example of setting a low-level keyboard hook with C#. I actually have an example of doing so in my May 2006 MSDN Magazine article on Managed Debugging Assistants, but the example is purposefully buggy in order to demonstrate the behavior of certain MDAs.

Here is an example without the bug (compile this as a console application):

using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;

class InterceptKeys
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;

public static void Main()
_hookID = SetHook(_proc);

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)
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
int vkCode = Marshal.ReadInt32(lParam);
return CallNextHookEx(_hookID, nCode, wParam, lParam);

[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);

Comments (215)
  1. Soumitra Banerjee says:

    Hi Stephen,

    Do you have anything similiar for low-level mouse hook?




  2. Оказывается, это очень просто реализовать. Стивен показывает элементарный пример

  3. Stephen Toub says:

    After my last post on implementing low-level keyboard hooks in C#, Soumitra asked if it was possible…

  4. Soumitra, I didn’t, but the code for doing low-level mouse hooks is almost identical to that for low-level keyboard hooks, so I posted a mouse hooks version for you at http://blogs.msdn.com/toub/archive/2006/05/03/589468.aspx.  Hope it’s helpful.

  5. Joku says:


    Great piece of code but it doesn’t output anything if I press Alt or AltGr. For all other keys it works.

  6. ALT is a system key and won’t be handled by the hook because of the filter for WM_KEYDOWN in HookCallback.

  7. bg says:

    I added a check for WM_SYSKEYDOWN and got the alt and altgr keys

    private const int WM_SYSKEYDOWN = 0x0104;

  8. Mladen says:

    great stuff!

    I’m wondering how would you check for a combination of CTRL+V or CTRL+ALT+k or similar?


  9. System.Windows.Forms.Control.ModifierKeys should do the trick, telling you whether shift, alt, and/or control are pressed.

  10. Mladen says:

    yes that’s true 🙂

    but how would i use them in

    if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)


       // this doesn’t work for me

       int vkCode = Marshal.ReadInt32(lParam);

       if ((Keys)vkCode == Keys.C && (Keys)vkCode == Keys.Control)





    lParam has only one value, no?

    so vkCode is also just one value.

    What am i missing here??

  11. if (Keys.C == (Keys)vkCode && Keys.Control == Control.ModifierKeys)

  12. mladen says:

    thank you very much.

  13. KingOfFotuna says:

    Thx, very good code

  14. Dennis says:

    Thanks… I have a question.  What would be the best way to take input from an attached device like a barcode reader and capture that information, but provide the application different data?  Thanks in advance

  15. Serg says:

    Thinks, very goo-od!

  16. What am I doing wrong? says:

    I have tried the code. But I only get this error

    C:Documents and SettingsThomasMy DocumentsVisual Studio ProjectsHooktestInterceptKeys.cs(10): Method ‘InterceptKeys.HookCallback(int, System.IntPtr, System.IntPtr)’ referenced without parentheses

    complaing on this!

    private static LowLevelKeyboardProc _proc = HookCallback;

  17. Stephen Toub says:

    You’re probably using C# 1.x, rather than 2.0.  This code is C# 2.0, making use of delegate inference.

  18. Rok says:

    How do I have the app "eat" up certain key strokes and not pass it up the chain?

    For eg: I’d like to disable the LWin & RWin keys for the duration this program is running.

    I tried the following:

    switch ((Keys)vkCode)


       // set of keys that should be trapped and nullified

       case Keys.LWin:

       case Keys.RWin:

    return CallNextHookEx((IntPtr)0, 0, wParam, (IntPtr)0);



         // pass it along to windows

         return CallNextHookEx(_hookID, nCode, wParam, lParam);


  19. Firemaple says:

    Is there a way to do the same thing in C#.NET 1.1 (as below) or is not possible?


    C:Documents and SettingsThomasMy DocumentsVisual Studio ProjectsHooktestInterceptKeys.cs(10): Method ‘InterceptKeys.HookCallback(int, System.IntPtr, System.IntPtr)’ referenced without parentheses

    complaing on this!

    private static LowLevelKeyboardProc _proc = HookCallback;

  20. Rok, if you want to eat the keystrokes, don’t call CallNextHookEx when you receive one of them.

    Firemaple, sure, just change that to:

    private static LowLevelKeyboardProc _proc = new LowLevelKeyboardProc(HookCallback);

    C# 2.0 supports delegate inference (where the compiler knows that I wanted to create an instance of LowLevelKeyboardProc and so doesn’t make me type it out), a feature new since 1.1.

  21. Levi says:

    Does anyone know how one would go about getting this to work as a Windows Service?  When running as a service, the event does not seem to fire.  I’m thinking this has something to do with the interactivity of services.

  22. SinhTo says:

    How can i run KeyboardHook at backgroud and trap all keys at all programs.

  23. I’m not clear on what you’re asking, as the code as it currently exist does intercept the keys for all processes.

  24. fred says:

    i hav created a hook that will allow u to access all users on any network

    to do this i just made a hook that allowed u to get all passwords and usernames.

  25. Raghavendra says:


       This article helped me a lot, presently I am trying to build a MSAA application in c#, there I am using IAccessible object. To get the IAccessble object pointer I need to call the AccessibleObjectFromEvent and need to pass the VARIANT structure. I am stuking here. Can u resolve this problem.



  26. Beast says:

    Cool, works well.

    If you have the time can you please advise how I can insert keystrokes into the stream. e.g. What I would like to be able to do is hook my "q" key and  replace it with two "a" key keystrokes



  27. You can send keystrokes to any app using standard window mechanisms and messages, for example the SendInput function from Win32 or the SendKeys.Send method from Windows Forms.

  28. Joao Ferreira says:

    I can’t compile, it gives me an error in the "using System.Windows.Forms;" directive. Is there supposed to be this namespace since this is a console program?

    Thanks for the code

  29. There’s no problem in using the Windows Forms DLL from a console app.  If you’re getting a compilation error on that line, it’s almost certainly because you’re not referencing the Windows Forms DLL when you compile.

  30. Joao Ferreira says:

    Ah, ok, I got it working now. Sorry for the lame question, still getting accustomed to C#.

    Thanks for the quick reply.

  31. Great article!  I’m trying to make a quick & dirty keyboard filter to simplify adding documentation boiler plate to .ASM code.  This way I hope to get my Assembler students to actually do it!

    Whenever I use SendKeys.Send(string), the control keys currently in effect are applied to the string by the application.

    For example, if Notepad is running, and my filter does something like

    if (Keys.C == (Keys)vkCode && Keys.Control == Control.ModifierKeys)

      SendKeys.Send( "hi there" );

    Notepad pops up a Replace dialog box because the ‘h’ in "hi…" is interpreted as Ctrl+h.

    Any easy way to turn off the control key for Notepad in this type of case?

    Thanks a lot,  G.Montante

  32. NewUser says:

    Will it work in Vista.  

    I don’t think so because hooking has some issues because of new Securities problems.

    How should all be done in Vista??

  33. NewUser says:

    I don’t know what’s the reason but I posted this same issue of Vista on many forums but no body use to reply and if some body even reply there is no concrete answer. Everyone revolves around Security Policies or applying XP2 security, but it solves my problem in no way.

  34. NewUser, yes, it should work in Vista, but not in situations where a lower privileged application tries to control a more privileged application; Vista does include security features to prevent such hijacking.

    Gary, unfortunately I can’t think of any good way to do that without running into a catch-22 situation.  Nice idea, though, and best of lucking finding a solution.

  35. primo says:

    For .Net 1.x, change the Following:

    private static LowLevelKeyboardProc _proc;// = HookCallback;


    public static void Main() {

    _proc += new LowLevelKeyboardProc(HookCallback);

    _hookID = SetHook(_proc);




  36. rose says:

    hi steohen, i have made this code on windows application not in console after fixing error the program results no yhing could you help me please about how to make it working at windows application thanx.

  37. rose says:

    hi stephen, i have made this code on windows application not in console after fixing error the program results no thing could you help me please about how to make it working at windows application thanx.

  38. Chaosdeckel says:


    you can ‘return new IntPtr(1);’ for the key’s you want to block.

  39. Rose, this should work fine in a Windows Forms application as long as you’re correctly pumping messages on the thread that installed the hook.  Without knowing more about your code, though, I can’t help much.

  40. Gary says:

    Thanks for the code Stephen (and suggestions from others)! I needed to trap the function keys to setup a quick navigation within my application. One thing that I noticed is if you did not return quickly the keypress advances to the next hook and this was a problem as I wanted to display a dialog  on F1 but the next application was getting the event. So I decided to record the key event, setup a timer for 100ms and process the key event when the timer is raised. This allows for immediate return of (1) which consumes the key press as desired. I hope this helps, and if anyone has a better method please let me know. Cheers Gary.

  41. Ravikanth says:

    Hi Stephen,

    Actually i am looking to develop a windows service with similar functionality.

    For ex. if i press key "s" it should save a image.

    so from the service ""onstart" method i am calling something like this

    myKeys.RegisterKeyBoardHook();where myKeys is the object of InterceptKeys class and written

    public void RegisterKeyBoardHook()


                <Check to see whether the code pressed is S>


               _hookID = SetHook(_proc);



           } in the InterceptKeys class.

    But when i press the key "s" storeImage is not getting called..

    Any help on this..



  42. Ravikanth says:

    Hi Stephan,

    Though Its a very worthy article,

    I am left over with a question.

    private static IntPtr HookCallback(

               int nCode, IntPtr wParam, IntPtr lParam)


               if (nCode >= 0 && (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN))


                   int vkSCode = Marshal.ReadInt32(lParam);

    if (((Keys)(Keys.S)) == (Keys)vkSCode && ((Keys)(Keys.Control | Keys.Alt) == Control.ModifierKeys))





               return CallNextHookEx(_hookID, nCode, wParam, lParam);


    using the above code snippet i am able to trap CTRL+ALT+S

    How can i implement CTRL+ALT+S+L ??Bcoz there will be only one lParam…

    Can you please reply me fast..



  43. Watch for both WM_KEYDOWN and WM_KEYUP for both keys.  You’ll need to look for receiving a WM_KEYDOWN for S and one for L before you receive a WM_KEYUP for whatever was received first.  You won’t just get one event, because there are truly multiple keystrokes here.

  44. Ravikanth says:

    Hi Stephan,

    I written the code as below..

    if (nCode >= 0 && (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN))


    if (nCode >= 0 && (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN))


     int vkCode = Marshal.ReadInt32(lParam);

     if (((Keys)(Keys.S)) == (Keys)vkCode)

         keySPressed = true;

     if (((Keys)(Keys.L)) == (Keys)vkCode)

         keyLPressed = true;

     if (keySPressed && keyLPressed && ((Keys)(Keys.Control | Keys.Alt) == Control.ModifierKeys))





                   else if (nCode >= 0 && (wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP))


                       keySPressed = false;

                       keyLPressed = false;



               return CallNextHookEx(_hookID, nCode, wParam, lParam);


    But still i am getting lot of calls to "StoreImage".

    Where i am going wrong ???

  45. I don’t follow the logic you’re using.  You could try something like the following, though I haven’t tested it.  In general, I’m happy to try to help when I have time, but I don’t have time right now to debug random code.

    private static bool keySPressed, keyLPressed;

    private static bool ControlAltPressed




           Keys mods = Keys.Control | Keys.Alt;

           return (Control.ModifierKeys & mods) == mods;



    private static IntPtr HookCallback(

       int nCode, IntPtr wParam, IntPtr lParam)


       Keys key = (Keys)Marshal.ReadInt32(lParam);

       if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)


           if (key == Keys.S && ControlAltPressed) keySPressed = true;

           if (key == Keys.L && ControlAltPressed) keyLPressed = true;

           if (keySPressed && keyLPressed) Console.WriteLine("Pressed");


       else if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP)


           if (key == Keys.S) keySPressed = false;

           if (key == Keys.L) keyLPressed = false;


       return CallNextHookEx(_hookID, nCode, wParam, lParam);


  46. Note, too, that the above sample won’t catch all corner cases. For example, keySPressed and keyLPressed will remain true even if the user lets go of the Control or Alt keys (while still continuing to hold S and L).

  47. John says:

    hi stephen

    do you have anything similar for the PocketPC



  48. Phillip Pearce says:

    Hi Stephan,

    This is a more general question regarding local hooks. Is it possible to create local hooks for other applications present on the desktop, assuming I know thre thread id of this application?



  49. Phillip Pearce says:

    Hi Stephan,

    This is a more general question regarding local hooks. Is it possible to create local hooks for other applications present on the desktop, assuming I know the thread id of this application?



  50. joe says:

    Is there a way to just intercept for current process key press?  The sample code catch all process key action, right?



  51. Joe: Sure, see http://support.microsoft.com/kb/318804.  The example traps mouse events, but the code for keyboard events is similar.  If you search the Web, you’ll find a bunch of additional examples.

    Philip: You can either create a local hook (just the current process) or a global hook (every process).  If you create a global hook, when you receive an event, you can do things like check what window is currently in the foreground to deduce what app will be processing the message, and filter based on that.

  52. Phillip says:


    So its either local on the current process only OR global on all processes.

    I have an accounting application that I want to hook and subsequently trap keystrokes to add additional functionalty. I invoked the applications executable using the ‘CreateProcess’ API, obtained the thread id and defined my hook(s) based on that but the SetWindowsHookEx function failed!

    Is this approach not possible based on your definition of what you can hook?



  53. From the documentation:

    "The global hooks are a shared resource, and installing one affects all applications in the same desktop as the calling thread."

    Additionally, most global hooks can’t be used from .NET… from support.microsoft.com/kb/318804:

    "Except for the WH_KEYBOARD_LL low-level hook and the WH_MOUSE_LL low-level hook, you cannot implement global hooks in the Microsoft .NET Framework. To install a global hook, a hook must have a native DLL export to inject itself in another process that requires a valid, consistent function to call into. This behavior requires a DLL export. The .NET Framework does not support DLL exports. Managed code has no concept of a consistent value for a function pointer because these function pointers are proxies that are built dynamically."

  54. Phillip says:

    Thanks. Yes, I was aware of the limitations,  costs (performance) and ‘danger’ of global hooks in .NET, which is why my first choice would have been a local hook.

    I guess you are saying that I cannot define a hook using the thread id from another process – is that correct?



  55. The only global hooks that work with .NET (due to the injection issue mentioned previously) are WH_KEYBOARD_LL and WH_MOUSE_LL, and those can’t be associated with a particular thread in another app; if you try, you’ll get back  Win32 error 0x0595: "This hook procedure can only be set globally".

  56. Phillip says:

    Okay. I understand the limitations on the scope of global hooks, however that is really not the way I actually want to go anyway.

    My question was really on local hooks and whether you could use the thread id from another process to define your hook.

    I guess you are saying you cannot do this and you are suggesting global hooks as an alternative – but bearing in mind their limitations in .NET.



  57. Ran Sagy says:

    Thanks for this sample. I needed something similar for a small project I’m doing (basically grab keyboard strokes, And pastes info into the clipboard based on which application was active when the keypress was made), And this does the trick. Too bad the .NET API is still missing many native calls needed. Hopefully, By Orcas it will get better.

  58. Dan says:

    Hey Stephen,

    Thanks for the code, but I have one problem though.

    I have been trying to use the code in a WINFX .NET 3.0 project and I have managed to get it to work by adding System.Windows.Input to the namespace and changing Keys to Key as in:

    int vkCode = Marshal.ReadInt32(lParam);


    It debugs the project fine but when it comes to pressing a key, rather than showing a D, it outputs a Y instead.

    Any ideas?


  59. The System.Windows.Forms.Keys and System.Windows.Input.Key enumerations have different values (Keys.D == 0x44, Keys.Y == 0x59, Key.D == 0x2F, and Key.Y = 0x44).  The former maps more directly to virtual key codes.  If you’re using WPF, you can use the public static method System.Windows.Input.KeyInterop.KeyFromVirtualKey to convert vkCode into a Key value.


  60. Dan says:

    Ah right. Thanks for your help! 🙂

    – Dan

  61. Arif says:

    Hey All,

    Great article and useful converstations! I was able to hookup the keyboard to a local process (using the WH_KEYBOARD [=0x02] hook and passing the process id to the SetWindowsHookEx API) and also by using Philips timer idea, was able to cache and control the key strokes.

    Thanks all for the help;

    – Arif

  62. What do you mean "this isn’t working"?  How exactly is it not working?  Are you getting a compiler error?  Is it throwing an exception? etc.

  63. reesylou says:

    Firstly… wonderful piece of code.  

    I am building a Keyboard Basher for my baby daughter, and as such want to detect and redirect several keystrokes (like LWin and RWin).

    Using your sample as part of a Windows form, I have no problem detecting and consuming these keys, but what if I want to act on them (and still not pass them on to the system)?  How do I workaround not being able to call a non-static method directly in this code?

  64. reesylou says:

    (PS I am using .NET 1.1 and have adapted the code accordingly based on your previous comments)

  65. Igor Gatis says:

    I’m using your code to launch an very simple app that allows to copy code snippets from anywhere. It works just fine until I right click on the app tray icon to access its menu. After that, it does fire keyboard events to my app anymore (like it was unhooked).

    Is it expected? Or am I doing something that’s causing this?

  66. Igor Gatis says:

    One more thing: I’m using Vista 64-bit.

  67. Varix says:

    Im doing a similar hook in Delphi. I understand that the style is different from c#. I have a basic hook, but it actually traps the keys. I would like them to be read, but still passed on to the application that has focus. How would i do that?

  68. Varix, just make sure to call CallNextHookEx in all places where you want the keys passed along.

  69. guyc says:

    Will this hook work with 3d games that use Directx?

  70. Derek says:

    Great code. Thank you very much.

  71. evrastil says:

    Hi Stephen great code…

    I have a question. I see that Im not alone, because people asked here before, but no answer…

    Does anyone know how one would go about getting this to work as a Windows Service?  When running as a service, the event does not seem to fire. Can you help Stephen or anyone?

  72. Flood says:

    Hi all

    Good stuff Stephen and contributers also.

    I did have the same question as evrastil about running this as a windows service… any ideas or pointers?

    Thank you,

  73. Jonathan says:

    How in .NET framework 2.0 do I convert the Integer keyCode or IntPtr lParam value to the actual value entered by the user, not one of the Keys enumerators?

  74. Russell says:


    First of thanks to Stephen Toub for the code. Currently my PC is running an app that changes mode if I press the F12 key. If I run your program it shows all keys except the F12 key (probably that program not passing it up to next hook as eating it up?). How can I make sure that your program first traps the F12 rather than that program? Although my ultimate goal is to not trap the event rather send/generate the F12 keystrokes from my program to change the mode (SendInput using user32.dll does not work, so I think it is using low level hook or something?) of that program using code.


  75. Ed says:


    I’m having the same problem Joao had back Jan. 16: I get the error in "using System.Windows.Forms."  Apparently he got it to work, but I don’t understand the solution.  How does one refrence the Windows Forms DLL when compiling?

    I’m a real noob with C# and I’m using Visual C# 2005 Express.



  76. Ed says:

    Duh.  I found the problem.  I needed to add

    System.Windows.Forms to the references in the Solution Explorer in Visual C# Express.

    Thanks for the great code, Stephen!


  77. mike says:

    Hi Stephen, Will this code work in the Windows Compact Framework?  Im guessing using coredll.dll instead of user32.dll might work for some of those unmanaged commands but im not sure how that would translate with the rest of the code.



  78. Jon says:

    Do you know of any more forums related to this topic and a windows service?  I’ve tried the above links and can’t find a solution.

    I wish to temporarily disable the windows and alt+tab system keys which I can’t trap in my app. This occurs while a form is visible and then is released when the form is hidden.

    My service already runs interactively (hence the form appearing), which is a proposed solution on one of the forums.

    Many thanks for any help on this

  79. Naveen says:

    i’m using ur code for low-level keyboard hook

    but the above code throw an error

    "namespace name ‘Process’ could not be found"

    even after importing all the namespaced

    can u plz help me in finding solution


    Naveen Kushwaha


  80. bob builder says:

    Hello.. How can I differ between capital letter, other languages letters and regular letters

    i.e :

    c and C will give me the same results.

    also for every other key like b and B.


  81. Bob, you can use GetKeyState from user32.dll to check the status of the shift key, for example.

  82. bob builder says:

    But it doesn’t gets me if it’s other languags.

    also, if caps lock were hitted it doesn’t give me the state.

    I would like to know which letter has been typed in Hebrew.

  83. ShaMirza says:

    Any solution which make this work on vista.

  84. xiaojiuhk says:

    Thank you, bur the code is too short , I am suspicions of its function.

  85. Update: I finally resolved this. The code was using the WH_KEYBOARD flag. When run under Vista, the call to SetWindowsHookEx () would fail with a NULL return code. I changed the flag to WH_KEYBOARD_LL and Vista (and other platforms) are once again happy.

  86. jon says:

    Hey, i want to ‘eat up’ keys, but your suggestion of not calling CallNextHookEx isn’t working. other applications receive input. any other ideas?

  87. hunter says:

    In HookCallback(), instead of returning nothing or the original value how can I return another key value? For example if ‘j’ was pressed how can I change it so that ‘k’ was pressed?

  88. hunter says:

    In HookCallback(), instead of returning nothing or the original value how can I return another key value? For example if ‘j’ was pressed how can I change it so that ‘k’ was pressed?

  89. Hezi says:


    How can I trap Alt+Tab keys? A similar question has been asked already by Jon on September 20 2007 but I Didn’t fined an answer.



  90. Stephan says:

    I don’t know if it is exactly the same … I want to exchange keypresses like user pressed X but it is replaced with Y.

    I need it in a way that the following events get the replaced value.

    this should work like this

    user presses X >>>

    1. replace event is called X is replaced with Y

    2. KeyDown with "Y"

    3. KeyPress with "Y"

    4. KeyUp with "Y"

  91. Matt says:


    Thanks for providing your code and keeping up with all the comments/questions that people have added.  That’s very cool of you.

    I have another question.

    I’m using your code – along with the other example you gave for listening to mouse events – to detect whether my windows forms app is currently in use.  I’m only interested in events from MY app/process, but when I pass-in the thread id for the current thread, the hook doesn’t work.

    Also, when I just pass in zero as the thread id, my little test app is slow to close (3 or 4 sec compared to almost-instantaneous when the hooks aren’t there).  I assume this is b/c it’s listening for events from all processes.

    So my question is: how can I set the listener to listen to my app/process only?  Or, if that’s not possible, how can I speed things up?

    Thanks in advance.


  92. Jon, if your goal is to eat the input (not calling CallNextHookEx), make sure you return (IntPtr)1 from the hook callback rather than IntPtr.Zero.

    Hezi, the code as I have it is looking only for WM_KEYDOWN messages… for alt, you also need WM_SYSKEYDOWN.

    Hunter and Stephan, see http://support.microsoft.com/kb/33690.

    Matt, for an example of setting a hook only for the current process, see http://support.microsoft.com/kb/318804.

  93. Is there anyway, to get the code to write the localized names of the keys out? When I press on "ÆØÅ" (three Danish letters) it says Oemtilde, Oem7 and Oem6.

    Another thing: Is it possible to get the code not to register the key several times because it is pressed down for a while, so it only tracks the key once everytime you press and ‘unpress’?

  94. I got the keydown fixed! 😀 Just changed the KEYDOWN to KEYUP and changed the 0x-thingy.

    I still haven’t figured out how to use a specific keyboard layout… 🙁

  95. Raveheart says:

    I also can’t get this to run as a service, even allowing for interaction with the desktop. All I’m trying to do is get the time of the very last input on an XP machine (with multiple fast user-switching logins). I need to know if any user is still active so my service can react appropriately. Very grateful for any suggestions/comments.

  96. aalan says:

    Hi Stephen,

    Do you have anything similiar for low-level mouse hook?


  97. Nik says:

    Stephen just wanted to thank you for all the hard work you have put in and for the patience while replying back to the questions.

    Keep up the good work guys!

  98. Caspian says:

    Hi – I’m trying to compile your program using Microsoft Visual C# Express Edition, but I get an error in the build process – it says  ‘The type or namespace name ‘Windows’ does not exist in the namespace ‘System’ (are you missing an assembly reference?)’

    How do I use an assembly reference?



  99. Mark says:

    Hi toub, great code!

    how to know the difference between eg. a (lowercase) and A (Uppercase)?

    the same for other( b,B; c,C and so on…)

    thnk a lot


  100. You can use GetKeyState from user32.dll to determine the state of the shift key and the caps lock key.  Alternatively, you can use Control.ModifierKeys to get the state of the shift key and Console.CapsLock to get the state of the caps lock key; internally, they just use GetKeyState.

  101. kooldude says:


    I want to hook Fn+ keys. For ex Fn+F1..F10.

    Please advise How to go about it.

    Thanks a lot.

  102. naren says:

    i want hook for toggling windows

  103. RickyS says:

    Stephen and Gary,

    I notice a couple of comments about the issue sendkeys with the control key.  I’m getting as Gary mentioned, the control (and alt) keys in addition to my send key string.  Can either of you elaborate on the cause and workaround / solution for this situation.

    Thanks for this great article and thread!


  104. eddie says:

    I am having trouble capturing shift+{any kay} when it is pressed in continuous manner.

    It goes like this..

    1. You press shift+a

    2. Release the ‘a’ key but dont release the shift key.

    3. Press ‘b’. Here the program is supposed to capture shift+b but it only captures b.

    I am using GetAsyncKeyState to get the status of shift key. If I release the shift key at step 2 above, the program capture shift+b fine.

    Am I missing something here?

  105. asnat says:


    i have a problem which seems a bit strange.

    i have a small program that do the follow:

    if (vkCode == key) sendkey.sendwait("^c");

    when the key is the CTRL key the program runs well. if it’s a shift it doesn’t.

    any idea?

  106. sudheer says:


    I want to do something on when key down and also on key up.




    ///do some thing




    ///do some thing


    I am not familiar with c# and .net please can you help me out.

  107. Lasse says:


    Is there any possibility to place the self-defined hook procedure at the end of the hook chain?

    E.g. if I monitor keyboard strokes and identify a ‘ctrl+c’ my hook fires before the copy-action (resulting from ctrl+c) starts. Is it possible to have my hook fire after this copy action?

    Thanks in advance.

    Cheers, Lasse.

  108. s sharp says:

    I am having trouble capturing shift+{any kay}

  109. Sebastiano says:

    I’m trying do send keys to a directx application (mictosoft train simulator), the classic sendkey doesn’t work….

    I tryed to see if there’s something in the directx to emulate a keypress, but i still haven’t found anything.

    Please help me!!

  110. Brandon says:

    Thank you so much this works like a dream. You dont know how much this just helped me!!!

  111. chan says:

    Is there a way to capture keys from multimedia keyboard?

    I able to capture all keys except these keys "PLAY","PAUSE", "FORWARD", "REVERSE","HOME", and "POWER".

    Thank you for your hard work.

  112. Nicholas says:

    Hello! Thank you for this great piece of code! It helped me a lot. Using the program above, I’m "recording" the keys pressed into a file. Everything is ok, I am able to handle situations when Shift or Caps are pressed.

    My question: How can I implement a timer so the file gets empty between a specific interval  (example: every 10 min. the file is emptied)?

    I don’t know where should I declare the timer. I tried to declare it in Main(), something like:


    _hookID = SetHook(_proc);

    System.Timers.Timer timer = new System.Timers.Timer(30000);

    timer.Elapsed += new ElapsedEventHandler(anotherclass.OnTimedEvent);

      timer.Enabled = true;




    The code above works just ONCE! The file gets emptied once…

    Thank you. I hope you will reply soon.


  113. Nicholas says:

    Hi! Me again… The timer works fine, there was a problem somewhere else in my code… Thanks anyway.


  114. Bhavesh says:

    kool application… this is what i was looking for from long time

  115. ibrahim says:

    Hey, why you use Application.Run() to call the HookCallback() method. Unfortunately, i got an error "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." when i suppose to call the "HookCallback()" method without Application.Run().

    The error shows in the following code,

    return CallNextHookEx(_hookID, nCode, wParam, lParam);

    i’m using another form in my program, hence i need to call "HookCallback()" method without "Application.Run".

    Is there any way to do like this….

  116. yosi says:

    hi! i am wating for an answer. how can i add a new item to the pop-up menu of the computer(right click).


  117. HauLD says:

    It’s very useful code. Thank you a lot.

  118. Attila Pápai says:

    Hello All!

    I am making a service application which logging user activites like mouse moving and key pressing and here comes Hooks. First of all I tried it in a console application and everything was perfect, but when I put the code (and some other) to the service app. and started it, nothing happened. I am sure the code is good. I am running the service in the background with Local System privileges.

    Is there anybody can help me?


  119. Attila Pápai says:

    Okey, I found the way to this.

    Here is the code:

    put it in AfterInstall:

    RegistryKey ckey = Registry.LocalMachine.OpenSubKey(@"SYSTEMCurrentControlSetServicesnServiceName",true);

               if (ckey != null)


                   if (ckey.GetValue("Type") != null)


                       ckey.SetValue("Type", ((int)ckey.GetValue("Type") | 272));



  120. Chris P says:

    Hello.  I’m working on this bit as a windows service as well, in a Vista 32-bit environment.  Unfortunately, this all works well and good until I run it as a service.  Then it’s all failure.  I noticed my service will actually briefly catch keys after the installer runs, but shortly after it’s shutdown and when I launch it from my services panel I get nothing.  I tried the above mentioned fix, setting my type value to 272, but no avail.  Has anyone else found a way around the Windows Service limitations?

  121. Amelie says:

    Hi Toub,

    I have a simple question:

    Your code captures all key presses globally, right? Is there a way to limit those to a single application, like a way to specify in the hook so that key presses are only captured if that application is in focus?

    Also do you know how to detect if shift/alt/control keys are pressed? I would like to add these info separately to the eventargs. Should I convert the keycode into Keys? If so, how? Because I am writing a DLL, not exe.


  122. 4gGood idea.2f I compleatly disagree with last post .  nir

    <a href="http://skuper.ru">ламинат купить</a> 6r

  123. Darkonekt says:

    Hey i have written code that works perfect on windows and console apps that check all kinds of key combos and it works wonderful. But when i run it inside a service it wont work. This is my opinion services run under a different user session and therefore they catch keystrokes for that user only under which they are running. Now my question is: has anyone had the hook working under a service? If so can you please show us. I have tried a million things and nothing works. Also has anyone been able to run a .NET DLL under svchost? May be thats the answer. I havent been able to do neither one.

  124. Abraham says:

    Hi, this is a great start for me – a newbie.

    I have a java program that programatically toggles the Caps Lock key.  Is there a way to allow the ‘programatic key strokes’ but block the actual key strokes from the keyboard?

    Any advice at all would be gratefuly received.



  125. Anil says:

    Do you have a code to cature key board ket events using window service without using form.

    Could you please suggest me where can I find this code




  126. Richard says:

    Hi, have you ever tried to use comments in your code? I think they are fundamental.

  127. jordanwb says:

    How would I use this in a Windows Form Application?

  128. Argon says:

    Works almost perfect, just for a detail, I opened a instance of notepad and when I tried to close it, takes a lot to close.

    Any suggestions?

  129. Pramod.dev says:

    I have a requirement to alert user that caps key is on. And i dont want to use any heavy interop. Is there any other way to do this.


    Pramod Pallath Vasudevan.

  130. semir says:

    Please can someone tell me how to make keyboard hook from windows service? I was trying to allow interact width desktop but it is not working and I don’t get any exception…??

  131. ttomsen says:

    The reason this is not working in an windows app is the line :


    Then the very next line unhooks the hook.

    So i removed the application run, i put the hook close in the formClosed event.

    This works, however my call back is being called twice now?

  132. Bruce says:

    Stephen, I’m writing a service that catch all printscreen and save the image in a directory.

    My SendHook returns a number, but my HookCallback not respond to any click. Can you help me?

  133. La Dai Dong says:

    Thanks much for your code.

    I’m modified it as an Class. Now I can use it like this:

    KeyHook newKeyTrap = new KeyHook();

    //IMPORTANT – Set Even Handle for KeyHook Return Event

    newKeyTrap.keyHookReturn += new KeyHook.KeyHookReturn(HookReturn);


    private void HookReturn(int keyEvent, int vkCode)


          //Do Any things with vkCode

          //You can use System.Windows.Forms.Keys class to check any button is pressed included Multi Media Key

          //If you don’t know the name of that button in Keys Class just write out the vkCode and Find for that code in Keys Class


    My Code also can detect which Window is focus in (By the Window Title)

    Email me if You interested in My Code.


  134. Luiz Roberto says:

    Thank you very much for your code.

    3 years later still helping peoples.

  135. Обои says:

    thanx for the interesting posts

  136. woop says:

    awesome piece of code. Cheers!

  137. Akshay says:

    i have a requirement where i need to create a virtual keyboard and its keys should change on the culture of c# code.

    Ao if  A S D F keys are in english keyboard then if i change the culture to french it should show me French keyboard keys in place of  A S D F it should start showing Q S D F

    does anyone knows how to do that.

  138. Возникла сегодня задача… Сделать возможность приложению реагировать на нажатие клавиш. Ничего сложного

  139. janardhan says:

    hello….when i compile this code, i’m getting…" Error 1 ‘WindowsFormsApplication1.Form1.Dispose(bool)’: no suitable method found to override " ….i just copy pasted the above code to a new forms application…what do i have to do to make this code work?

  140. Amarpreet Singh says:

    Great Post Dear

    I was looking exactly the same thing you did.


    Keep it up.

  141. ankush says:

    hi Stephan

    can you help me. actually i am working on a window application using c#, i wanna know how to capture keystrokes when my window application is active, i wanna know that how to capture keystrokes with source application, please help me out . thanks

  142. ankush says:

    hi Stephan

    can you help me. actually i am working on a window application using c#, i wanna know how to capture keystrokes when my window application is active, i wanna know that how to capture keystrokes with source application, please help me out . thanks

  143. Amit R says:

    Hi Stephan,

    Great post.

    I have question about Windows Mobile development.

    Can we use the same code into the Windows Mobile application? If yes, then what about the OEM keys?



    Amit Rote

  144. Andy Bantly says:

    How to create a keyboard and mouse hook in Visual C++ 2005

    Step 1: Create a CWinThread derived thread to house the hook procedures.  The documentation tells us that hook procedures can have global or thread state.  We are interested in thread state so we place our hook in a thread and then hook the Thread ID of the main .EXE, which can be DOC/VIEW or Dialog based.

    Step 2: Instantiate the thread that contains the hook in the application.

    Step 1 Code

    #define WM_ENDTHREAD WM_APP + 100

    // CHookThread

    class CHookThread : public CWinThread




    CHookThread(int iThreadId = GetCurrentThreadId());

    virtual ~CHookThread();

    virtual BOOL InitInstance();

    virtual int ExitInstance();


    afx_msg void OnEndThread(WPARAM wParam,LPARAM lParam);


    int m_iThreadId;

    static HHOOK m_hKeyBdHook;

    static HHOOK m_hMouseHook;

    static LRESULT CALLBACK KeyBdHookProc(int nCode,WPARAM wParam,LPARAM lParam);

    static LRESULT CALLBACK MouseHookProc(int nCode,WPARAM wParam,LPARAM lParam);




    HHOOK CHookThread::m_hKeyBdHook = NULL;

    HHOOK CHookThread::m_hMouseHook = NULL;

    IMPLEMENT_DYNCREATE(CHookThread, CWinThread)

    CHookThread::CHookThread(int iThreadId) : m_iThreadId(iThreadId)





    // Unhook the keyboard

    if (m_hKeyBdHook)



    m_hKeyBdHook = NULL;


    // Unhook the mouse

    if (m_hMouseHook)



    m_hMouseHook = NULL;



    BOOL CHookThread::InitInstance()


    // Start recording the keyboard messages

    HINSTANCE hInstance = AfxGetInstanceHandle();

    m_hKeyBdHook = SetWindowsHookEx(WH_KEYBOARD,CHookThread::KeyBdHookProc,hInstance,m_iThreadId);

    if (!m_hKeyBdHook)


    // Start recording the mouse messages

    m_hMouseHook = SetWindowsHookEx(WH_MOUSE,CHookThread::MouseHookProc,hInstance,m_iThreadId);

    if (!m_hMouseHook)


    return TRUE;


    int CHookThread::ExitInstance()


    return CWinThread::ExitInstance();


    // CHookThread message handlers

    BEGIN_MESSAGE_MAP(CHookThread, CWinThread)



    // Record the keyboard messages

    LRESULT CALLBACK CHookThread::KeyBdHookProc(int nCode,WPARAM wParam,LPARAM lParam)


    LRESULT Res = CallNextHookEx(m_hKeyBdHook,nCode,wParam,lParam);

    return Res;


    // Record the mouse messages

    LRESULT CALLBACK CHookThread::MouseHookProc(int nCode,WPARAM wParam,LPARAM lParam)


    LRESULT Res = CallNextHookEx(m_hMouseHook,nCode,wParam,lParam);

    return Res;


    void CHookThread::OnEndThread(WPARAM wParam,LPARAM lParam)


    // End the thread



    Step 2 Code

    In the constructor of the dialog or the view class, create the thread that creates the hook.  Make sure to give it the thread id of the current application!

    // CRemoteDesktopView construction/destruction



    // Hook the keyboard and mouse

    m_pHookThread = new CHookThread(GetCurrentThreadId());





    // Unhook the keyboard and mouse



    This is all there is to it.  Of course you are responsible for filling in the code after the actual event is received!  In my case, I write PC remote control software and I use journaling to help me control the server by recording the messages on one machine and playing them back on another.

  145. William C says:

    I have converted it into vb.net xpress for who ever wants it. Enjoy.

    Imports System

    Imports System.Diagnostics

    Imports System.Windows.Forms

    Imports System.Runtime.InteropServices

    Public Class Form1

       Private Const WH_KEYBOARD_LL As Integer = 13

       Private Const WM_KEYDOWN As Integer = &H100

       Private Shared _proc As New LowLevelKeyboardProc(AddressOf HookCallback)

       Private Shared _hookID As IntPtr = IntPtr.Zero

       Private Shared Function SetHook(ByVal proc As LowLevelKeyboardProc) As IntPtr

           Using curProcess As Process = Process.GetCurrentProcess()

               Using curModule As ProcessModule = curProcess.MainModule

                   Return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0)

               End Using

           End Using

       End Function

       Private Delegate Function LowLevelKeyboardProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr

       Private Shared Function HookCallback(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr

           If nCode >= 0 AndAlso wParam = CType(WM_KEYDOWN, IntPtr) Then

               Dim vkCode As Integer = Marshal.ReadInt32(lParam)

               ‘Console.WriteLine(CType(vkCode, Keys))

               MsgBox(CType(vkCode, Keys).ToString)

           End If

           Return CallNextHookEx(_hookID, nCode, wParam, lParam)

       End Function

       <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _

       Private Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal lpfn As LowLevelKeyboardProc, ByVal hMod As IntPtr, ByVal dwThreadId As UInteger) As IntPtr

       End Function

       <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _

       Private Shared Function UnhookWindowsHookEx(ByVal hhk As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean

       End Function

       <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _

       Private Shared Function CallNextHookEx(ByVal hhk As IntPtr, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr

       End Function

       <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _

       Private Shared Function GetModuleHandle(ByVal lpModuleName As String) As IntPtr

       End Function

       Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

           _hookID = SetHook(_proc)



       End Sub

    End Class

  146. Nitin says:

    Thanks for the code I found it very very useful but how can we use for disable Alt+F4 ?

    I tried my best with this code it doesn’t work. Actually when pressing Alt+F4 it is not even calling HookCallback function. So, there is no way to track it.

    Is there anyone know any idea to get around this ?

  147. dvdamrketzz says:

    Диски blu-ray фильмы по 20$ dvd фильмы диски новинки по 1.8$

    в наличии и под заказ, доставка в течении 3х дней



    наш сайт http://www.dvd-market.com.ua

  148. TYRichard says:

    Very interesting site.  I appreciate your comment about my   black  script  Do you want a fresh joke from net?   Who was Snow White’s brother? Egg White. Get the yolk?


  149. fincareertut says:

    How to build a [url=http://timezonegames.co.in/_backup/index.php]career in finance[/url]? We know as it to do!

    In a turning-point the in the most suitable way of all to do a career.

    We drive avoid you herein 🙂

    On our portal you desire catch sight of the first-class suggestions on stint!

  150. michaeljyuti says:

    And for you crisis?

    you heard of new law, about an exit from a crisis:

    agreement about [url=http://www.netvibes.com/debt_consolidation]debt consolidation[/url]

    This agreement narrates about new on-line finance center, where any man, can get a credit.

  151. Cool post, I’ll try this tonight!

  152. ComputerAngel says:


    I tried your application and it works great except a little problem. May be you can help me out.

    In the HookCallback function we get the keys like Keys.Oem1, Keys.A etc.. The problem is i want to convert keys.Oem1 to actual characters of the inputed keys that a "real" application sees. I have tried MapVirtualKeyW but it has limitation since it is blind to any keyboard state such as the shift key, etc. i believe WM_CHAR is the correct way to doing it but how 🙁 dont know. i also googled but no luck.

    Thanks for your help in advance

  153. TheRage3K says:

    Thanks!  I had some code to capture the key press… but without the "Marshal.ReadInt32(lparam)", I didn’t know WHICH key was being pressed!  This provided the missing link.

  154. Гносис says:

    How to eat key strokes?

    For example, i need to clear key buffer, to avoid print space, when i press WINKEY + SPACE, and perform some operation…

    private static IntPtr HookCallback(

      int nCode, IntPtr wParam, IntPtr lParam)


     int vkCode = Marshal.ReadInt32(lParam);

     if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)


       if ((Keys)vkCode == Keys.LWin ||

           (Keys)vkCode == Keys.RWin)


         WinKeyStillPressed = true;



     if (nCode >= 0 && wParam == (IntPtr)WM_KEYUP)


      if ((Keys)vkCode == Keys.LWin ||

          (Keys)vkCode == Keys.RWin)

      { //clear flag

        WinKeyStillPressed = false;


      if (WinKeyStillPressed)


        if ((Keys)vkCode == Keys.Space)


          PlayPauseInner(); // My Styff

          return CallNextHookEx((IntPtr)0, 0, wParam, (IntPtr)0); // does not eat key strokes

          return (IntPtr)0; // does not eat key strokes

          return (IntPtr)1; // does not eat key strokes


        if ((Keys)vkCode == Keys.Left)


          PlayRewind(); // My Styff


        if ((Keys)vkCode == Keys.Right)


          PlayForward(); // My Styff




    return CallNextHookEx((IntPtr)0, 0, wParam, (IntPtr)0);


  155. bhagavath says:

    hi all,

        how to find the name of all the processes receiving key board input.please help me on this…

    Thanks in advance

  156. Rajib Mandal says:


    Ist id possible to trapp series of keystorkes  before pressing enter key?

  157. Rajib Mandal says:

    I want to trap series of keystrokes i.e "a1de"

    How is it possible?

  158. jcooke says:

    If anyone is still reading, this code has gotten me 90% of the way, but I’m trying to figure out how to capture input from a particular HID and let the others pass through.

    Are these hooks at too high level of abstraction to do this?


  159. cksubs says:

    I’m trying to use this code to output a different keyboard char than the one actually typed. The relevant message has been changed to this:

       private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)


           if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)



               KBDLLHOOKSTRUCT replacementKey = new KBDLLHOOKSTRUCT();

               Marshal.PtrToStructure(lParam, replacementKey);

               replacementKey.vkCode = 90; // char ‘Z’

               Marshal.StructureToPtr(replacementKey, lParam, true);


           return CallNextHookEx(_hookID, nCode, wParam, lParam);


    Unfortunately this outputs a "A first chance exception of type ‘System.ArgumentException’ occurred in foobar.exe" every time I press a key. Any idea?

  160. Nuren Geodakov says:

    No luck creating a Windows Service that would capture Hot Keys like Ctrl+Alt+[some char].

    The service captures nothing. I tried that patch with the Registry, does not work. Although the code works for Windows Forms applications.

    If you guys can find a solution for Windows services please share

    Thank you


  161. Mike says:

    Cool, Do you know how to do the (approx.) equivilant in Visual Basic?

  162. Zeeshan Umar says:

    Thanks for sharing this, I remembered the days of C++ and windows programming.

  163. Tapan says:

    I am new to windows programing, and i am trying to trap the ALT+TAB, ALT+ESC.. keys and then disable there action, can you help me to get this done. I need to do it in VB.Net

  164. pinevn says:

    I use this sample code in windows 7; and i replace Console.WriteLine((Keys)vkCode) by  MessageBox.Show(Convert.ToString((Keys)vkCode)). when it runs, i press one key for 11 times, the hook keyboard is crashed!!!! I don't know why, can you help me plz??????

  165. Brett Widmann says:

    This is so helpful! Thanks for sharing.

  166. Innocent Boy says:


    Thanks for the above mentioned code. I was actually searching for something that can hook the keyboard events only for one application i.e. powerpoint 2007.

    In your code SetWindowsHookEx expects the parameter 0, therefore the hook is applied for all the applications. I do not want that. i only want the hook to be applicable with powerpoint 2007 application. Can you help?

  167. Jason says:

    Thanks for the piece of code it's extremely helpful!  🙂

  168. Charlie says:

    HookCallback() is never called in .NET 4.0 on XP SP3. Am I missing something?

  169. Andreas says:

    I know it isn't really a productive comment, but thanks a lot for this!

  170. Roberto says:

    Hello, I wanted to see if it is possible to "modify"  the hook so that it changes de key pressed, for example:  if i press "a", it will display a "b"…    

  171. Paulo RB says:

    I would like to know what happens if I don't use the        Application.Run();  , it seems that this call

    is necessary to make it run.

    But I can't compile using   Application.Run() .  

    If I code a windows service how the code should be changed?


  172. Monosodium says:

    @JCooke – I think this is too high-level for your needs.

    I'm working on a project with some similar requirements and you'd need to look at using GetRawInputData from User32.dll.  http://www.codeproject.com/…/rawinput.aspx probably has what you need though.

  173. Jalle says:

    Does any1 know if I can store this KeyboardHook code in seperate Class or Module ?

    I dont want to mix all this KeyboardHook  with other ode in my form so I would like to have it in external module or class file?

    I belive this is simple, but I am not so familiar with it ..

  174. anant says:

    how can i use the same for compact framework??

  175. mj121 says:

    hi Stephen,

    nice article!!! how can i perform this.. ex: first press A and then B after that AB becomes C..? (deleting both A and B)

    press A -> A

    press B -> C (generally this is AB)


  176. Allan Chen says:

    my problem is that whe using low level key board hook in a console app, it can get the key information when the app lost focus which is expected, but when I change this code a little bit and make it works in a win form app, it can only get the key information just when the window get focus, but when it lost focus, it cannot get the key information anymore.

  177. Jose Maali says:

    I am trying to run this application as task (on Task Scheduler) on Windows 7 but there is an issue which I couldn't figure out.

    It might be because of either threading or security?

    Has anyone run this code as a task or it is not possible?

  178. women down jacket says:

    Snow still underground rustling, more bitter cold air. When we looked around, neusoft wan to already became a XueSu ice sculpture of the world. Nomura HuangZhong, cold Lin haystack was draped thick.<a href="http://www.downjacketclearance.com/moncler-c-2.html">women down jacket</a>

  179. Thanks, made my tool complete. 🙂

  180. Markus Florian says:


    Is there a way to know which device send the input?

    i need to identify the input source because i want to filter the barcode scanner

  181. ED says:


    Does this work for WinForm? I've tried it in winform and it's not working. If I comment out the Application.Start(); The winform will no capture the keys. If I leave Application.Start(); then the form will not show but the key capture fires. Is console app codes different than winform code? What am I missing?



  182. ravi says:

    Error 1 The name 'SetHook' does not exist in the current context c:users****documentsvisual studio 2010ProjectstrycatchtrycatchProgram.cs 29 23 trycatch

    wat to do?

  183. Sebastian says:

    Hi there,

    I'm developing an application which is doing some things in a loop, and this loop have to breaked when any key is entered.

    I tried the above code but the HookCallback method is called only after the loop.

    Is there a way i can do any modify in this code to make it work for me ?

    I looked into it : http://www.codeproject.com/…/Processing-Global-Mouse-and-Keyboard-Hooks-in-C

    but it uses a lot of its own classes which is not good.

    VisualStudio 2010, C#, windows7, .NET 3.5

  184. jefftoaster says:

    Excellent work!  I'm using this to trap (and eat) some keypress combinations that are invalid under certain data conditions for my users in an accounting package they use.  Very Pleased!

  185. whitebyte says:

    we made up a open source component in c# that uses hooks or polling (you can choose), way more convenient:


  186. moji says:

    That was great


  187. Troy19 says:

    Im not sure if this will get answered? but im going to ask in any case.

    Is there a way that we can measure the speed of the current users usage in terms of keyboard mouse activity?

    not using a prescribed piece of text, like most typing-tutors do,

    but more along the lines of how fast is the user using the keyboard and mouse independently and in combination?

    regardless of what the user is actually doing.

  188. Pravesh says:

    I have used this code in windows service, But it is not detecting any key events.

    Do you have any idea to handle this in windows service.

  189. Hi. I'm making stopwatch using the shortcuts and it works when I press 2 times "Home" after opening the program. When I press one time or wait a little after running the program, it will start the stopwatch and nothing else. My code is as follows:

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {

           if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN) {

               vkCode = Marshal.ReadInt32(lParam);

               if ((Keys)vkCode == Keys.Home)




                   broken = 0;

                   start = DateTime.Now;

                   while(broken == 0) {

                       elapsed = stopwatch.Elapsed;

                       minutes = (int)elapsed.TotalMinutes;

                       fsec = 60 * (elapsed.TotalMinutes – minutes); //double

                       sec = (int)fsec;

                       tsOut = String.Format("{0}:{1:D2}", minutes, sec);

                       Console.Write("r{0}", tsOut);

                       start = DateTime.Now;

                           while (start.AddSeconds(1) >= DateTime.Now) //it runs for a second


                               CallNextHookEx(_hookID, nCode, wParam, lParam);

                               vkCode = Marshal.ReadInt32(lParam);

                               if ((Keys)vkCode == Keys.End)

                                   broken = 1;




                   CallNextHookEx(_hookID, nCode, wParam, lParam);


               if ((Keys)vkCode == Keys.End)





           return CallNextHookEx(_hookID, nCode, wParam, lParam);


    Would you help me with this?

  190. can you gave the sample program sir of Low-Level Keyboard hook says:

    can you gave the sample program sir of Low-Level Keyboard hook

    it gonna help me a lot in my study

    just send me please.. g.jhonmichael@gmail.com

    thanks you sir….:D

  191. Lenny says:

    Hi, with this code how can I hook an USB barcode reader knowing its HID?.



  192. per says:

    having same prob as you reg. ll keyb proc on excel2013, saw your posting on the guy with word2013 prob's, you asked for some help, did you get any answer? my mail is permortenjensen@hotmail.com

  193. Parimal Bhavsar says:

    I need one help. i am running application in minized mode and override wndproce() method to capture all windows message.now problem start i do not get windows message when i double click on same application. can u help to figure out it.

  194. Its working perfectly I changed it according to my application perspective. but the problem is when window is logged off and my application is still running behing (via thread) it stopped recording key strokes.

  195. Sarah says:

    Why I fail to read the barcodes that created by this barcode solution(http://www.barcodelib.com/csharp)? Is this the barcode quiet zone setting issue?

  196. Shilpa says:

    i have a tool where in i will have to lock the computer if the computer is left idle for 10min while the tool is still running.

    Please help asap…

    Thanks in advance!

  197. Parul says:

    Can anyone help ? how to host wcf service in windows service which does keystroke logged and saves it to a file.

  198. LdRH says:

    Thank u very much Steph, u're an angel and u'll change the world!!!

  199. Mohammad Hossein says:


    thank u so much ^_^

    you helped me to run it in windows form application 🙂

    it works 😉

  200. toroto says:

    thanks for sharing this valuable code…

  201. Sj says:

    Canany one help me with hooking DOUBLE tap

  202. Default says:

    Hello! How I can it ?

    switch ((Keys)vkCode)


    case (Keys.C == (Keys)vkCode && Keys.Control == Control.ModifierKeys):

    Console.WriteLine("CTRL+C: {0}",(Keys)vkCode);


    case (Keys.V == (Keys)vkCode && Keys.Control == Control.ModifierKeys):

    Console.WriteLine("CTRL+V: {0}",(Keys)vkCode);



  203. Nice. Is it possible to disable a key's default application based or global windows based action totally? says:

    I am using the mute key to switch the keyboard to a different language. Is it possible to make the mute key do only this thing without disabling the sound? Thanks.

Comments are closed.

Skip to main content