2015-12-15 37 views
5

Üzerinde çalıştığım bir medya yürütücüsü uygulamasının bir parçası olarak, medya kontrol tuşları için genel tuşa basmak istiyorum (oynat, ileri atla, geri atla vb.).C# Kanca Global Klavye Olayları - .net 4.0

Yaklaşık 2 saat süredir bir çözüm bulmaya çalışıyorum - ama bu işe yaradı bulamadım. Aynı şey hakkında birkaç Stackoverflow yanıtı buldum, ama hiçbiri işe yaramadı.

MouseKeyHook NuGet paketini denedim, ancak bu olayı asla tetiklemez. Ben de FMUtils.KeyboardHook paketini denedim, ama aynı şey, konsolda basıldıktan hemen sonra çeneyi kapatması dışında konsolda basıldı - ve neden kaynak koduna baktıktan sonra olay hakkında hiçbir fikrim yok.

Bu codeproject projesini http://www.codeproject.com/Articles/18638/Using-Window-Messages-to-Implement-Global-System-H almaya çalıştım ama demoyu bile çalıştıramadım, hem demolar sadece izleyemediğim tuhaf hatalar attı.

Sorum, benim Winforms uygulamama odaklanmadığında klavye basmalarını yakalamak için kullanabileceğim .net 4.0 numaralı klavyede parmak basma yöntemiyle bilinen bir yöntemdir.

cevap

8

