2011-12-17 37 views
0

我正在编写媒体应用程序,我希望它可以与标准Media Center远程一起使用。 箭头键,下一步和输入工作正常(和其他人,我敢肯定,但这就是我正在使用),但播放和暂停不起作用。我使用WH_KEYBOARD_LL事件的全局钩子捕获其他键。用于全局捕获Media Center远程特殊键的C#API

当按下“播放”或“暂停”(不要与媒体键盘上的播放/暂停...混淆)时,没有事件,它似乎不使用键盘事件。

C#中是否存在一个标准的方法来全局捕获这些按钮?

更新:

下面是我使用的钩子代码:

using System; 
using System.Diagnostics; 
using System.Runtime.CompilerServices; 
using System.Runtime.InteropServices; 
using System.Windows.Input; 

namespace Elpis.KeyboardHook 
{ 
    /// <summary> 
    /// Listens keyboard globally. 
    /// 
    /// <remarks>Uses WH_KEYBOARD_LL.</remarks> 
    /// </summary> 
    public class KeyboardListener : IDisposable 
    { 
     /// <summary> 
     /// Creates global keyboard listener. 
     /// </summary> 
     public KeyboardListener() 
     { 
      // We have to store the HookCallback, so that it is not garbage collected runtime 
      hookedLowLevelKeyboardProc = LowLevelKeyboardProc; 

      // Set the hook 
      hookId = InterceptKeys.SetHook(hookedLowLevelKeyboardProc); 

      // Assign the asynchronous callback event 
      hookedKeyboardCallbackAsync = KeyboardListener_KeyboardCallbackAsync; 
     } 

     #region IDisposable Members 

     /// <summary> 
     /// Disposes the hook. 
     /// <remarks>This call is required as it calls the UnhookWindowsHookEx.</remarks> 
     /// </summary> 
     public void Dispose() 
     { 
      InterceptKeys.UnhookWindowsHookEx(hookId); 
     } 

     #endregion 

     /// <summary> 
     /// Destroys global keyboard listener. 
     /// </summary> 
     ~KeyboardListener() 
     { 
      Dispose(); 
     } 

     /// <summary> 
     /// Fired when any of the keys is pressed down. 
     /// </summary> 
     public event RawKeyEventHandler KeyDown; 

     /// <summary> 
     /// Fired when any of the keys is released. 
     /// </summary> 
     public event RawKeyEventHandler KeyUp; 

     #region Inner workings 

     /// <summary> 
     /// Hook ID 
     /// </summary> 
     private readonly IntPtr hookId = IntPtr.Zero; 

     /// <summary> 
     /// Event to be invoked asynchronously (BeginInvoke) each time key is pressed. 
     /// </summary> 
     private readonly KeyboardCallbackAsync hookedKeyboardCallbackAsync; 

     /// <summary> 
     /// Contains the hooked callback in runtime. 
     /// </summary> 
     private readonly InterceptKeys.LowLevelKeyboardProc hookedLowLevelKeyboardProc; 

