Office Addin 2013中的C#全局键盘钩子

我遇到了一个问题,使我的Office Addin可以在Powerpoint 2013上使用我的全局键盘,但在以前的版本(2007和2010)上不能使用。
我没有得到任何exception,但似乎在Powerpoint 2013从来没有触发OnKeyDown事件,我不知道为什么。

在所有版本的Windows(XP,7,8和8.1),32位和64位环境下,我都遇到同样的问题。 Microsoft Office的版本是32位。

这是一个代码示例:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Linq; using PowerPoint = Microsoft.Office.Interop.PowerPoint; using Office = Microsoft.Office.Core; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Diagnostics; namespace testHook { public partial class ThisAddIn { Hook hook; private void ThisAddIn_Startup(object sender, System.EventArgs e) { hook = new Hook(Hook.HookType.KeyBoard, Hook.HookVisibility.Global); hook.OnKeyDown += new KeyEventHandler(hook_OnKeyDown); hook.Start(); } void hook_OnKeyDown(object sender, KeyEventArgs e) { MessageBox.Show(e.KeyCode.ToString()); } private void ThisAddIn_Shutdown(object sender, System.EventArgs e) { hook.Stop(); hook = null; } #region VSTO generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InternalStartup() { this.Startup += new System.EventHandler(ThisAddIn_Startup); this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown); } #endregion class Hook { private IntPtr m_Hook = (IntPtr)0; private HookVisibility m_Visibility; private HookType m_HookType; private HookProc m_Proc; public enum HookType { KeyBoard }; public enum KeyBoardEventType { KeyDown, KeyUp, SysKeyDown, SysKeyUp, KeyShift, KeyCapital, NumLock }; public enum HookVisibility { Global, Local }; private delegate IntPtr HookProc(int nCode, int wParam, IntPtr lParam); private KeyPressEventHandler m_onKeyPress; private KeyEventHandler m_onKeyUp; private KeyEventHandler m_onKeyDown; public event KeyPressEventHandler OnKeyPress { add { m_onKeyPress += value; } remove { m_onKeyPress -= value; } } public event KeyEventHandler OnKeyUp { add { m_onKeyUp += value; } remove { m_onKeyUp -= value; } } public event KeyEventHandler OnKeyDown { add { m_onKeyDown += value; } remove { m_onKeyDown -= value; } } #region DLLImport [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hmod, int dwThreadId); [DllImport("user32.dll")] private static extern IntPtr CallNextHookEx(IntPtr hHook, int nCode, IntPtr wParam, IntPtr lParam); [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)] private static extern bool UnhookWindowsHookEx(IntPtr hHook); [DllImport("Kernel32.dll", SetLastError = true)] private static extern IntPtr GetModuleHandle(IntPtr lpModuleName); [DllImport("Kernel32.dll", SetLastError = true)] private static extern IntPtr GetModuleHandle(String lpModuleName); [DllImport("Kernel32.dll")] private static extern IntPtr GetCurrentThreadId(); [DllImport("user32")] private static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState); [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] private static extern short GetKeyState(int vKey); [DllImport("user32")] private static extern int GetKeyboardState(byte[] pbKeyState); #endregion [StructLayout(LayoutKind.Sequential)] private class KeyboardHookStruct { public int vkCode; public int scanCode; public int flags; public int time; public int dwExtraInfo; } public Hook(HookType H, HookVisibility H2) { m_HookType = H; m_Visibility = H2; } public bool Start() { if (m_HookType == HookType.KeyBoard) m_Proc = new HookProc(KeyProc); if (m_Visibility == HookVisibility.Global) m_Hook = SetWindowsHookEx(getHookType(m_HookType, m_Visibility), m_Proc, GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0); else if (m_Visibility == HookVisibility.Local) m_Hook = SetWindowsHookEx(getHookType(m_HookType, m_Visibility), m_Proc, GetModuleHandle((IntPtr)0), (int)GetCurrentThreadId()); if (m_Hook == (IntPtr)0) return false; return true; } public bool Stop() { return UnhookWindowsHookEx(m_Hook); } private int getHookType(HookType H, HookVisibility V) { if (H == HookType.KeyBoard && V == HookVisibility.Local) return 2; if (H == HookType.KeyBoard && V == HookVisibility.Global) return 13; else return -1; } private int getKeyBoardEventType(KeyBoardEventType K) { if (K == KeyBoardEventType.KeyDown) return 0x100; if (K == KeyBoardEventType.KeyUp) return 0x101; if (K == KeyBoardEventType.SysKeyDown) return 0x104; if (K == KeyBoardEventType.SysKeyUp) return 0x105; if (K == KeyBoardEventType.KeyShift) return 0x10; if (K == KeyBoardEventType.KeyCapital) return 0x14; if (K == KeyBoardEventType.NumLock) return 0x90; else return -1; } private IntPtr KeyProc(int nCode, int wParam, IntPtr lParam) { bool handled = false; if ((nCode >= 0) && (m_onKeyDown != null || m_onKeyUp != null || m_onKeyPress != null)) { KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); if (m_onKeyDown != null && (wParam == 0x100 || wParam == 0x104)) { Keys keyData = (Keys)MyKeyboardHookStruct.vkCode; KeyEventArgs e = new KeyEventArgs(keyData); m_onKeyDown(this, e); handled = handled || e.Handled; } if (m_onKeyPress != null && wParam == 0x100) { bool isShift = ((GetKeyState(0x10) & 0x80) == 0x80 ? true : false); bool isCapslock = (GetKeyState(0x14) != 0 ? true : false); byte[] keyState = new byte[256]; GetKeyboardState(keyState); byte[] inBuffer = new byte[2]; if (ToAscii(MyKeyboardHookStruct.vkCode, MyKeyboardHookStruct.scanCode, keyState, inBuffer, MyKeyboardHookStruct.flags) == 1) { char key = (char)inBuffer[0]; if ((isCapslock ^ isShift) && Char.IsLetter(key)) key = Char.ToUpper(key); KeyPressEventArgs e = new KeyPressEventArgs(key); m_onKeyPress(this, e); handled = handled || e.Handled; } } if (m_onKeyUp != null && (wParam == 0x101 || wParam == 0x105)) { Keys keyData = (Keys)MyKeyboardHookStruct.vkCode; KeyEventArgs e = new KeyEventArgs(keyData); m_onKeyUp(this, e); handled = handled || e.Handled; } } if (handled) return (IntPtr)1; else return CallNextHookEx(m_Hook, nCode, (IntPtr)wParam, (IntPtr)lParam); } } } 

我的应用程序需要在幻灯片放映过程中触发事件,因为我有一些其他的窗口在演示过程中显示,而且我必须根据用户按下的按键来更新它们。 我已经尝试了很多解决scheme,但是钩子是唯一能够完成这项工作的人。

我尝试了一个本地键盘钩子而不是全局的键盘钩子。 我实际上认为这是实现它的唯一方法,因为这是来自Microsoft的错误,而不是代码。 但是,我无法使本地的任何版本的Powerpoint正常工作。

Solutions Collecting From Web of "Office Addin 2013中的C#全局键盘钩子"

问题不是Powerpoint特定的,它与任何Office产品一起使用。 我正在研究一个Outlook插件并解决这个问题。 据报道(没有任何回答不幸)微软: https : //social.msdn.microsoft.com/Forums/office/en-US/93d08ccc-9e77-4f72-9c51-477468d89681/keyboardhook-will-not-work -in-字2013?论坛= worddev

我已经能够做出“解决方法”:我已经注册了全局钩子和本地钩子(“线程”)。 它工作,但keyProc被称为“怪异”,当它是本地的,不尊重记录的参数: – wParam不是WM_ *之一,但直接包含vkCode – lParam无法访问(AccessViolation)据我所知,这是因为一些“ TranslateMessage“处理。

我也调整了您的代码,以便能够捕获ALT组合。

  private bool wParamAlt; private IntPtr KeyProc(int nCode, int wParam, IntPtr lParam) { bool handled = false; if ((nCode == 0) && (m_onKeyDown != null || m_onKeyUp != null || m_onKeyPress != null)) { KeyboardHookStruct MyKeyboardHookStruct; if (wParam >= 0x100) { MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); wParamAlt = false; } else { MyKeyboardHookStruct = new KeyboardHookStruct(); MyKeyboardHookStruct.vkCode = wParam; if (wParamAlt) { wParamAlt = (wParam == 18); wParam = 0x104; } else { wParamAlt = (wParam == 18); wParam = 0x100; } } if (m_onKeyDown != null && (wParam == 0x100 || wParam == 0x104)) { Keys keyData = (Keys)MyKeyboardHookStruct.vkCode; if (wParam == 0x104) keyData |= Keys.Alt; KeyEventArgs e = new KeyEventArgs(keyData); m_onKeyDown(this, e); handled = handled || e.Handled; } if (m_onKeyPress != null && wParam == 0x100) { bool isShift = ((GetKeyState(0x10) & 0x80) == 0x80 ? true : false); bool isCapslock = (GetKeyState(0x14) != 0 ? true : false); byte[] keyState = new byte[256]; GetKeyboardState(keyState); byte[] inBuffer = new byte[2]; if (ToAscii(MyKeyboardHookStruct.vkCode, MyKeyboardHookStruct.scanCode, keyState, inBuffer, MyKeyboardHookStruct.flags) == 1) { char key = (char)inBuffer[0]; if ((isCapslock ^ isShift) && Char.IsLetter(key)) key = Char.ToUpper(key); KeyPressEventArgs e = new KeyPressEventArgs(key); m_onKeyPress(this, e); handled = handled || e.Handled; } } if (m_onKeyUp != null && (wParam == 0x101 || wParam == 0x105)) { Keys keyData = (Keys)MyKeyboardHookStruct.vkCode; if (wParam == 0x105) keyData |= Keys.Alt; KeyEventArgs e = new KeyEventArgs(keyData); m_onKeyUp(this, e); handled = handled || e.Handled; } } if (handled) return (IntPtr)1; else return CallNextHookEx(m_Hook, nCode, (IntPtr)wParam, (IntPtr)lParam); }