In some cases we need to hook to Revit to track some keys, for instance the ESCAPE key. This can be done with Win32 APIs with SetWindowsHookEx method. Below is the regular OnStartup and OnShutdown with calls to it.
public Result OnStartup(UIControlledApplication application)
{
// hook
HookMainApp();
return Result.Succeeded;
}
public Result OnShutdown(UIControlledApplication application)
{
// unhook
UnhookMainApp();
return Result.Succeeded;
}
private void KeyPressed(Keys keyPressed)
{
if (keyPressed == Keys.Escape)
{
TaskDialog.Show("Key was pressed", "Escape");
}
}
And to make this work, also include the following methods on the project:
#region "Windows Hook"
// **********
// Code based on the following post
// http://www.pinvoke.net/default.aspx/user32.setwindowshookex
// **********
private void HookMainApp()
{
// initialize our delegate
this.myCallbackDelegate = new HookProc(this.MyCallbackFunction);
// get the process and set up the hook
using (Process process = Process.GetCurrentProcess())
using (ProcessModule module = process.MainModule)
{
hookId = SetWindowsHookEx(HookType.WH_KEYBOARD,
this.myCallbackDelegate, IntPtr.Zero,
(uint)AppDomain.GetCurrentThreadId());
}
}
private void UnhookMainApp()
{
UnhookWindowsHookEx(hookId);
}
private int MyCallbackFunction(int code,
IntPtr wParam, IntPtr lParam)
{
if (code < 0)
{
//you need to call CallNextHookEx without
// further processing and return the value
// returned by CallNextHookEx
return CallNextHookEx(IntPtr.Zero, code,
wParam, lParam);
}
// we can convert the 2nd parameter (the key code)
// to a System.Windows.Forms.Keys enum constant
Keys keyPressed = (Keys)wParam.ToInt32();
KeyPressed(keyPressed);
//return the value returned by CallNextHookEx
return CallNextHookEx(IntPtr.Zero, code,
wParam, lParam);
}
// hook deleate
private HookProc myCallbackDelegate = null;
// hook id for unhook
IntPtr hookId;
[DllImport("user32.dll")]
static extern int CallNextHookEx(IntPtr hhk, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetWindowsHookEx(
HookType hookType, HookProc lpfn, IntPtr hMod,
uint dwThreadId);
public enum HookType : int
{
WH_JOURNALRECORD = 0,
WH_JOURNALPLAYBACK = 1,
WH_KEYBOARD = 2,
WH_GETMESSAGE = 3,
WH_CALLWNDPROC = 4,
WH_CBT = 5,
WH_SYSMSGFILTER = 6,
WH_MOUSE = 7,
WH_HARDWARE = 8,
WH_DEBUG = 9,
WH_SHELL = 10,
WH_FOREGROUNDIDLE = 11,
WH_CALLWNDPROCRET = 12,
WH_KEYBOARD_LL = 13,
WH_MOUSE_LL = 14
}
delegate int HookProc(int code, IntPtr wParam,
IntPtr lParam);
#endregion