Son X yıldır çeşitli projeler için kullandığım kod İşte. Hiçbir sorunla çalışmaz (Windows'daki herhangi bir .NET sürümü için). Umarım size yardımcı olur.

public class KeyboardHook : IDisposable 
{ 
    bool Global = false; 

    public delegate void LocalKeyEventHandler(Keys key, bool Shift, bool Ctrl, bool Alt); 
    public event LocalKeyEventHandler KeyDown; 
    public event LocalKeyEventHandler KeyUp; 

    public delegate int CallbackDelegate(int Code, int W, int L); 

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
    public struct KBDLLHookStruct 
    { 
     public Int32 vkCode; 
     public Int32 scanCode; 
     public Int32 flags; 
     public Int32 time; 
     public Int32 dwExtraInfo; 
    } 

    [DllImport("user32", CallingConvention = CallingConvention.StdCall)] 
    private static extern int SetWindowsHookEx(HookType idHook, CallbackDelegate lpfn, int hInstance, int threadId); 

    [DllImport("user32", CallingConvention = CallingConvention.StdCall)] 
    private static extern bool UnhookWindowsHookEx(int idHook); 

    [DllImport("user32", CallingConvention = CallingConvention.StdCall)] 
    private static extern int CallNextHookEx(int idHook, int nCode, int wParam, int lParam); 

    [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall)] 
    private static extern int GetCurrentThreadId(); 

    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 
    } 

    private int HookID = 0; 
    CallbackDelegate TheHookCB = null; 

    //Start hook 
    public KeyboardHook(bool Global) 
    { 
     this.Global = Global; 
     TheHookCB = new CallbackDelegate(KeybHookProc); 
     if (Global) 
     { 
      HookID = SetWindowsHookEx(HookType.WH_KEYBOARD_LL, TheHookCB, 
       0, //0 for local hook. eller hwnd til user32 for global 
       0); //0 for global hook. eller thread for hooken 
     } 
     else 
     { 
      HookID = SetWindowsHookEx(HookType.WH_KEYBOARD, TheHookCB, 
       0, //0 for local hook. or hwnd to user32 for global 
       GetCurrentThreadId()); //0 for global hook. or thread for the hook 
     } 
    } 

    bool IsFinalized = false; 
    ~KeyboardHook() 
    { 
     if (!IsFinalized) 
     { 
      UnhookWindowsHookEx(HookID); 
      IsFinalized = true; 
     } 
    } 
    public void Dispose() 
    { 
     if (!IsFinalized) 
     { 
      UnhookWindowsHookEx(HookID); 
      IsFinalized = true; 
     } 
    } 

    //The listener that will trigger events 
    private int KeybHookProc(int Code, int W, int L) 
    { 
     KBDLLHookStruct LS = new KBDLLHookStruct(); 
     if (Code < 0) 
     { 
      return CallNextHookEx(HookID, Code, W, L); 
     } 
     try 
     { 
      if (!Global) 
      { 
       if (Code == 3) 
       { 
        IntPtr ptr = IntPtr.Zero; 

        int keydownup = L >> 30; 
        if (keydownup == 0) 
        { 
         if (KeyDown != null) KeyDown((Keys)W, GetShiftPressed(), GetCtrlPressed(), GetAltPressed()); 
        } 
        if (keydownup == -1) 
        { 
         if (KeyUp != null) KeyUp((Keys)W, GetShiftPressed(), GetCtrlPressed(), GetAltPressed()); 
        } 
        //System.Diagnostics.Debug.WriteLine("Down: " + (Keys)W); 
       } 
      } 
      else 
      { 
       KeyEvents kEvent = (KeyEvents)W; 

       Int32 vkCode = Marshal.ReadInt32((IntPtr)L); //Leser vkCode som er de første 32 bits hvor L peker. 

       if (kEvent != KeyEvents.KeyDown && kEvent != KeyEvents.KeyUp && kEvent != KeyEvents.SKeyDown && kEvent != KeyEvents.SKeyUp) 
       { 
       } 
       if (kEvent == KeyEvents.KeyDown || kEvent == KeyEvents.SKeyDown) 
       { 
        if (KeyDown != null) KeyDown((Keys)vkCode, GetShiftPressed(), GetCtrlPressed(), GetAltPressed()); 
       } 
       if (kEvent == KeyEvents.KeyUp || kEvent == KeyEvents.SKeyUp) 
       { 
        if (KeyUp != null) KeyUp((Keys)vkCode, GetShiftPressed(), GetCtrlPressed(), GetAltPressed()); 
       } 
      } 
     } 
     catch (Exception) 
     { 
      //Ignore all errors... 
     } 

     return CallNextHookEx(HookID, Code, W, L); 

    } 

    public enum KeyEvents 
    { 
     KeyDown = 0x0100, 
     KeyUp = 0x0101, 
     SKeyDown = 0x0104, 
     SKeyUp = 0x0105 
    } 

    [DllImport("user32.dll")] 
    static public extern short GetKeyState(System.Windows.Forms.Keys nVirtKey); 

    public static bool GetCapslock() 
    { 
     return Convert.ToBoolean(GetKeyState(System.Windows.Forms.Keys.CapsLock)) & true; 
    } 
    public static bool GetNumlock() 
    { 
     return Convert.ToBoolean(GetKeyState(System.Windows.Forms.Keys.NumLock)) & true; 
    } 
    public static bool GetScrollLock() 
    { 
     return Convert.ToBoolean(GetKeyState(System.Windows.Forms.Keys.Scroll)) & true; 
    } 
    public static bool GetShiftPressed() 
    { 
     int state = GetKeyState(System.Windows.Forms.Keys.ShiftKey); 
     if (state > 1 || state < -1) return true; 
     return false; 
    } 
    public static bool GetCtrlPressed() 
    { 
     int state = GetKeyState(System.Windows.Forms.Keys.ControlKey); 
     if (state > 1 || state < -1) return true; 
     return false; 
    } 
    public static bool GetAltPressed() 
    { 
     int state = GetKeyState(System.Windows.Forms.Keys.Menu); 
     if (state > 1 || state < -1) return true; 
     return false; 
    } 
} 

Testi uygulaması:

static class Program 
{ 
    [STAThread] 
    static void Main() 
    { 
     var kh = new KeyboardHook(true); 
     kh.KeyDown += Kh_KeyDown; 
     Application.Run(); 
    } 

    private static void Kh_KeyDown(Keys key, bool Shift, bool Ctrl, bool Alt) 
    { 
     Debug.WriteLine("The Key: " + key); 
    } 
} 

Bazı kod temizleme yapabileceğini, ama işe yarıyor gibi rahatsız değil.

+1

Teşekkürler! Çalıştı :) –

+0

Harika :) thx: p – Soheyl

+0

C# ile çalışan tek kancalar düşük seviyededir: WH_KEYBOARD_LL ve WH_MOUSE_LL. Yani, bu örnekten global olmayan kanca çalışmayacak. [Güven bana] (https://github.com/Gh61/csharp-global-windows-hook) veya [Microsoft'a Güven] (https://support.microsoft.com/en-us/help/318804/how- set-a-pencere kanca-in-görsel-c - net) – Gh61