Well got everything working on my own (somehow).
Thought I would share what I had.
To do the testing I used "notepad++", but you can change that to whatever .exe you want to hook. Does work with "WoW".
Note: 64-bit applications (including notepad on 64-bit versions of Windows) will not work.
Features:
Low Level Keyboard Hook
Process Specific (Only hooks keys when designated process window is active)
Event Driven
Prevents Auto-Repeat (this can be added easily for rapid fire)
Code:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Diagnostics;
namespace Hook
{
/// <summary>
/// Hooks keyboard input of a specific application
/// <remarks>
/// George Mamaladze: http://www.codeproject.com/KB/cs/globalhook.aspx
/// Stephen Toub: http://blogs.msdn.com/toub/archive/2006/05/03/589423.aspx
/// Eitan Pogrebizsky: http://www.koders.com/csharp/fid6AF179F76C05AF581905FF86477E98F2D4D86622.aspx
/// Michael Schierl: http://mwinapi.sourceforge.net/
/// Richard Carr: http://www.blackwasp.co.uk/GetActiveProcess.aspx
/// Modified by nilum
/// </remarks>
/// </summary>
///
public class KeyboardHook : IDisposable
{
public event KeyEventHandler KeyDown;
public event KeyPressEventHandler KeyPress;
public event KeyEventHandler KeyUp;
public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
public int hKeyboardHook = 0; //Declare keyboard hook handle as int.
private const int WM_KEYDOWN = 0x100;
private const int WM_KEYUP = 0x101;
private const int WM_SYSKEYDOWN = 0x104;
private const int WM_SYSKEYUP = 0x105;
private const uint MASK_KEYDOWN = 0x40000000; // for bit 30
private const uint MASK_KEYUP = 0x80000000; // for bit 31
private const int HC_ACTION = 0; //#define HC_ACTION 0
private const int HC_NOREMOVE = 3; //#define HC_NOREMOVE 3
private const int WH_KEYBOARD_LL = 13;
private readonly HookProc keyboardHook; //Declare KeyboardHookProcedure as HookProc type.
public static Process[] processes = Process.GetProcessesByName("notepad++");
public KeyboardHook()
{
keyboardHook = new HookProc(keyboardHookProc);
Start();
}
~KeyboardHook()
{
Stop();
}
/// <summary>
/// Unhooks the hook if necessary.
/// </summary>
public void Dispose()
{
Stop();
}
public void Start()
{
// install Keyboard hook
if (hKeyboardHook == 0)
{
IntPtr keyboardHookPointer = Marshal.GetFunctionPointerForDelegate(keyboardHook);
hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,
keyboardHookPointer,
GetModuleHandle((processes[0].MainModule).ModuleName),
0);
//If SetWindowsHookEx fails.
if (hKeyboardHook == 0)
{
Win32Exception ex = new Win32Exception(Marshal.GetLastWin32Error());
//Settings.Instance.Logger.Log(LogLevelType.ErrorsOnly, ex, "Installing keyboard hook failed.");
Stop();
throw ex;
}
}
}
public void Stop()
{
bool retKeyboard = true;
if (hKeyboardHook != 0)
{
retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
hKeyboardHook = 0;
}
//If UnhookWindowsHookEx fails.
if (!(retKeyboard))
{
//Settings.Instance.Logger.Log(LogLevelType.ErrorsOnly, "UnhookWindowsHookEx failed.");
throw new Exception("UnhookWindowsHookEx failed.");
}
}
//Declare wrapper managed KeyboardHookStruct class.
[StructLayout(LayoutKind.Sequential)]
public class KeyboardHookStruct
{
public int vkCode; //Specifies a virtual-key code. The code must be a value in the range 1 to 254.
public int scanCode; // Specifies a hardware scan code for the key.
public int flags; // Specifies the extended-key flag, event-injected flag, context code, and transition-state flag.
public int time; // Specifies the time stamp for this message.
public int dwExtraInfo; // Specifies extra information associated with the message.
}
private int keyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
if ((nCode >= 0) &&
(nCode != HC_NOREMOVE) &&
(KeyDown != null || KeyUp != null || KeyPress != null) &&
(GetActiveProcess().Id == processes[0].Id)) //Makes sure the Actice Process is the process we want to receive input from
{
KeyboardHookStruct keyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(
lParam, typeof(KeyboardHookStruct));
Keys keyData = (Keys)keyboardHookStruct.vkCode;
/*
if (Keys.Control != keyData && Keys.Alt != keyData && Keys.Shift != keyData) {
// Add in modifier key.
keyData |= Control.ModifierKeys;
}
*/
KeyEventArgs e = new KeyEventArgs(keyData);
// Raise KeyDown.
if (KeyDown != null && (wParam.ToInt32() == WM_KEYDOWN || wParam.ToInt32() == WM_SYSKEYDOWN))
{
KeyDown(this, e);
}
// Raise KeyUp.
if (KeyUp != null && (wParam.ToInt32() == WM_KEYUP || wParam.ToInt32() == WM_SYSKEYUP))
{
KeyUp(this, e);
}
}
return CallNextHookEx(hKeyboardHook, nCode, wParam, (IntPtr)lParam);
}
private static Process GetActiveProcess()
{
IntPtr hwnd = GetForegroundWindow();
return hwnd != null ? GetProcessByHandle(hwnd) : null;
}
private static Process GetProcessByHandle(IntPtr hwnd)
{
try
{
uint processID;
GetWindowThreadProcessId(hwnd, out processID);
return Process.GetProcessById((int)processID);
}
catch { return null; }
}
//Import for SetWindowsHookEx function.
//Use this function to install a hook.
[DllImport("user32.dll", SetLastError = true)]
public static extern int SetWindowsHookEx(int idHook, IntPtr callback, IntPtr hInstance, uint threadId);
//Import for UnhookWindowsHookEx.
//Call this function to uninstall the hook.
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
//Import for CallNextHookEx.
//Use this function to pass the hook information to next hook procedure in chain.
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
//Needed to get the Active Window (Window ready to receive user input)
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr GetForegroundWindow();
//Needed to get the Process ID of the Active Window
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern Int32 GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
}
}
Implementation:
Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Hook
{
public partial class MainForm : Form
{
KeyboardHook keyHook = new KeyboardHook();
public MainForm()
{
InitializeComponent();
keyHook.KeyDown += new KeyEventHandler(keyHook_KeyDown);
keyHook.KeyPress += new KeyPressEventHandler(keyHook_KeyPress);
keyHook.KeyUp += new KeyEventHandler(keyHook_KeyUp);
}
private void keyHook_KeyDown(object sender, KeyEventArgs e)
{
label1.Text = e.KeyData.ToString();
}
private void keyHook_KeyUp(object sender, KeyEventArgs e)
{
label2.Text = e.KeyData.ToString();
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if (keyHook.hKeyboardHook != 0)
{
keyHook.Stop();
checkBox1.Text = "Hook";
}
else if (keyHook.hKeyboardHook == 0)
{
keyHook.Start();
checkBox1.Text = "Unhook";
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (keyHook.hKeyboardHook != 0)
{
keyHook.Stop();
}
}
}
}
I plan on adding mouse support eventually.
Hope this is helpful to someone.