Refactored Hot Key processing and Dual Mode as extensible Message Pump Processors.

This commit is contained in:
Lorenz Cuno Klopfenstein 2010-06-30 13:42:35 +02:00
parent 86cf05ae3d
commit a7863b5c0e
10 changed files with 232 additions and 138 deletions

View file

@ -1,90 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace OnTopReplica {
/// <summary>
/// HotKey registration helper.
/// </summary>
public class HotKeyManager : IDisposable {
public HotKeyManager(Form form) {
Owner = form;
}
public Form Owner { get; private set; }
[Flags]
public enum HotKeyModifiers : int {
Alt = 0x1,
Control = 0x2,
Shift = 0x4,
Windows = 0x8
}
const int WM_HOTKEY = 0x312;
[DllImport("user32.dll")]
static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")]
static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private delegate void FormDelegate(HotKeyModifiers mod, Keys key, HotKeyHandler handler);
public void RegisterHotKey(HotKeyModifiers mod, Keys key, HotKeyHandler handler) {
Owner.Invoke(new FormDelegate(RegisterHotKeyCore), mod, key, handler);
}
private void RegisterHotKeyCore(HotKeyModifiers mod, Keys keys, HotKeyHandler handler) {
var newKey = ++_lastUsedKey;
if (!RegisterHotKey(Owner.Handle, newKey, (int)mod, (int)keys)) {
Console.Error.WriteLine("Failed to register {0} hot key.", newKey);
return;
}
_handlers[newKey] = handler;
}
public void ProcessHotKeys(Message msg) {
if (msg.Msg == WM_HOTKEY) {
int keyId = msg.WParam.ToInt32();
if (!_handlers.ContainsKey(keyId))
return;
_handlers[keyId].Invoke();
}
}
private delegate void VoidFormDelegate();
private void UnregisterHotKeysCore() {
foreach (var key in _handlers.Keys) {
if (!UnregisterHotKey(Owner.Handle, key))
Console.Error.WriteLine("Failed to unregister {0} hot key.", key);
}
}
#region IDisposable Members
public void Dispose() {
if (Owner != null && Owner.IsHandleCreated) {
Owner.Invoke(new VoidFormDelegate(UnregisterHotKeysCore));
}
}
#endregion
public delegate void HotKeyHandler();
private int _lastUsedKey = 0;
Dictionary<int, HotKeyHandler> _handlers = new Dictionary<int, HotKeyHandler>();
}
}

View file

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace OnTopReplica {
interface IMessagePumpProcessor : IDisposable {
void Initialize(MainForm form);
void Process(Message msg);
}
}

View file

