using System; using System.Windows.Forms; using System.ComponentModel; namespace EveOPreview.UI { class HotkeyHandler : IMessageFilter, IDisposable { private static int _currentId; private const int MaxId = 0xBFFF; #region Private fields private readonly int _hotkeyId; private readonly IntPtr _hotkeyTarget; #endregion public HotkeyHandler(IntPtr target, Keys hotkey) { this._hotkeyId = HotkeyHandler._currentId; HotkeyHandler._currentId = (HotkeyHandler._currentId + 1) & HotkeyHandler.MaxId; this._hotkeyTarget = target; // Assign properties this.IsRegistered = false; this.KeyCode = hotkey; } public void Dispose() { if (this.IsRegistered) { this.Unregister(); } GC.SuppressFinalize(this); } ~HotkeyHandler() { // Unregister the hotkey if necessary if (this.IsRegistered) { try { this.Unregister(); } catch (Exception) { // Please no exceptions in the finalizer thread } } } public bool IsRegistered { get; private set; } public Keys KeyCode { get; private set; } public event HandledEventHandler Pressed; public bool CanRegister() { // Any exception means "no, you can't register" try { // Attempt to register if (this.Register()) { // Unregister and say we managed it this.Unregister(); return true; } } catch (Win32Exception) { } catch (NotSupportedException) { } return false; } public bool Register() { // Check that we have not registered if (this.IsRegistered) { throw new NotSupportedException("This hotkey is already registered"); } if (this.KeyCode == Keys.None) { throw new NotSupportedException("Cannot register an empty hotkey"); } // Remove all modifiers from the 'main' hotkey uint key = (uint)this.KeyCode & (~(uint)Keys.Alt) & (~(uint)Keys.Control) & (~(uint)Keys.Shift); // Get unmanaged version of the modifiers code uint modifiers = (this.KeyCode.HasFlag(Keys.Alt) ? HotkeyHandlerNativeMethods.MOD_ALT : 0) | (this.KeyCode.HasFlag(Keys.Control) ? HotkeyHandlerNativeMethods.MOD_CONTROL : 0) | (this.KeyCode.HasFlag(Keys.Shift) ? HotkeyHandlerNativeMethods.MOD_SHIFT : 0); // Register the hotkey if (!HotkeyHandlerNativeMethods.RegisterHotKey(this._hotkeyTarget, this._hotkeyId, modifiers, key)) { return false; } Application.AddMessageFilter(this); this.IsRegistered = true; // We successfully registered return true; } public void Unregister() { // Check that we have registered if (!this.IsRegistered) { throw new NotSupportedException("This hotkey was not registered"); } Application.RemoveMessageFilter(this); // Clean up after ourselves if (!HotkeyHandlerNativeMethods.UnregisterHotKey(this._hotkeyTarget, this._hotkeyId)) { throw new Win32Exception(); } this.IsRegistered = false; } #region IMessageFilter public bool PreFilterMessage(ref Message message) { return this.IsRegistered && (message.Msg == HotkeyHandlerNativeMethods.WM_HOTKEY) && (message.WParam.ToInt32() == this._hotkeyId) && this.OnPressed(); } #endregion private bool OnPressed() { // Fire the event if we can HandledEventArgs handledEventArgs = new HandledEventArgs(false); this.Pressed?.Invoke(this, handledEventArgs); // Return whether we handled the event or not return handledEventArgs.Handled; } } }