/trunk/misu/MisuMainForm.cs |
@@ -0,0 +1,247 @@ |
using System; |
using System.ComponentModel; |
using System.Drawing; |
using System.Linq; |
using System.Threading.Tasks.Dataflow; |
using System.Windows.Forms; |
using Configuration; |
using Gma.System.MouseKeyHook; |
|
namespace misu |
{ |
public partial class MisuMainForm : Form |
{ |
#region Public Enums, Properties and Fields |
|
public Settings Settings { get; set; } |
|
#endregion |
|
#region Private Delegates, Events, Enums, Properties, Indexers and Fields |
|
private BufferBlock<KeyEventArgs> PressedKeysBufferBlock { get; } |
|
private IKeyboardMouseEvents GlobalHook { get; } |
|
private AboutForm AboutForm { get; set; } |
|
private BindKeyForm BindKeyForm { get; set; } |
|
private volatile bool _lock; |
|
#endregion |
|
#region Constructors, Destructors and Finalizers |
|
public MisuMainForm() |
{ |
InitializeComponent(); |
|
PressedKeysBufferBlock = new BufferBlock<KeyEventArgs>(new DataflowBlockOptions {EnsureOrdered = true}); |
|
// Load the settings. |
var serialization = Serialization.Deserialize(@"Settings.xml"); |
switch (serialization) |
{ |
case SerializationSuccess<Settings> serializationSuccess: |
Settings = serializationSuccess.Result; |
break; |
case SerializationFailure _: |
Settings = new Settings(); |
break; |
} |
|
Settings.PropertyChanged += Settings_PropertyChanged; |
Settings.Binding.PropertyChanged += Binding_PropertyChanged; |
|
// Hook to global events. |
GlobalHook = Hook.GlobalEvents(); |
|
// Bind to receive keyboard presses. |
GlobalHook.KeyDown += GlobalHook_KeyDown; |
GlobalHook.KeyUp += GlobalHook_KeyUp; |
|
GlobalHook.MouseUpExt += GlobalHook_BlockMouse; |
GlobalHook.MouseDragFinishedExt += GlobalHook_BlockMouse; |
GlobalHook.MouseDragStartedExt += GlobalHook_BlockMouse; |
GlobalHook.MouseWheelExt += GlobalHook_BlockMouse; |
GlobalHook.MouseMoveExt += GlobalHook_BlockMouse; |
GlobalHook.MouseDownExt += GlobalHook_BlockMouse; |
|
if (Settings.Binding.Keys.Any()) |
{ |
Notify($"Shortcut is bound.", |
$"Press {Settings.Binding} to toggle locking."); |
} |
} |
|
#endregion |
|
#region Event Handlers |
|
private async void Binding_PropertyChanged(object sender, PropertyChangedEventArgs e) |
{ |
await Settings.Serialize(@"Settings.xml"); |
} |
|
private void GlobalHook_BlockMouse(object sender, MouseEventExtArgs e) |
{ |
// Do not perform any operations while the binding form is visible. |
if (BindKeyForm != null && BindKeyForm.Visible) |
{ |
return; |
} |
|
if (_lock && Settings.Mouse) |
{ |
e.Handled = true; |
} |
} |
|
private async void Settings_PropertyChanged(object sender, PropertyChangedEventArgs e) |
{ |
// Serialize the settings to the configuration file on form closing. |
await Settings.Serialize(@"Settings.xml"); |
} |
|
private void GlobalHook_KeyUp(object sender, KeyEventArgs e) |
{ |
// Do not perform any operations while the binding form is visible. |
if (BindKeyForm != null && BindKeyForm.Visible) |
{ |
return; |
} |
|
if (!PressedKeysBufferBlock.TryReceiveAll(out var keys)) |
{ |
return; |
} |
|
if (Settings.Binding == null) |
{ |
return; |
} |
|
if (Settings.Binding.Keys.SequenceContains(keys.Select(key => key.KeyCode))) |
{ |
_lock = !_lock; |
|
// Lock the cursor in position. |
switch (_lock) |
{ |
case true: |
Cursor.Clip = new Rectangle(Cursor.Position, new Size(1, 1)); |
break; |
default: |
Cursor.Clip = Screen.PrimaryScreen.Bounds; |
break; |
} |
|
// Dismiss the current keypress to avoid typing the key. |
e.Handled = true; |
e.SuppressKeyPress = true; |
|
Notify($"Mouse and Keyboard are {(_lock ? "locked" : "unlocked")}.", |
$"Press {Settings.Binding} to toggle mouse and keyboard locking."); |
} |
} |
|
private async void GlobalHook_KeyDown(object sender, KeyEventArgs e) |
{ |
// Do not perform any operations while the binding form is visible. |
if (BindKeyForm != null && BindKeyForm.Visible) |
{ |
return; |
} |
|
if (_lock && Settings.Keyboard) |
{ |
e.SuppressKeyPress = true; |
e.Handled = true; |
} |
|
await PressedKeysBufferBlock.SendAsync(e); |
} |
|
private void OnContextMenuAboutClick(object sender, EventArgs e) |
{ |
// Show the about form. |
AboutForm = new AboutForm(); |
AboutForm.Show(); |
} |
|
private void OnContextMenuQuitClick(object sender, EventArgs e) |
{ |
Application.Exit(); |
} |
|
private void OnContextMenuLaunchOnBootChanged(object sender, EventArgs e) |
{ |
Settings.LaunchOnBoot = ((ToolStripMenuItem) sender).Checked; |
|
Utilities.LaunchOnBootSet(Settings.LaunchOnBoot); |
} |
|
private void OnContextMenuBindKeyClick(object sender, EventArgs e) |
{ |
BindKeyForm = new BindKeyForm(GlobalHook, Settings); |
BindKeyForm.KeyBound += BindKeyForm_KeyBound; |
BindKeyForm.Closing += BindKeyForm_Closing; |
BindKeyForm.Show(); |
} |
|
private void BindKeyForm_Closing(object sender, CancelEventArgs e) |
{ |
BindKeyForm.KeyBound -= BindKeyForm_KeyBound; |
BindKeyForm.Closing -= BindKeyForm_Closing; |
} |
|
private async void BindKeyForm_KeyBound(object sender, KeyBoundEventArgs e) |
{ |
Notify("Shortcut key is bound.", |
$"Press {e.Binding} to toggle between locked and unlocked keyboard and mouse."); |
|
Settings.Binding.Keys.AddRange(e.Binding.Keys); |
|
await Settings.Serialize(@"Settings.xml"); |
} |
|
private void KeyboardToolStripMenuItem_CheckedChanged(object sender, EventArgs e) |
{ |
var item = (ToolStripMenuItem) sender; |
|
Settings.Keyboard = item.Checked; |
} |
|
private void MouseToolStripMenuItem_CheckedChanged(object sender, EventArgs e) |
{ |
var item = (ToolStripMenuItem) sender; |
|
Settings.Mouse = item.Checked; |
} |
|
private void ContextMenuStrip_Opening(object sender, CancelEventArgs e) |
{ |
// Apply the settings to the menu items. |
launchOnBootToolStripMenuItem.Checked = Settings.LaunchOnBoot; |
Utilities.LaunchOnBootSet(Settings.LaunchOnBoot); |
|
mouseToolStripMenuItem.Checked = Settings.Mouse; |
keyboardToolStripMenuItem.Checked = Settings.Keyboard; |
} |
|
#endregion |
|
#region Private Methods |
|
private void Notify(string title, string message, int timeout = 10000) |
{ |
misuNotificationIcon.BalloonTipTitle = title; |
misuNotificationIcon.BalloonTipText = message; |
// the timeout parameter is not used for Windows Vista and up |
misuNotificationIcon.ShowBalloonTip(timeout); |
} |
|
#endregion |
} |
} |