2017-10-13 9 views
0

J'essaie de créer des raccourcis souris globaux dans mon programme en utilisant SetWindowsHookEx(). Jusqu'à présent j'ai essayé de les créer comme dans un article que j'ai vu ici mais, je ne sais pas vraiment comment le faire. Le problème est actuellement que je ne sais pas exactement ce que _globalMouseHookCallback est.Comment créer correctement une touche de raccourci globale de la souris dans wpf C#

C'est ce que je l'ai écrit à ce jour:

class GlobalHotkey 
{ 

    [DllImport("user32.dll")] 
    static extern IntPtr SetWindowsHookEx(int idHook, HookProc callback, IntPtr hInstance, uint threadId); 

    [DllImport("user32.dll")] 
    static extern bool UnhookWindowsHookEx(IntPtr hInstance); 

    [DllImport("user32.dll")] 
    static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam); 

    internal delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam); 

    private IntPtr _hGlobalMouseHook; 


    MainWindow _m; 

    private const int WH_KEYBOARD_LL = 13; 
    private const int WH_MOUSE_LL = 14; 

    private const int WM_LBUTTONDOWN = 0x0201; 
    private const int WM_LBUTTONUP = 0x0202; 
    private const int WM_RBUTTONDOWN = 0x0204; 
    private const int WM_RBUTTONUP = 0x0205; 

    private static IntPtr hook = IntPtr.Zero; 

    public GlobalHotkey(MainWindow m) 
    { 
     _m = m; 
    } 

    public void SetUpHook() 
    { 
     _m.rtbLog.AppendText("Setting up global Hotkey \n"); 

     _globalMouseHookCallback = LowLevelMouseProc; 

     _hGlobalMouseHook = SetWindowsHookEx(WH_MOUSE_LL, _globalMouseHookCallback, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0); 

     if (_hGlobalMouseHook == IntPtr.Zero) 
     { 
      _m.rtbLog.AppendText("Unable to set up global mouse hook\n"); 
     } 
    } 

    public void ClearHook() 
    { 
     _m.rtbLog.AppendText("Deleting global mouse hook\n"); 

     if (_hGlobalMouseHook != IntPtr.Zero) 
     { 
      if (!UnhookWindowsHookEx(_hGlobalMouseHook)) 
      { 
       _m.rtbLog.AppendText("Unable to delete global mouse hook\n"); 
      } 

      _hGlobalMouseHook = IntPtr.Zero; 
     } 

    } 

    public int LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam) 
    { 
     if (nCode >= 0) 
     { 
      var wmMouse = wParam; 

      if (wmMouse == (IntPtr)WM_LBUTTONDOWN) 
      { 
       _m.rtbLog.AppendText("Right Mouse down"); 
      } 
      if (wmMouse == (IntPtr)WM_LBUTTONUP) 
      { 
       _m.rtbLog.AppendText("Left Mouse up"); 
      } 

      if (wmMouse == (IntPtr)WM_RBUTTONDOWN) 
      { 
       _m.rtbLog.AppendText("Right Mouse down"); 
      } 
      if (wmMouse == (IntPtr)WM_RBUTTONUP) 
      { 
       _m.rtbLog.AppendText("Right Mouse up"); 
      } 
     } 

     return CallNextHookEx(_hGlobalMouseHook, nCode, wParam, lParam); 
    } 
} 

Ce truc global hotkey est assez difficile est là comme un tutoriel qui explique facilement newbs comme moi: P?

EDIT J'ai donc essayé d'adapter l'exemple de Koby Ducks à mon code.

Ceci est ma classe Hotkey:

class GlobalHotkey 
{ 

    MainWindow _m; 

    private static readonly object sSyncObj = new object(); 
    private static readonly HashSet<Key> sDownKeys = new HashSet<Key>(); 
    private static readonly Dictionary<Key, Action> sPressActions = new Dictionary<Key, Action>(); 
    private static readonly Dictionary<Key, Action> sReleaseActions = new Dictionary<Key, Action>(); 

    public GlobalHotkey(MainWindow m) 
    { 
     _m = m; 

    } 

