Recently I came across a problem where a customer was looking for the ways to call a function in an VSTO office add-in using keyboard shortcuts. Since I could not find good documentation on it, I decided to document my findings.
One can implement these in following ways:
1. Use KeyBindings
2. Hook the main window and trap the key combinations to launch custom functions.
Using KeyBindings
KeyBindings can be used to assign keyboard shortcuts to macros. Then macros can be used to call the function in managed add-in. I found following are few useful links which talk about the VSTO-VBA integration.
VSTO VBA integration: http://msdn.microsoft.com/en-us/magazine/cc163373.aspx
Calling VSTO code from VBA: http://msdn.microsoft.com/en-us/office/cc178910.aspx
KeyBindings Collection: http://msdn.microsoft.com/en-us/library/bb211991(v=office.12).aspx.
Using Keyboard Hook
This can also be achieved using Windows Hooks(http://msdn.microsoft.com/en-us/library/ms997537.aspx)
Following is a sample class which traps Ctrl+1 keys and writes "A" in A4 cell in Excel (I used this class in a VSTO Excel addin project). This class uses local hook to trap Ctrl+1 keys. It can be used to set hook (by calling its SetHook function), release hook (by calling its ReleaseHook function).
using
System;using
System.Diagnostics;using
System.Windows.Forms;using
System.Runtime.InteropServices;using
Microsoft.Office.Core;using
Microsoft.Office.Interop.Excel;using
Excel = Microsoft.Office.Interop.Excel;
namespace
Hooking{
publicclassInterceptKeys{
publicdelegateintLowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam); privatestaticLowLevelKeyboardProc _proc = HookCallback; privatestaticIntPtr _hookID = IntPtr.Zero; privatestatic Microsoft.Office.Tools.CustomTaskPane ctpRef = null;//Declare the mouse hook constant. //For other hook types, you can obtain these values from Winuser.h in the Microsoft SDK.
privateconstint WH_KEYBOARD = 2;
privateconstint HC_ACTION = 0;
publicstaticvoid SetHook()
{
_hookID = SetWindowsHookEx(WH_KEYBOARD, _proc, IntPtr.Zero, (uint)AppDomain.GetCurrentThreadId());
}
publicstaticvoid ReleaseHook()
{
UnhookWindowsHookEx(_hookID);
}
privatestaticint HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode < 0)
{
return (int)CallNextHookEx(_hookID, nCode, wParam, lParam);
}
else
{
if (nCode == HC_ACTION){
Keys keyData = (Keys)wParam; if (Functions.IsKeyDown(Keys.ControlKey) && keyData == Keys.D1){
object missing = System.Reflection.Missing.Value;Excel.
Workbook exBook = Excel_CustomTaskPane_ACC.Globals.ThisAddIn.Application.ActiveWorkbook;Excel.
Worksheet exSheet = (Excel.Worksheet)exBook.ActiveSheet;exSheet.get_Range(
"A4", missing).Value2 = "A";}
}
return (int)CallNextHookEx(_hookID, nCode, wParam, lParam);}
}
[
DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] privatestaticexternIntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[
DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)][
return: MarshalAs(UnmanagedType.Bool)] privatestaticexternbool UnhookWindowsHookEx(IntPtr hhk);[
DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] privatestaticexternIntPtr CallNextHookEx(IntPtr hhk, int nCode,IntPtr wParam, IntPtr lParam);}
publicclassFunctions{
publicstaticbool IsKeyDown(Keys keys){
return (GetKeyState((int)keys) & 0x8000) == 0x8000;}
[
DllImport("user32.dll")] staticexternshort GetKeyState(int nVirtKey);}
}