Click here to Skip to main content
Email Password   helpLost your password?

Introduction

This class allows you to tap keyboard and mouse and/or to detect their activity even when an application runs in the background or does not have any user interface at all. This class raises common .NET events with KeyEventArgs and MouseEventArgs, so you can easily retrieve any information you need.

Background

There are a number of applications that run in the background and detect user inactivity to change their mode. For example, MSN Messenger (or any other messenger). I was going to write such an application, so I searched MSDN and found "exactly" what I needed: 318804 - HOW TO: Set a Windows Hook in Visual C# .NET. This article describes how to tap the mouse movement, but it works only when an application is active. At the end of this article, I found this explanation: "Global hook is not supported in .NET Framework. You cannot implement global hooks in Microsoft .NET Framework...". Anyway, I continued my research and found out that there are exceptions. There are WH_KEYBOARD_LL and WH_MOUSE_LL hooks that can be installed globally. So, I have basically replaced WH_MOUSE with WH_MOUSE_LL in the MSDN example, and it works.

The second step was to extract the information received into a .NET EventArgs and raise the appropriate events.

I found a similar article in CodeProject, under Global System Hooks in .NET by Michael Kennedy, but what I dislike is, there is an unmanaged DLL in C++ that is a main part of this solution. This unmanaged DLL is in C++, and a number of classes make it complicated to integrate it in my own tiny application.

Revisions

This article was posted in 2004 and updated in 2006. During all this time until now I receive a lot of positive feedback and recommendations. There were also a number of technology improvements like .NET Framework 3.5 or Visual Studio 2008. So I have decided to update it once more.

I have refactored and improved the solution, made it more flexible, stable and efficient. But this refactoring also had some drawbacks:

  1. Number of code lines and files has grown.
  2. Backward compatibility to older .NETs is lost.

That's why I attend to leave the old version also to be available for download.

Using the Code [Version 2]

The Simple Way

If you are developing a Windows Forms application and prefer drag & drop programming, there is a component named GlobalEventProvider inside the assembly Gma.UserActivityMonitor.dll. Just drag and drop it to your form and create events using the property editor events tab.

The Alternative Way

Use events provided by the static class HookManager. Note that the sender object in events is always null.

For more usage hints, see the source code of the attached demo application.

Using the Code [Version 1]

To use this class in your application, you need to just create an instance of it and hang on events you would like to process. Hooks are automatically installed when the object is created, but you can stop and start listening using appropriate public methods.

UserActivityHook actHook;
void MainFormLoad(object sender, System.EventArgs e)
{
    actHook= new UserActivityHook(); // crate an instance

    // hang on events

    actHook.OnMouseActivity+=new MouseEventHandler(MouseMoved);
    actHook.KeyDown+=new KeyEventHandler(MyKeyDown);
    actHook.KeyPress+=new KeyPressEventHandler(MyKeyPress);
    actHook.KeyUp+=new KeyEventHandler(MyKeyUp);
}

Now, an example of how to process an event:

public void MouseMoved(object sender, MouseEventArgs e)
{
    labelMousePosition.Text=String.Format("x={0}  y={1}", e.X, e.Y);
    if (e.Clicks>0) LogWrite("MouseButton     - " + e.Button.ToString());
}

Changes and Updates from [Version 0] to [Version 1]

I'd like to thank you all for all the useful comments in the discussion forum. There were a lot of bugs and proposals posted after this article was published on 4th June, 2004. Over and over again came the same topics, and I had to refer to previous posts in the discussion, that is why I have decided to revise the code and publish a FAQ. Here is the list of the most important changes:

FAQ [Version 1]

Question

The project cannot be run in Visual Studio .NET 2005 in debug mode because of an exception error caused by calling the SetWindowsHookEx. Why? Is it a problem of .NET 2.0?

Answer

The compiled release version works well so that cannot be a .NET 2.0 problem. To workaround, you just need to uncheck the check box in the project properties that says: "Enable Visual Studio hosting process". In the menu: Project -> Project Properties... -> Debug -> Enable the Visual Studio hosting process.

Question

I need to suppress some keystrokes after I have processed them.

Answer

Just set the e.Handled property to true in the key events you have processed. It prevents the keystrokes being processed by other applications.

Question:

Is it possible to convert your global hooks to application hooks which capture keystrokes and mouse movements only within the application?

Answer

Yes. Just use...

private const int WH_MOUSE = 7;
private const int WH_KEYBOARD = 2;

... everywhere, instead of:

private const int WH_MOUSE_LL = 14;
private const int WH_KEYBOARD_LL = 13;

Question

Does it work on Win98 (Windows ME, Windows 95)?

Answer

Yes and No. The global hooks WH_MOUSE_LL and WH_KEYBOARD_LL can be monitored only under Windows NT/2000/XP. In other cases, you can only use application hooks (WH_MOUSE and WH_KEYBOARD) which capture keystrokes and mouse movement only within the application.

