Files
eveo/Eve-O-Preview/Hotkeys/Hotkey.cs
2016-05-09 19:48:55 +03:00

332 lines
6.6 KiB
C#

using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.Xml.Serialization;
using System.Runtime.InteropServices;
namespace EveOPreview
{
public class Hotkey : IMessageFilter
{
private static int _currentId;
private const int MaxId = 0xBFFF;
[XmlElement("keyCode")]
private Keys _keyCode;
[XmlElement("shift")]
private bool _shift;
[XmlElement("control")]
private bool _control;
[XmlElement("alt")]
private bool _alt;
[XmlElement("windows")]
private bool _windows;
[XmlIgnore]
private int _id;
[XmlIgnore]
private bool _isRegistered;
[XmlIgnore]
private Control _windowControl;
public event HandledEventHandler Pressed;
public Hotkey()
: this(Keys.None, false, false, false, false)
{
}
public Hotkey(Keys keyCode, bool shift, bool control, bool alt, bool windows)
{
// Assign properties
this.KeyCode = keyCode;
this.Shift = shift;
this.Control = control;
this.Alt = alt;
this.Windows = windows;
// Register us as a message filter
Application.AddMessageFilter(this);
}
~Hotkey()
{
// Unregister the hotkey if necessary
if (this.IsRegistered)
{
this.Unregister();
}
}
public Hotkey Clone()
{
// Clone the whole object
return new Hotkey(this._keyCode, this._shift, this._control, this._alt, this._windows);
}
public bool GetCanRegister(Control windowControl)
{
// Handle any exceptions: they mean "no, you can't register" :)
try
{
// Attempt to register
if (this.Register(windowControl))
{
// Unregister and say we managed it
this.Unregister();
return true;
}
}
catch (Win32Exception)
{
}
catch (NotSupportedException)
{
}
return false;
}
public bool Register(Control windowControl)
{
// Check that we have not registered
if (this._isRegistered)
{
throw new NotSupportedException("You cannot register a hotkey that is already registered");
}
// We can't register an empty hotkey
if (this.IsEmpty)
{
throw new NotSupportedException("You cannot register an empty hotkey");
}
// Get an ID for the hotkey and increase current ID
this._id = Hotkey._currentId;
Hotkey._currentId = Hotkey._currentId + 1 % Hotkey.MaxId;
// Translate modifier keys into unmanaged version
uint modifiers = (this.Alt ? HotkeyNativeMethods.MOD_ALT : 0) | (this.Control ? HotkeyNativeMethods.MOD_CONTROL : 0) |
(this.Shift ? HotkeyNativeMethods.MOD_SHIFT : 0) | (this.Windows ? HotkeyNativeMethods.MOD_WIN : 0);
// Register the hotkey
if (HotkeyNativeMethods.RegisterHotKey(windowControl.Handle, this._id, modifiers, _keyCode) == 0)
{
// Is the error that the hotkey is registered?
if (Marshal.GetLastWin32Error() != HotkeyNativeMethods.ERROR_HOTKEY_ALREADY_REGISTERED)
{
throw new Win32Exception();
}
return false;
}
// Save the control reference and register state
this._isRegistered = true;
this._windowControl = windowControl;
// We successfully registered
return true;
}
public void Unregister()
{
// Check that we have registered
if (!this._isRegistered)
{
throw new NotSupportedException("You cannot unregister a hotkey that is not registered");
}
// It's possible that the control itself has died: in that case, no need to unregister!
if (!this._windowControl.IsDisposed)
{
// Clean up after ourselves
if (HotkeyNativeMethods.UnregisterHotKey(this._windowControl.Handle, this._id) == 0)
{
throw new Win32Exception();
}
}
// Clear the control reference and register state
this._isRegistered = false;
this._windowControl = null;
}
private void Reregister()
{
// Only do something if the key is already registered
if (!this._isRegistered)
{
return;
}
// Save control reference
Control windowControl = this._windowControl;
// Unregister and then reregister again
this.Unregister();
this.Register(windowControl);
}
public bool PreFilterMessage(ref Message message)
{
// Only process WM_HOTKEY messages
if (message.Msg != HotkeyNativeMethods.WM_HOTKEY)
{
return false;
}
// Check that the ID is our key and we are registerd
return this._isRegistered && (message.WParam.ToInt32() == this._id) && this.OnPressed();
}
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;
}
public override string ToString()
{
// We can be empty
if (this.IsEmpty)
{
return "(none)";
}
// Build key name
string keyName = Enum.GetName(typeof(Keys), this._keyCode) ?? " ";
switch (this._keyCode)
{
case Keys.D0:
case Keys.D1:
case Keys.D2:
case Keys.D3:
case Keys.D4:
case Keys.D5:
case Keys.D6:
case Keys.D7:
case Keys.D8:
case Keys.D9:
// Strip the first character
keyName = keyName.Substring(1);
break;
}
// Build modifiers
string modifiers = "";
if (this._shift)
{
modifiers += "Shift+";
}
if (this._control)
{
modifiers += "Control+";
}
if (this._alt)
{
modifiers += "Alt+";
}
if (this._windows)
{
modifiers += "Windows+";
}
// Return result
return modifiers + keyName;
}
public bool IsEmpty
{
get
{
return this._keyCode == Keys.None;
}
}
public bool IsRegistered
{
get
{
return this._isRegistered;
}
}
public Keys KeyCode
{
get
{
return this._keyCode;
}
set
{
// Save and reregister
this._keyCode = value;
this.Reregister();
}
}
public bool Shift
{
get
{
return this._shift;
}
set
{
// Save and reregister
this._shift = value;
this.Reregister();
}
}
public bool Control
{
get
{
return this._control;
}
set
{
// Save and reregister
this._control = value;
this.Reregister();
}
}
public bool Alt
{
get
{
return this._alt;
}
set
{
// Save and reregister
this._alt = value;
this.Reregister();
}
}
public bool Windows
{
get
{
return this._windows;
}
set
{
// Save and reregister
this._windows = value;
this.Reregister();
}
}
}
}