WPFでホットキーの登録を行うサンプルを書いてみました。
Win32のRegisterHotKey/UnregisterHotKeyというAPIを呼び出すことで、ホットキーの登録/登録解除ができます。
このAPIでホットキーを登録しておくと、アプリがアクティブでないときでも有効なグローバルなホットキーとなります。
サンプル
HotKeyHelperというクラスを作り、以下のように登録/登録解除できるようにしました。
MainWindow.xaml.cs
/// <summary>/// MainWindow.xaml の相互作用ロジック/// </summary>publicpartialclass MainWindow : Window { private HotKeyHelper _hotkey; public MainWindow() { InitializeComponent(); // HotKeyの登録this._hotkey = new HotKeyHelper(this); this._hotkey.Register(ModifierKeys.Control | ModifierKeys.Shift, Key.X, (_, __) => { MessageBox.Show("HotKey"); }); } protectedoverridevoid OnClosed(EventArgs e) { base.OnClosed(e); // HotKeyの登録解除this._hotkey.Dispose(); } }
HotKeyHeloper.cs
続いてHotKeyHelperの中身です。
このクラスで、複数のホットキー登録を管理します。
また、IDisposableを実装しておき、Disposeのタイミングですべてのホットキー登録を解除するようにしています。
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using System.Windows.Interop; namespace HotKeySample { publicclass HotKeyItem { public ModifierKeys ModifierKeys { get; private set; } public Key Key { get; private set; } public EventHandler Handler { get; private set; } public HotKeyItem(ModifierKeys modKey, Key key, EventHandler handler) { this.ModifierKeys = modKey; this.Key = key; this.Handler = handler; } } /// <summary>/// HotKey登録を管理するヘルパークラス/// </summary>publicclass HotKeyHelper : IDisposable { private IntPtr _windowHandle; private Dictionary<int, HotKeyItem> _hotkeyList = new Dictionary<int, HotKeyItem>(); privateconstint WM_HOTKEY = 0x0312; [DllImport("user32.dll")] privatestaticexternint RegisterHotKey(IntPtr hWnd, int id, int modKey, int vKey); [DllImport("user32.dll")] privatestaticexternint UnregisterHotKey(IntPtr hWnd, int id); public HotKeyHelper(Window window) { var host = new WindowInteropHelper(window); this._windowHandle = host.Handle; ComponentDispatcher.ThreadPreprocessMessage += ComponentDispatcher_ThreadPreprocessMessage; } privatevoid ComponentDispatcher_ThreadPreprocessMessage(ref MSG msg, refbool handled) { if (msg.message != WM_HOTKEY) { return; } var id = msg.wParam.ToInt32(); var hotkey = this._hotkeyList[id]; hotkey?.Handler ?.Invoke(this, EventArgs.Empty); } privateint _hotkeyID = 0x0000; privateconstint MAX_HOTKEY_ID = 0xC000; /// <summary>/// 引数で指定された内容で、HotKeyを登録します。/// </summary>/// <paramname="modKey"></param>/// <paramname="key"></param>/// <paramname="handler"></param>/// <returns></returns>publicbool Register(ModifierKeys modKey, Key key, EventHandler handler) { var modKeyNum = (int)modKey; var vKey = KeyInterop.VirtualKeyFromKey(key); // HotKey登録while(this._hotkeyID < MAX_HOTKEY_ID) { var ret = RegisterHotKey(this._windowHandle, this._hotkeyID, modKeyNum, vKey); if (ret != 0) { break; } this._hotkeyID++; } if (this._hotkeyID < MAX_HOTKEY_ID) { // HotKeyのリストに追加 var hotkey = new HotKeyItem(modKey, key, handler); this._hotkeyList.Add(this._hotkeyID, hotkey); returntrue; } else { returnfalse; } } /// <summary>/// 引数で指定されたidのHotKeyを登録解除します。/// </summary>/// <paramname="id"></param>/// <returns></returns>publicbool Unregister(int id) { var ret = UnregisterHotKey(this._windowHandle, id); return ret == 0; } /// <summary>/// 引数で指定されたmodKeyとkeyの組み合わせからなるHotKeyを登録解除します。/// </summary>/// <paramname="modKey"></param>/// <paramname="key"></param>/// <returns></returns>publicbool Unregister(ModifierKeys modKey, Key key) { var item = this._hotkeyList .FirstOrDefault(o => o.Value.ModifierKeys == modKey && o.Value.Key == key); var isFound = !item.Equals(default(KeyValuePair<int, HotKeyItem>)); if (isFound) { var ret = Unregister(item.Key); if (ret) { this._hotkeyList.Remove(item.Key); } return ret; } else { returnfalse; } } /// <summary>/// 登録済みのすべてのHotKeyを解除します。/// </summary>/// <returns></returns>publicbool UnregisterAll() { var result = true; foreach(var item inthis._hotkeyList) { result &= this.Unregister(item.Key); } return result; } #region IDisposable Supportprivatebool disposedValue = false; protectedvirtualvoid Dispose(bool disposing) { if (!disposedValue) { if (disposing) { // マネージリソースの破棄 } // アンマネージリソースの破棄this.UnregisterAll(); disposedValue = true; } } ~HotKeyHelper() { Dispose(false); } publicvoid Dispose() { Dispose(true); GC.SuppressFinalize(this); } #endregion } }
http://sourcechord.hatenablog.com/entry/2017/02/11/125649
↑に書いたタスクトレイ常駐の方法と組み合わせると、
常駐アプリ作ったりするときに役に立つかな、、、と思います。