     /// <summary> 
     /// Actual callback hook. 
     /// 
     /// <remarks>Calls asynchronously the asyncCallback.</remarks> 
     /// </summary> 
     /// <param name="nCode"></param> 
     /// <param name="wParam"></param> 
     /// <param name="lParam"></param> 
     /// <returns></returns> 
     [MethodImpl(MethodImplOptions.NoInlining)] 
     private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam) 
     { 
      if (nCode >= 0) 
       if (wParam.ToUInt32() == (int) InterceptKeys.KeyEvent.WM_KEYDOWN || 
        wParam.ToUInt32() == (int) InterceptKeys.KeyEvent.WM_KEYUP || 
        wParam.ToUInt32() == (int) InterceptKeys.KeyEvent.WM_SYSKEYDOWN || 
        wParam.ToUInt32() == (int) InterceptKeys.KeyEvent.WM_SYSKEYUP) 
        hookedKeyboardCallbackAsync.BeginInvoke((InterceptKeys.KeyEvent) wParam.ToUInt32(), 
                  Marshal.ReadInt32(lParam), null, null); 

      return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam); 
     } 

     /// <summary> 
     /// HookCallbackAsync procedure that calls accordingly the KeyDown or KeyUp events. 
     /// </summary> 
     /// <param name="keyEvent">Keyboard event</param> 
     /// <param name="vkCode">VKCode</param> 
     private void KeyboardListener_KeyboardCallbackAsync(InterceptKeys.KeyEvent keyEvent, int vkCode) 
     { 
      switch (keyEvent) 
      { 
        // KeyDown events 
       case InterceptKeys.KeyEvent.WM_KEYDOWN: 
        if (KeyDown != null) 
         KeyDown(this, new RawKeyEventArgs(vkCode, false)); 
        break; 
       case InterceptKeys.KeyEvent.WM_SYSKEYDOWN: 
        if (KeyDown != null) 
         KeyDown(this, new RawKeyEventArgs(vkCode, true)); 
        break; 

        // KeyUp events 
       case InterceptKeys.KeyEvent.WM_KEYUP: 
        if (KeyUp != null) 
         KeyUp(this, new RawKeyEventArgs(vkCode, false)); 
        break; 
       case InterceptKeys.KeyEvent.WM_SYSKEYUP: 
        if (KeyUp != null) 
         KeyUp(this, new RawKeyEventArgs(vkCode, true)); 
        break; 
      } 
     } 

     private delegate void KeyboardCallbackAsync(InterceptKeys.KeyEvent keyEvent, int vkCode); 

     #endregion 
    } 

    /// <summary> 
    /// Raw KeyEvent arguments. 
    /// </summary> 
    public class RawKeyEventArgs : EventArgs 
    { 
     /// <summary> 
     /// Is the hitted key system key. 
     /// </summary> 
     public bool IsSysKey; 

     /// <summary> 
     /// WPF Key of the key. 
     /// </summary> 
     public Key Key; 

     /// <summary> 
     /// VKCode of the key. 
     /// </summary> 
     public int VKCode; 

     /// <summary> 
     /// Create raw keyevent arguments. 
     /// </summary> 
     /// <param name="VKCode"></param> 
     /// <param name="isSysKey"></param> 
     public RawKeyEventArgs(int VKCode, bool isSysKey) 
     { 
      this.VKCode = VKCode; 
      IsSysKey = isSysKey; 
      Key = KeyInterop.KeyFromVirtualKey(VKCode); 
     } 
    } 

    /// <summary> 
    /// Raw keyevent handler. 
    /// </summary> 
    /// <param name="sender">sender</param> 
    /// <param name="args">raw keyevent arguments</param> 
    public delegate void RawKeyEventHandler(object sender, RawKeyEventArgs args); 

    #region WINAPI Helper class 

    /// <summary> 
    /// Winapi Key interception helper class. 
    /// </summary> 
    internal static class InterceptKeys 
    { 
     #region Delegates 

     public delegate IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam); 

     #endregion 

     #region KeyEvent enum 

     public enum KeyEvent 
     { 
      WM_KEYDOWN = 256, 
      WM_KEYUP = 257, 
      WM_SYSKEYUP = 261, 
      WM_SYSKEYDOWN = 260 
     } 

     #endregion 

     public static int WH_KEYBOARD_LL = 13; 

     public static IntPtr SetHook(LowLevelKeyboardProc proc) 
     { 
      using (Process curProcess = Process.GetCurrentProcess()) 
      using (ProcessModule curModule = curProcess.MainModule) 
      { 
       return SetWindowsHookEx(WH_KEYBOARD_LL, proc, 
             GetModuleHandle(curModule.ModuleName), 0); 
      } 
     } 

     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId); 

     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     public static extern bool UnhookWindowsHookEx(IntPtr hhk); 

     [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, UIntPtr wParam, IntPtr lParam); 

     [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     public static extern IntPtr GetModuleHandle(string lpModuleName); 
    } 

    #endregion 
} 

回答

0

编辑:它看起来像在你的代码贴出您过滤以只重点起来关键事件:

private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam) 
    { 
     if (nCode >= 0) 
      if (wParam.ToUInt32() == (int) InterceptKeys.KeyEvent.WM_KEYDOWN || 
       wParam.ToUInt32() == (int) InterceptKeys.KeyEvent.WM_KEYUP || 
       wParam.ToUInt32() == (int) InterceptKeys.KeyEvent.WM_SYSKEYDOWN || 
       wParam.ToUInt32() == (int) InterceptKeys.KeyEvent.WM_SYSKEYUP) 
       hookedKeyboardCallbackAsync.BeginInvoke((InterceptKeys.KeyEvent) wParam.ToUInt32(), 
                 Marshal.ReadInt32(lParam), null, null); 

当您删除内部if语句时会发生什么?

private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam) 
    { 
     if (nCode >= 0) 
      hookedKeyboardCallbackAsync.BeginInvoke((InterceptKeys.KeyEvent) wParam.ToUInt32(), 
                Marshal.ReadInt32(lParam), null, null); 

根据this article播放相当于按Ctrl + Shift + P和暂停相当于按Ctrl + P。你能详细说明你所看到的吗?也许提供一些代码会有所帮助。

+0

我会尽力...用Code检查更新后的问题。 – 2011-12-17 05:19:36