    public static void ProcessKeyDown(KeyEventArgs args) 
    { 
     var key = args.Key; 
     var action = default(Action); 
     lock (sSyncObj) 
     { 
      if (!sDownKeys.Contains(key)) 
      { 
       sDownKeys.Add(key); 

       if (sPressActions.TryGetValue(key, out action)) 
       { 
        args.Handled = true; 
       } 
      } 
     } 

     action.Invoke(); 
    } 

    public static void ProcessKeyUp(KeyEventArgs args) 
    { 
     var key = args.Key; 
     var action = default(Action); 
     lock (sSyncObj) 
     { 
      if (sDownKeys.Remove(key)) 
      { 
       if (sReleaseActions.TryGetValue(key, out action)) 
       { 
        args.Handled = true; 
       } 
      } 
     } 

     action.Invoke(); 
    } 

    public static void AttachPressAction(Key key, Action action) 
    { 
     if (action == null) 
     { 
      throw new ArgumentNullException(nameof(action)); 
     } 

     lock (sSyncObj) 
     { 
      sPressActions.Add(key, action); 
     } 
    } 

    public static bool DetachPressAction(Key key) 
    { 
     lock (sSyncObj) 
     { 
      return sPressActions.Remove(key); 
     } 
    } 

    public static void AttachReleaseAction(Key key, Action action) 
    { 
     if (action == null) 
     { 
      throw new ArgumentNullException(nameof(action)); 
     } 

     lock (sSyncObj) 
     { 
      sReleaseActions.Add(key, action); 
     } 
    } 

    public static bool DetachReleaseAction(Key key) 
    { 
     lock (sSyncObj) 
     { 
      return sReleaseActions.Remove(key); 
     } 
    } 
} 

Et je créé mon action

public void MyTestAction() 
    { 
     rtbLog.AppendText("The B key was pressed"); 
    } 
myAction = new Action(MyTestAction); 

Mais dès que j'ai ajouté mes eventhandlers au PreviewKeyUp- et vers le bas de l'événement, il m'a donné une erreur disant que les paramètres de ProcessKeyUp- et Down, ne sont pas les mêmes que PreviewKeyUp- et Down.

PreviewKeyDown += GlobalHotkey.ProcessKeyDown; 
PreviewKeyUp += GlobalHotkey.ProcessKeyUp; 
+0

Cela signifie que vous souhaitez capturer les événements du clavier et de la souris qui se produisent même lorsque votre application n'a pas le focus? –

+0

Oui exactement cela – Celmos

+0

Voir ma mise à jour de la réponse. Le problème était que j'ai apparemment laissé de côté le paramètre de l'expéditeur. La grande majorité des événements Windows GUI sont de la forme '(expéditeur d'objet, args EventArgs)'. –

Répondre

0

Edit: Pour entrée quelle que soit la fenêtre actuellement concentrée (alias "global"), voir this answer sur l'API Win32 clavier.

Pour la saisie pendant que votre application est ciblée (alias «local»), vous pouvez utiliser des événements de prévisualisation. Indépendamment du fait que vous utilisiez cette méthode ou l'API Win32, prenez en compte les implications. Si vous avez 'A' lié, vous ne pourrez pas entrer 'a' ou 'A' dans les champs de saisie de texte. Une façon de contourner ce problème est la suivante:

public static void ProcessKeyDown(object sender, KeyEventArgs args) 
{ 
    // Detect keyboard input controls you may have issues with. 
    // If one has keyboard focus, skip hotkey processing. 
    if (Keyboard.FocusedElement is TextBox) { 
     return; 
    } 

    // ... 
} 
+0

Cette méthode fonctionne-t-elle également pour les raccourcis clavier de la souris? – Celmos

+0

OnPreviewMouseDown/Up réalise la même chose avec la souris. Pour détecter les entrées de souris globales sans utiliser l'API Win32, utilisez [CaptureMouse] (https://msdn.microsoft.com/en-us/library/system.windows.uielement.capturemouse (v = vs.110) .aspx). –

+0

Si cela répond à votre question, veuillez la marquer comme réponse acceptée. Si non, commentez et peut-être que je peux aider davantage. –