Quantcast
Channel: SourceChord
Viewing all articles
Browse latest Browse all 153

WPFでホットキーの登録

$
0
0

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
↑に書いたタスクトレイ常駐の方法と組み合わせると、
常駐アプリ作ったりするときに役に立つかな、、、と思います。


Viewing all articles
Browse latest Browse all 153

Trending Articles