mirror of
https://github.com/LorenzCK/OnTopReplica.git
synced 2024-05-21 04:43:55 +12:00
Refactored Hot Key processing and Dual Mode as extensible Message Pump Processors.
This commit is contained in:
parent
86cf05ae3d
commit
a7863b5c0e
|
@ -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>();
|
||||
|
||||
}
|
||||
|
||||
}
|
15
OnTopReplica/IMessagePumpProcessor.cs
Normal file
15
OnTopReplica/IMessagePumpProcessor.cs
Normal 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);
|
||||
|
||||
}
|
||||
}
|
|
@ -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:
|
||||
|
|
58
OnTopReplica/MessagePumpManager.cs
Normal file
58
OnTopReplica/MessagePumpManager.cs
Normal 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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
48
OnTopReplica/MessagePumpProcessors/HotKeyManager.cs
Normal file
48
OnTopReplica/MessagePumpProcessors/HotKeyManager.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
32
OnTopReplica/Native/HotKeyMethods.cs
Normal file
32
OnTopReplica/Native/HotKeyMethods.cs
Normal 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);
|
||||
|
||||
}
|
||||
}
|
|
@ -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" />
|
||||
|
|
Loading…
Reference in a new issue