I am using Keyboard Low Level hooks in a desktop application to monitor user activity. Code i am using for hooks is give below.
In this code (upto my knowledge) when I have to start monitoring user activity I call SetHook() this will install hook and I can monitor keys pressed on keyboard. When I want to stop capturing keys i just call UnHook() method.
Problem is when my application starts (SetHook() method is not called yet) my application install hooks automatically and it slows down system. System hangs for for 2-3 seconds every 1 mint.
To diagnose the problem I commented out all the below mentioned code and installed application. Now system works absolutely fine.
I am not sure why is this happening?
Why my application start capturing keys even I did not called SetHook() method yet?
Is there is any other way to capture global keys without using hooks?
Code for Hooks:
public static class WinKeyCapture5 {
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
public static DateTime LastKeyPressTime;
public static void SetHook()
{
SetHook(_proc);
}
public static void UnHook()
{
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 static IntPtr _hookID = IntPtr.Zero;
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);
//if (vkCode == 44)
//ScreenCapture.Load();
LastKeyPressTime = System.DateTime.Now;
//}
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);
}
Related
I'm experimenting with keyboard events and what you can do with them and I've found alot of tutorials and open source libraries to listen for keyboard events in other processes. I came up with the idea to create a simple 'hack' to lock the computer and then listen for the keyboard events. I figured I could force the user to input their password to unlock their computer and then I would've listened to the user input and thus obtaining the password specified. Here is the simple sample code I found on the internet which will listen for global keyboard events:
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);
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)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode);
}
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);
}
This works out quiet well, but for some reason there seems to be a exception when listening to keyboard inputs when the computer is locked? I'm not sure why it doesn't work, perhaps it's a security thing. Anyways it would be awesome if one could do this.
If this is on Windows, the locked screen is actually a different Window Station and is not owned by the interactive user, so therefore the interactive user cannot interact with it in any way (as a security measure). To interact with the lock screen, and logon in general, take a look at creating a Credential Provider
I found a way to capture the Print Screen button in C#. When pressing Alt + Print Screen a simple messagebox pops up saying the keys have been pressed. But it's unresponsive for a couple of seconds right after. I have no idea why this is happening.
Here's the code I use:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
_hookID = SetHook(_proc);
Application.Run(new Form1());
UnhookWindowsHookEx(_hookID);
}
/****************************************/
private const int WH_KEYBOARD_LL = 13;
//private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private const int VK_F1 = 0x70;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
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)
{
Keys number = (Keys)Marshal.ReadInt32(lParam);
if (number == Keys.PrintScreen)
{
if ((wParam == (IntPtr)260 && Keys.Alt == Control.ModifierKeys && number == Keys.PrintScreen))
{
MessageBox.Show("You pressed alt+ print screen");
}
}
}
return CallNextHookEx(IntPtr.Zero, 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);
}
Does anyone have a clue why it's hanging after the messagebox?
Windows cannot dispatch the next keyboard message until the hook callback finished executing. Clearly you do not want to use MessageBox.Show(), that blocks the callback. Windows puts up with that for several seconds before it declares your code broken and disables the hook.
Use Debug.Print() instead.
I made a simple hook keyboard in C#, so i have this following code :
private static IntPtr hKeyboardHook = IntPtr.Zero;
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x100;
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr 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, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
private static extern int UnhookWindowsHookEx(IntPtr idHook);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32")]
private static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState);
[DllImport("user32")]
private static extern int GetKeyboardState(byte[] pbKeyState);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern short GetKeyState(int vKey);
private delegate int HookProc(int nCode, int wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
public static extern IntPtr GetModuleHandle(string lpModuleName);
private static LowLevelKeyboardProc _proc = HookCallback;
public void initialization()
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
if (vkCode >= 32 && vkCode < 160)
Console.Write((Keys)vkCode);
if (vkCode == 13)
Console.WriteLine("\n");
}
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
It works fine with no problem !! my program grip all key pressed in other program and write it on the console.
But i want to have the name of the program where the key is pressed, and i don't know how i can do that.
Anyone can help me ?
You are using a low-level hook (WH_KEYBOARD_LL). Low-level hooks are dispatched before the window manager decides which program will receive the message. Therefore, there is no "name of the program where the key is pressed" because the window manager hasn't yet decided which program the keypress will be delivered to. (You can try to guess by calling GetForegroundWindow.)
(Just curious: What is the ultimate problem you're trying to solve by using a keyboard hook? Maybe there's a better way. I hope you're not writing a keylogger.)
I am developing an application that needs to handle all messages sent by the OS to any application.
The code works fine for WH_KEYBOARD_LL only, but fails with WH_GETMESSAGE or WH_CALLWNDPROC
class Program
{
private const int WH_KEYBOARD_LL = 13;
private const int WH_GETMESSAGE = 3;
private const int WH_CALLWNDPROC = 4;
private const int WM_KEYDOWN = 0x0100;
private static HookProc _proc = new HookProc(HookCallback);
private static IntPtr _hookID = IntPtr.Zero;
static void Main(string[] args)
{
TextWriter tw = new StreamWriter("date.txt");
tw.Write(DateTime.Now);
tw.Close();
_hookID = SetHook(_proc);
Application.Run();
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(HookProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_CALLWNDPROC , proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int code, IntPtr wParam, IntPtr lParam)
{
// This method is never called
return CallNextHookEx(_hookID, code, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
HookProc 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);
}
}
Edit:
I think the problem is with the .NET Frame work
Global hooks are not supported in the .NET Framework
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.
http://support.microsoft.com/kb/318804
why are you passing curModule.ModuleName into the winapi ?
According to http://support.microsoft.com/kb/318804, you can't do global hooks in .NET (except for WH_KEYBOARD_LL). See the information at the end of that article.
I need to be able to detect that the shift key is being held, but I don't want to use events or global variables to determine that. Is there an API in C# that lets you ask what keys are currently pressed instead of using the event?
if ((Control.ModifierKeys & Keys.Shift) != 0)
This will also be true if another modifier key is also down (eg, Ctrl+Shift). If you want to check whether Shift alone is pressed without any other modifiers, use
if (Control.ModifierKeys == Keys.Shift)
Note that even this will be true if another non-modifier is down (Eg, Shift+A). If you want to check whether Shift and only Shift is pressed, you'll have to use an API call.
If you're in a class that inherits Control (such as a form), you can remove the Control qualifier. (static properties don't need qualifiers in inherited classes)
Form.ModifierKeys
(static property)
You can install a low-level keyboard hook.
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);
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)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine((Keys)vkCode);
}
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);
}
Not sure if this available in C# but you can call GetAsyncKeyState. This method returns the state of a key at the time the method is called.
To call it from C# you'll need to use interop like any other Win32 API.