Question

I have a long delay when closing applications using hooks by clicking the x button in the titlebar. If I close the application via another event (button click) for example, that works fine.

Answer

It's a known bug of Microsoft. It has to do with the Windows themes. If you disable the Windows themes, the problem goes away. Another choice is to have the hook code run in a secondary thread.

Question

How do I catch key combinations like Ctrl+Shift+A?

Answer

You'll have to track which keys have gone down but not up. Only the most recently pressed key keeps sending KeyDown messages, but the others will still send a KeyUp when released. So if you make three flags IsCtrlDown, IsShiftDown, and IsADown, and set them to true at KeyDown and false at KeyUp, the expression (IsCtrlDown && IsShiftDown && IsADown) will give you the required result.

Question

Does it works with .NET Framework 1.1 and Visual Studio 2003?

Answer

Yes. The file UserActivityHook.cs can be used without any changes, in a Visual Studio 2003 .NET 1.1 project.

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
QuestionIssue with Windows7
pareshvarde
5:54 4 Feb '10  
I have a windows application where I need to monitor the global mouse and keyboard to check user's activeness. Everything was working perfectly until I installed my application on Windows7. It does not throws any error however the mousemove and keydown event not being called. Is there any issue using this DLL in WIndows7?

Please help
GeneralNot working in a windows service
ZanyRocket
0:55 27 Jan '10  
I have added handles to the static events in the HookManager class within the new routine of my own class. However, these events never seem to be raised. My program is a windows service I am making for my school. Other keyboard event monitoring libraries also don't seem to work within a service - I have tried the same code in form based applications and it works fine. Is there any way of making this work in a service?
GeneralRe: Not working in a windows service
xxxtriplex
0:06 29 Jan '10  
i have the same problem please can someone help ? thank you
AnswerRe: Not working in a windows service
George Mamaladze
0:09 29 Jan '10  
There are many post in this forums regarding this issue. It will not work as a windows service and the problem is Windows operating system architecture and the way it handles multipe user sessions.
GeneralRe: Not working in a windows service
xxxtriplex
1:05 29 Jan '10  
ok thank you for your quick response Smile ... and in a windows console application should it work ? thank you
AnswerRe: Not working in a windows service
George Mamaladze
1:17 29 Jan '10  
Yes it should. I think we had here someone already done that.
GeneralRe: Not working in a windows service
xxxtriplex
1:19 29 Jan '10  
do you now where to find any example on that ? or do you have any example ? thank you
GeneralKeyPress Problem
Lucas Luis Baruffi
14:20 26 Jan '10  
when I assing the KeyPress event with my keyboard Portuguese of Brazil, he fires twice, when I press seats, ' shoot twice getting '' or ~ getting ~~ sorry for my bad English: á, ã, â = '' ~~ ^^, but just in my text box or word, excel, web etc.., the event not return the caractere.
GeneralChange Left Click to Double Click?
wizi83
20:43 13 Jan '10  
Hi,
First of all, thank you so much for the wonderful application. I have been looking for this one forever.
I have a question. I want to write an application that allows users change LEFT Click to Double Click everytime they hit a button. If they want to go back to normal, hit "cancel" button.

Does anyone know how i can do that using the library?
Thank you ,
GeneralProblem with SetWindowsHookEx
klobow
7:26 8 Jan '10  
Hi,

First of all thanks for this work!
I've downloaded the source of your v1 solution. Started and compiled with VS05 it worked very fine. But when I copied your file "UserActivityHook.cs" to my own project the function SetWindowsHookEx always returns 0!

The error code returned mostly is 0, one time it was 1008. I used this class:

  class Program : System.Windows.Forms.Form
{
[STAThread]
static void Main(string[] args)
{
Application.Run(new Program());
}

public Program()
{
UserActivityHook hook;
try
{
hook = new UserActivityHook();
hook.KeyDown += new KeyEventHandler(MyKeyDown);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Error: " + ex.Message);
}
}

public void MyKeyDown(object sender, KeyEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Key pressed " + e.KeyData.ToString());
}
}


Sorry I have no other ideas.
Thanks for your help.

Regards,
Tobias
AnswerRe: Problem with SetWindowsHookEx
klobow
8:20 9 Jan '10  
i just have to read the FAQ where you have given the answer:
"...To workaround, you just need to uncheck the check box in the project properties that says: "Enable Visual Studio hosting process". In the menu: Project -> Project Properties... -> Debug -> Enable the Visual Studio hosting process."

Sorry for that and thanks for the work!

Regards Tobias
AnswerRe: Problem with SetWindowsHookEx
George Mamaladze
12:09 9 Jan '10  
Macht nichts, passiert fast Jedem zweiten. Smile
GeneralGlobalHooks in .NET CF for Windows Mobile...
Naresh Mehta
21:56 4 Jan '10  
Hi All,

Check out my post on Globalhooks in .NETCF for Windows Mobile. I hope it helps.