@ -13,13 +13,13 @@ namespace OnTopReplica {
//GUI
ThumbnailPanel _thumbnailPanel;
RegionBox _regionBox;
HotKeyManager _hotKeyManager;
//Window manager
WindowManager _windowManager = new WindowManager();
WindowHandle _lastWindowHandle = null;
DualModeManager _dualModeManager;
//Message pump extension
MessagePumpManager _msgPumpManager = new MessagePumpManager();
public MainForm() {
InitializeComponent();
@ -57,12 +57,13 @@ namespace OnTopReplica {
this.KeyUp += new KeyEventHandler(Form_KeyUp);
this.KeyPreview = true;
//Add hotkeys
_hotKeyManager = new HotKeyManager(this);
_hotKeyManager.RegisterHotKey(HotKeyManager.HotKeyModifiers.Control | HotKeyManager.HotKeyModifiers.Shift,
Keys.O, new HotKeyManager.HotKeyHandler(HotKeyOpenHandler));
//Init message pump extensions
_msgPumpManager.Initialize(this);
_dualModeManager = new DualModeManager(this);
//Add hotkeys
var hotKeyMgr = _msgPumpManager.Get<MessagePumpProcessors.HotKeyManager>();
hotKeyMgr.RegisterHotKey(Native.HotKeyModifiers.Control | Native.HotKeyModifiers.Shift,
Keys.O, new Native.HotKeyMethods.HotKeyHandler(HotKeyOpenHandler));
}
#region Child forms & controls events
@ -170,13 +171,7 @@ namespace OnTopReplica {
}
protected override void OnClosing(CancelEventArgs e) {
//Destroy hotkeys
_hotKeyManager.Dispose();
_hotKeyManager = null;
//Destroy dual mode manager
_dualModeManager.Dispose();
_dualModeManager = null;
_msgPumpManager.Dispose();
base.OnClosing(e);
}
@ -207,10 +202,7 @@ namespace OnTopReplica {
}
protected override void WndProc(ref Message m) {
if (_hotKeyManager != null)
_hotKeyManager.ProcessHotKeys(m);
if (_dualModeManager != null)
_dualModeManager.ProcessHookMessages(m);
_msgPumpManager.PumpMessage(m);
switch(m.Msg){
case NativeMethods.WM_NCRBUTTONUP:

View file

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Windows.Forms;
namespace OnTopReplica {
class MessagePumpManager : IDisposable {
Dictionary<Type, IMessagePumpProcessor> _processors = new Dictionary<Type, IMessagePumpProcessor>();
/// <summary>
/// Instantiates all message pump processors and registers them on the main form.
/// </summary>
/// <param name="form"></param>
public void Initialize(MainForm form) {
foreach (var t in Assembly.GetExecutingAssembly().GetTypes()) {
if (typeof(IMessagePumpProcessor).IsAssignableFrom(t) && !t.IsAbstract) {
var instance = (IMessagePumpProcessor)Activator.CreateInstance(t);
instance.Initialize(form);
_processors.Add(t, instance);
Console.WriteLine("Registered message pump processor: {0}", t);
}
}
}
/// <summary>
/// Run the registered message pump processors.
/// </summary>
/// <param name="msg">Message to process.</param>
public void PumpMessage(Message msg) {
foreach (var processor in _processors.Values) {
processor.Process(msg);
}
}
/// <summary>
/// Get the instance of a registered message pump processor.
/// Throw if instance not found.
/// </summary>
public T Get<T>() {
return (T)_processors[typeof(T)];
}
#region IDisposable Members
public void Dispose() {
foreach (var processor in _processors.Values) {
processor.Dispose();
}
_processors.Clear();
}
#endregion
}
}

View file

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace OnTopReplica.MessagePumpProcessors {
abstract class BaseMessagePumpProcessor : IMessagePumpProcessor {
protected MainForm Form { get; private set; }
#region IMessagePumpProcessor Members
public void Initialize(MainForm form) {
Form = form;
}
public abstract void Process(Message msg);
#endregion
bool _isDisposed = false;
protected abstract void Shutdown();
#region IDisposable Members
public void Dispose() {
if (_isDisposed)
return;
Shutdown();
_isDisposed = true;
}
#endregion
}
}

View file

@ -6,22 +6,23 @@ using System.Diagnostics;
using System.Reflection;
using System.IO;
using System.Windows.Forms;
using OnTopReplica.Native;
namespace OnTopReplica {
namespace OnTopReplica.MessagePumpProcessors {
class DualModeManager : IDisposable {
class DualModeManager : BaseMessagePumpProcessor {
public DualModeManager(MainForm form) {
_form = form;
public DualModeManager() {
_hookMsgId = HookMethods.RegisterWindowMessage("SHELLHOOK");
if (_hookMsgId == 0)
Console.Error.WriteLine("Failed to register SHELLHOOK Windows message.");
}
MainForm _form;
uint _hookMsgId;
bool _active = false;
static uint _hookMsgId = NativeHooks.RegisterWindowMessage("SHELLHOOK");
public void EnableDualMode(IEnumerable<WindowHandle> handles) {
if (!NativeHooks.RegisterShellHookWindow(_form.Handle)) {
if (!HookMethods.RegisterShellHookWindow(Form.Handle)) {
Console.WriteLine("Failed to register shell hook window.");
return;
}
@ -29,34 +30,29 @@ namespace OnTopReplica {
_active = true;
}
public void ProcessHookMessages(Message msg) {
if (msg.Msg == _hookMsgId) {
int hookCode = msg.WParam.ToInt32();
if (hookCode == NativeHooks.HSHELL_WINDOWACTIVATED ||
hookCode == NativeHooks.HSHELL_RUDEAPPACTIVATED) {
IntPtr activeHandle = msg.LParam;
}
}
}
public void Disable() {
if (!_active)
return;
if (!NativeHooks.DeregisterShellHookWindow(_form.Handle))
if (!HookMethods.DeregisterShellHookWindow(Form.Handle))
Console.WriteLine("Failed to deregister shell hook window.");
_active = false;
}
#region IDisposable Members
public void Dispose() {
Disable();
public override void Process(Message msg) {
if (msg.Msg == _hookMsgId) {
int hookCode = msg.WParam.ToInt32();
if (hookCode == HookMethods.HSHELL_WINDOWACTIVATED ||
hookCode == HookMethods.HSHELL_RUDEAPPACTIVATED) {
IntPtr activeHandle = msg.LParam;
}
}
}
#endregion
protected override void Shutdown() {
Disable();
}
}
}

View file

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using OnTopReplica.Native;
namespace OnTopReplica.MessagePumpProcessors {
/// <summary>
/// HotKey registration helper.
/// </summary>
class HotKeyManager : BaseMessagePumpProcessor {
int _lastUsedKey = 0;
Dictionary<int, HotKeyMethods.HotKeyHandler> _handlers = new Dictionary<int, HotKeyMethods.HotKeyHandler>();
public void RegisterHotKey(HotKeyModifiers mod, Keys keys, HotKeyMethods.HotKeyHandler handler) {
var newKey = ++_lastUsedKey;
if (!HotKeyMethods.RegisterHotKey(Form.Handle, newKey, (int)mod, (int)keys)) {
Console.Error.WriteLine("Failed to register {0} hot key.", newKey);
return;
}
_handlers[newKey] = handler;
}
public override void Process(Message msg) {
if (msg.Msg == HotKeyMethods.WM_HOTKEY) {
int keyId = msg.WParam.ToInt32();
if (!_handlers.ContainsKey(keyId))
return;
_handlers[keyId].Invoke();
}
}
protected override void Shutdown() {
foreach (var key in _handlers.Keys) {
if (!HotKeyMethods.UnregisterHotKey(Form.Handle, key)) {
Console.Error.WriteLine("Failed to unregister {0} hot key.", key);
}
}
}
}
}

View file

@ -3,12 +3,12 @@ using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace OnTopReplica {
namespace OnTopReplica.Native {
/// <summary>
/// Helpers for interop with native Windows hooks.
/// </summary>
static class NativeHooks {
static class HookMethods {
public const int HSHELL_WINDOWACTIVATED = 4;
public const int HSHELL_RUDEAPPACTIVATED = HSHELL_WINDOWACTIVATED | HSHELL_HIGHBIT;

View file

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace OnTopReplica.Native {
[Flags]
public enum HotKeyModifiers : int {
Alt = 0x1,
Control = 0x2,
Shift = 0x4,
Windows = 0x8
}
static class HotKeyMethods {
public delegate void HotKeyHandler();
public const int WM_HOTKEY = 0x312;
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
public delegate void FormDelegate(HotKeyModifiers mod, Keys key, HotKeyHandler handler);
}
}

View file

@ -131,13 +131,17 @@
</Compile>
<Compile Include="CloneClickEventArgs.cs" />
<Compile Include="CloseRequestEventArgs.cs" />
<Compile Include="DualModeManager.cs" />
<Compile Include="NativeHooks.cs" />
<Compile Include="MessagePumpManager.cs" />
<Compile Include="MessagePumpProcessors\DualModeManager.cs" />
<Compile Include="IMessagePumpProcessor.cs" />
<Compile Include="MessagePumpProcessors\BaseMessagePumpProcessor.cs" />
<Compile Include="Native\HookMethods.cs" />
<Compile Include="Native\HotKeyMethods.cs" />
<Compile Include="WindowsSevenMethods.cs" />
<None Include="CommonControls.cs" />
<Compile Include="EnumerationExtensions.cs" />
<Compile Include="FullscreenMode.cs" />
<Compile Include="HotKeyManager.cs" />
<Compile Include="MessagePumpProcessors\HotKeyManager.cs" />
<Compile Include="PlatformSupport.cs" />
<Compile Include="Platforms\Other.cs" />
<Compile Include="Platforms\WindowsSeven.cs" />