2014-10-16 73 views
2

我遇到了一個問題,使我的Office Addin可以在Powerpoint 2013上使用我的全局鍵盤,但在以前的版本(2007和2010)上不能使用。
我沒有得到任何異常,但似乎從未在Powerpoint 2013上觸發過OnKeyDown事件,我不知道爲什麼。Office Addin 2013中的C#全局鍵盤鉤子

我在所有版本的Windows(XP,7,8 & 8.1),64位32位環境下都遇到同樣的問題。 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); 
     } 
    } 
} 

我的應用程序需要在幻燈片中觸發事件,因爲我有一些其他的窗戶都在演示過程中顯示出來,和我有根據鍵更新他們用戶按下。我已經嘗試了很多解決方案,但鉤子是唯一能夠完成這項工作的人。

我嘗試了一個本地鍵盤鉤而不是全局鍵盤鉤。我實際上認爲這是實現它的唯一方法,因爲它是來自Microsoft的錯誤,而不是來自代碼。但是,我無法讓本地的任何版本的Powerpoint正常工作。

+0

不良的錯誤檢查,返回一個布爾,然後不驗證它,應該是在錯誤列表的頂部。拋出異常,你不能忽視這一點。任何失敗的pinvoke函數的Win32Exception,所以你知道爲什麼。 – 2014-10-16 10:56:57

+0

我不驗證它是因爲它有效,它只是爲了舉例。這是我的問題,鉤子正在工作,但事件從未在Powerpoint 2013上觸發,我不知道爲什麼。我沒有得到你最後一句話,dll不會失敗。 – 2014-10-16 11:46:16

+0

你有這個工作嗎? – TWilly 2015-02-27 20:01:47

回答

2

問題不在於Powerpoint特有,它與任何Office產品一起發生。 我正在研究Outlook插件並解決此問題。 據報道(不含unfortunely任何答案)微軟: https://social.msdn.microsoft.com/Forums/office/en-US/93d08ccc-9e77-4f72-9c51-477468d89681/keyboardhook-will-not-work-in-word-2013?forum=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); 
    } 
+0

這個答案是一個隱藏的寶石。我不應該對評論如此喋喋不休,但你已經贏得了你的讚賞。 – 2017-08-08 17:10:16

+0

thk u!請注意我接受的答案:) – 2017-08-11 15:32:04

+0

只有@Valar Morghulis可以 – 2017-08-15 07:33:24