http://www.naresh.se/2009/09/08/getkeyboardstate-mousehooks-not-available-in-windows-mobile/

Yours

Wolverine

visit me at:

http://www.naresh.se/

QuestionGetting the Keyboard Device Info for a Pressed Key Event
active6
11:35 27 Dec '09  
Is it possible to get the device info associated with the pressed key?

That is, like combining this global hook handler with retrieving the Raw Input data as detailed here:

Using Raw Input from C# to handle multiple keyboards[^]

I would like to use a second keyboard as a "macro-keyboard", replacing the pressed key with other key/mouse events, but only when that key is pressed on a specific keyboard.
GeneralWindows Handle to Process ID
rtarquini
8:07 24 Dec '09  
George.. Nice article & thanks for the support

Here is a tidbit for those folks wanting get at the Process information when an event is triggered on a global hook.

uint pid;
int handle = GetForegroundWindow();
IntPtr wHandle = new IntPtr(handle);
GetWindowThreadProcessId(wHandle, out pid);
Process p = Process.GetProcessById((int)pid);
String Text = p.ProcessName; // Application Name

Rich
GeneralHow is keypress event detected
Member 4159175
10:00 20 Dec '09  
Hello George:

Thank you very much for the code! It is very helpful for learning hooks using C#.

I am looking through your source code and trying to figure out how you detect the keypress event.

If I understand correctly, you used the ToAscii() function to determine if a keypress event has had happened. Am I right? I have to say that I don't understand MSDN's documentation on this function so I cannot figure out why you used it for detecting keypress.

Another question I have is about the handled parameter. In the keypress block and keyup block, you wrote

handled = handled || e.Handled;


Instead of

handled = e.Handled;


Could you explain why?

Again, thank you very much for your help!
AnswerAm I just stupid or? Using simple method [SOLVED]
elmernite
6:30 15 Dec '09  
I cannot drag and drop GlobalEventProvider to my form? Does anyone have a step by step. Where do I drag from? Maybe I'm just being thick headed but I cannot find it.

SOLVED: Go here to see how to add items to the toolbox.
http://msdn.microsoft.com/en-us/library/ms165355(VS.80).aspx[^] Thanks to George Mamaladze!
-Elmernite

modified on Tuesday, December 15, 2009 11:53 AM

AnswerRe: Am I just stupid or? Using simple method
George Mamaladze
6:33 15 Dec '09  
ita appairs like other nonvisual components Timer, DataSet etc. not on the form itself but on a special bar under the form at the bottom of the window the form appairs in.
GeneralRe: Am I just stupid or? Using simple method
elmernite
6:42 15 Dec '09  
Thanks for the rapid response, but that's not my problem, The problem is that it is not showing up in my toolbox. I cannot find where the object is to drop into my form.

-Elmernite
AnswerRe: Am I just stupid or? Using simple method
George Mamaladze
6:46 15 Dec '09  
See MSDN How to: Add Items to the Toolbox

http://msdn.microsoft.com/en-us/library/ms165355(VS.80).aspx
AnswerRe: Am I just stupid or? Using simple method
elmernite
6:50 15 Dec '09  
So I guess the answer to my first question would be "Yes, you are just stupid"
It didn't even cross my mind to google how to add items to the toolbox. Thanks for the rapid responses. (You might want to add that link to the article somewhere)

-Elmernite
Generalwin 32 exceptiom
evald80
11:41 13 Dec '09  
hello, on mouse up event i get the i/o overlapped..
what does it mean?
Generaldouble keypress detection
carterlist
12:42 11 Dec '09  
Great work man! Say, how can i detect a double keypress like Google Desktop gets called up each time a user hits CTRL twice in quick succession?
AnswerRe: double keypress detection
George Mamaladze
23:37 13 Dec '09  
Detect the first key press and remember DateTime.Now.
If the second key press is the same key calculate the difference between DateTime.Now and the remembered value.
If the difference is less then the certain value than you have your "double key press"
GeneralHooks is getting stopped automatically after a while in "windiows 7" OS, But its works fine in Vista and XP
prashganth
2:53 9 Dec '09  
Hi george,

refering link :Processing Global Mouse and Keyboard Hooks in C#[^]

i have added "CaptureScreen.CaptureScreen.GetDesktopImage();" as last line of the _keyPress event, the hook is getting stopped automatically after a while in Windows 7 Operating system.


private void HookManager_KeyPress(object sender, KeyPressEventArgs e)
{
textBoxLog.AppendText(string.Format("KeyPress - {0}\n", e.KeyChar));
textBoxLog.ScrollToCaret();
CaptureScreen.CaptureScreen.GetDesktopImage();
}

any luck why this happens?

Note: This works fine on my vista and Xp machine

Best regards
Prasanth.k
prasanthk"at"dsrc"dot"'co"dot".in


Last Updated 12 Nov 2008 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010