mattsven
mattsven

Reputation: 23253

Trying to use (System-Wide) Hotkeys in WPF/C#

I've been trying to use System-Wide/Global HotKeys in my latest WPF/C# project. Lucky for me, I came upon this wonderful class, here - http://www.codeproject.com/Tips/274003/Global-Hotkeys-in-WPF.

The only problem is, I can't get it to work. I've been banging my head with this since last week, and the weird thing is, I'm getting no errors. Here's my code, any ideas why?

HotKey hotkey = new HotKey((System.Windows.Interop.HwndSource)System.Windows.Interop.HwndSource.FromVisual(App.Current.MainWindow));
                //hotkey.Modifiers = list[i]._HotkeyA.Modifier; hotkey.Key = list[i]._HotkeyA._Key;
                hotkey.Modifiers = HotKey.ModifierKeys.Shift; hotkey.Key = Key.F2;
                hotkey.HotKeyPressed += new EventHandler<HotKeyEventArgs>(delegate(Object o, HotKeyEventArgs e)
                {
                    Console.WriteLine("Congratulations, Cap'n.");
                    System.Windows.Forms.MessageBox.Show("YAAY HOTKEY HAZ BEEN TEH PRESSEDS!");
                });
                hotkey.Enabled = true;

Thanks in advance!

Upvotes: 2

Views: 1702

Answers (2)

Mathew Sachin
Mathew Sachin

Reputation: 1449

The following implementation Uses the WPF ComponentDispatcher class to Dispatch Windows Messages.

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;

[Flags]
public enum ModifierKeyCodes : uint
{
    Alt = 1,
    Control = 2,
    Shift = 4,
    Windows = 8
}

/// <summary>
/// Virtual Key Codes
/// </summary>
public enum VirtualKeyCodes : uint
{
A = 65,
B = 66,
C = 67,
D = 68,
E = 69,
F = 70,
G = 71,
H = 72,
I = 73,
J = 74,
K = 75,
L = 76,
M = 77,
N = 78,
O = 79,
P = 80,
Q = 81,
R = 82,
S = 83,
T = 84,
U = 85,
V = 86,
W = 87,
X = 88,
Y = 89,
Z = 90
}

class KeyboardHook : IDisposable
{
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);

[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, ModifierKeyCodes fdModifiers, VirtualKeyCodes vk);

#region Fields
WindowInteropHelper host;
bool IsDisposed = false;
int Identifier;

public Window Window { get; private set; }

public VirtualKeyCodes Key { get; private set; }

public ModifierKeyCodes Modifiers { get; private set; }
#endregion

public KeyboardHook(Window Window, VirtualKeyCodes Key, ModifierKeyCodes Modifiers)
{
    this.Key = Key;
    this.Modifiers = Modifiers;

    this.Window = Window;
    host = new WindowInteropHelper(Window);

    Identifier = Window.GetHashCode();

    RegisterHotKey(host.Handle, Identifier, Modifiers, Key);

    ComponentDispatcher.ThreadPreprocessMessage += ProcessMessage;
}

void ProcessMessage(ref MSG msg, ref bool handled)
{
    if ((msg.message == 786) && (msg.wParam.ToInt32() == Identifier) && (Triggered != null))
        Triggered();
}

public event Action Triggered;

public void Dispose()
{
    if (!IsDisposed)
    {
        ComponentDispatcher.ThreadPreprocessMessage -= ProcessMessage;

        UnregisterHotKey(host.Handle, Identifier);
        Window = null;
        host = null;
    }
    IsDisposed = true;
}
}

Disposing the Object Unregisters the HotKey. You need to hold a reference to the KeyboardHook class to prevent it from being unregistered.

Example:

// Registers a Hook to MyWindow - Ctrl+A and calls DoWork() when Triggered.
var KH = new KeyboardHook(MyWindow, VirtualKeyCodes.A, ModifierKeyCodes.Ctrl);
KH += () => DoWork();

// When you don't need the Hook
KH.Dispose();

Upvotes: 4

AndrewS
AndrewS

Reputation: 6094

Make sure you are holding a strong reference to that HotKey. From the link you provided that object has a finalizer that would set the Enabled to false which would unregister the hotkey.

Upvotes: 0

Related Questions