misu

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 2  →  ?path2? @ 3
/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
}
}