mirror of
https://github.com/kangyu-california/PersistentWindows.git
synced 2025-05-10 20:45:38 +02:00
543 lines
19 KiB
C#
543 lines
19 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Windows.Forms;
|
|
using System.Net;
|
|
using System.Timers;
|
|
using System.IO;
|
|
using System.IO.Compression;
|
|
using System.Drawing;
|
|
|
|
using PersistentWindows.Common.Diagnostics;
|
|
using PersistentWindows.Common.WinApiBridge;
|
|
|
|
namespace PersistentWindows.SystrayShell
|
|
{
|
|
public partial class SystrayForm : Form
|
|
{
|
|
private const int MaxSnapshots = 38; // 0-9, a-z, ` and final one for undo
|
|
|
|
private bool pauseAutoRestore = false;
|
|
public bool toggleIcon = false;
|
|
|
|
private int skipUpgradeCounter = 0;
|
|
private bool pauseUpgradeCounter = false;
|
|
|
|
public bool autoUpgrade = false;
|
|
|
|
private int ctrlKeyPressed = 0;
|
|
private int shiftKeyPressed = 0;
|
|
private int altKeyPressed = 0;
|
|
private int clickCount = 0;
|
|
private bool firstClick = false;
|
|
private bool doubleClick = false;
|
|
|
|
private DateTime clickTime;
|
|
|
|
private System.Timers.Timer clickDelayTimer;
|
|
|
|
private Dictionary<string, bool> upgradeDownloaded = new Dictionary<string, bool>();
|
|
|
|
public SystrayForm(bool enable_upgrade_notice)
|
|
{
|
|
InitializeComponent();
|
|
|
|
if (File.Exists(Program.DisableUpgradeNotice))
|
|
upgradeNoticeMenuItem.Text = "Enable upgrade notice";
|
|
else if (!enable_upgrade_notice)
|
|
{
|
|
File.Create(Program.DisableUpgradeNotice);
|
|
upgradeNoticeMenuItem.Text = "Enable upgrade notice";
|
|
}
|
|
else
|
|
upgradeNoticeMenuItem.Text = "Disable upgrade notice";
|
|
|
|
if (File.Exists(Program.DisableWebpageCommander))
|
|
{
|
|
invokeWebCommander.Text = "Enable webpage commander";
|
|
}
|
|
|
|
clickDelayTimer = new System.Timers.Timer(1000);
|
|
clickDelayTimer.Elapsed += ClickTimerCallBack;
|
|
clickDelayTimer.SynchronizingObject = this.contextMenuStripSysTray;
|
|
clickDelayTimer.AutoReset = false;
|
|
clickDelayTimer.Enabled = false;
|
|
}
|
|
|
|
public void StartTimer(int milliseconds)
|
|
{
|
|
clickDelayTimer.Interval = milliseconds;
|
|
clickDelayTimer.AutoReset = false;
|
|
clickDelayTimer.Enabled = true;
|
|
}
|
|
|
|
private void ClickTimerCallBack(Object source, ElapsedEventArgs e)
|
|
{
|
|
if (clickCount == 0)
|
|
{
|
|
// fix context menu position
|
|
//contextMenuStripSysTray.Show(Cursor.Position);
|
|
return;
|
|
}
|
|
|
|
pauseUpgradeCounter = true;
|
|
|
|
Keys keyPressed = Keys.None;
|
|
//check 0-9 key pressed
|
|
for (Keys i = Keys.D0; i <= Keys.D9; ++i)
|
|
{
|
|
if (User32.GetAsyncKeyState((int)i) != 0)
|
|
{
|
|
keyPressed = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//check a-z pressed
|
|
if (keyPressed == Keys.None)
|
|
for (Keys i = Keys.A; i <= Keys.Z; ++i)
|
|
{
|
|
if (User32.GetAsyncKeyState((int)i) != 0)
|
|
{
|
|
keyPressed = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (keyPressed == Keys.None)
|
|
{
|
|
if (User32.GetAsyncKeyState((int)Keys.Oem3) != 0)
|
|
{
|
|
keyPressed = Keys.Oem3;
|
|
}
|
|
}
|
|
|
|
int totalSpecialKeyPressed = shiftKeyPressed + altKeyPressed;
|
|
|
|
if (clickCount > 2)
|
|
{
|
|
}
|
|
else if (totalSpecialKeyPressed > clickCount)
|
|
{
|
|
//no more than one key can be pressed
|
|
}
|
|
else if (altKeyPressed == clickCount && altKeyPressed != 0 && ctrlKeyPressed == 0)
|
|
{
|
|
//restore previous workspace (not necessarily a snapshot)
|
|
Program.RestoreSnapshot(MaxSnapshots - 1);
|
|
}
|
|
else
|
|
{
|
|
if (keyPressed == Keys.None)
|
|
{
|
|
if (clickCount == 1 && firstClick && !doubleClick)
|
|
{
|
|
if (ctrlKeyPressed > 0 && altKeyPressed > 0 && shiftKeyPressed == 0)
|
|
Program.FgWindowToBottom();
|
|
else if (ctrlKeyPressed > 0 && altKeyPressed == 0 && shiftKeyPressed == 0)
|
|
Program.RecallLastKilledPosition();
|
|
else if (ctrlKeyPressed == 0 && altKeyPressed == 0 && shiftKeyPressed > 0)
|
|
Program.CenterWindow();
|
|
else if (ctrlKeyPressed == 0 && altKeyPressed == 0 && shiftKeyPressed == 0)
|
|
//restore unnamed(default) snapshot
|
|
Program.RestoreSnapshot(0);
|
|
}
|
|
else if (clickCount == 2 && firstClick && doubleClick)
|
|
Program.CaptureSnapshot(0, delayCapture: shiftKeyPressed > 0);
|
|
}
|
|
else
|
|
{
|
|
int snapshot = -1;
|
|
if (keyPressed == Keys.Oem3)
|
|
snapshot = MaxSnapshots - 2;
|
|
else if (keyPressed >= Keys.D0 && keyPressed <= Keys.D9)
|
|
snapshot = keyPressed - Keys.D0;
|
|
else if (keyPressed >= Keys.A && keyPressed <= Keys.Z)
|
|
snapshot = keyPressed - Keys.A + 10;
|
|
|
|
if (snapshot < 0)
|
|
{
|
|
//invalid key pressed
|
|
}
|
|
else if (clickCount == 1 && firstClick && !doubleClick)
|
|
{
|
|
Program.RestoreSnapshot(snapshot);
|
|
}
|
|
else if (clickCount == 2 && firstClick && doubleClick)
|
|
{
|
|
Program.CaptureSnapshot(snapshot, delayCapture: shiftKeyPressed > 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
clickCount = 0;
|
|
doubleClick = false;
|
|
firstClick = false;
|
|
ctrlKeyPressed = 0;
|
|
shiftKeyPressed = 0;
|
|
altKeyPressed = 0;
|
|
}
|
|
|
|
//private void TimerEventProcessor(Object myObject, EventArgs myEventArgs)
|
|
public void UpdateMenuEnable(bool enableRestoreFromDB, bool checkUpgrade)
|
|
{
|
|
if (enableRestoreFromDB)
|
|
restoreToolStripMenuItem.Image = null;
|
|
else
|
|
restoreToolStripMenuItem.Image = Properties.Resources.question;
|
|
|
|
if (checkUpgrade && upgradeNoticeMenuItem.Text.Contains("Disable"))
|
|
{
|
|
if (pauseUpgradeCounter)
|
|
{
|
|
pauseUpgradeCounter = false;
|
|
}
|
|
else
|
|
{
|
|
if (skipUpgradeCounter == 0)
|
|
{
|
|
CheckUpgradeSafe();
|
|
}
|
|
|
|
skipUpgradeCounter = (skipUpgradeCounter + 1) % 31;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void EnableSnapshotRestore(bool enable)
|
|
{
|
|
restoreSnapshotMenuItem.Enabled = enable;
|
|
}
|
|
|
|
private void CheckUpgradeSafe()
|
|
{
|
|
try
|
|
{
|
|
CheckUpgrade();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Program.LogError(ex.ToString());
|
|
}
|
|
}
|
|
|
|
private void CheckUpgrade()
|
|
{
|
|
ServicePointManager.Expect100Continue = true;
|
|
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
|
|
var cli = new WebClient();
|
|
string data = cli.DownloadString($"{Program.ProjectUrl}/releases");
|
|
|
|
string latest_pattern = "releases/latest";
|
|
int index = data.IndexOf(latest_pattern);
|
|
index -= 256;
|
|
data = data.Substring(index, 256);
|
|
string pattern = "releases/tag/";
|
|
index = data.IndexOf(pattern);
|
|
string latestVersion = data.Substring(index + pattern.Length, data.Substring(index + pattern.Length, 6).LastIndexOf('"'));
|
|
|
|
string[] latest = latestVersion.Split('.');
|
|
int latest_major = Int32.Parse(latest[0]);
|
|
int latest_minor = Int32.Parse(latest[1]);
|
|
|
|
string[] current = Application.ProductVersion.Split('.');
|
|
int current_major = Int32.Parse(current[0]);
|
|
int current_minor = Int32.Parse(current[1]);
|
|
|
|
if (current_major < latest_major
|
|
|| current_major == latest_major && current_minor < latest_minor)
|
|
{
|
|
notifyIconMain.ShowBalloonTip(5000, $"{Application.ProductName} {latestVersion} upgrade is available", "The upgrade notice can be disabled in menu", ToolTipIcon.Info);
|
|
upgradeNoticeMenuItem.Text = $"Upgrade to {latestVersion}";
|
|
|
|
if (!upgradeDownloaded.ContainsKey(latestVersion))
|
|
{
|
|
string url = Program.ProjectUrl + "/releases";
|
|
var os_version = Environment.OSVersion;
|
|
if (os_version.Version.Major < 10)
|
|
Process.Start(url);
|
|
else if (os_version.Version.Build < 22000)
|
|
Process.Start(url);
|
|
/* windows 11
|
|
else
|
|
Process.Start(new ProcessStartInfo(url));
|
|
*/
|
|
|
|
var src_file = $"{Program.ProjectUrl}/releases/download/{latestVersion}/{System.Windows.Forms.Application.ProductName}{latestVersion}.zip";
|
|
var dst_file = $"{Program.AppdataFolder}/upgrade.zip";
|
|
var dst_dir = Path.Combine($"{Program.AppdataFolder}", "upgrade");
|
|
var install_dir = Application.StartupPath;
|
|
|
|
{
|
|
cli.DownloadFile(src_file, dst_file);
|
|
if (Directory.Exists(dst_dir))
|
|
Directory.Delete(dst_dir, true);
|
|
ZipFile.ExtractToDirectory(dst_file, dst_dir);
|
|
upgradeDownloaded[latestVersion] = true;
|
|
|
|
string batFile = Path.Combine(Program.AppdataFolder, $"pw_upgrade.bat");
|
|
string content = Program.WaitPwFinish;
|
|
content += $"\ncopy /Y \"{dst_dir}\\*.*\" \"{install_dir}\"";
|
|
content += "\nstart \"\" /B \"" + Path.Combine(install_dir, Application.ProductName) + ".exe\" " + Program.CmdArgs;
|
|
File.WriteAllText(batFile, content);
|
|
|
|
if (autoUpgrade)
|
|
Upgrade();
|
|
else
|
|
notifyIconMain.Icon = Program.UpdateIcon;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Exit()
|
|
{
|
|
var process = Process.GetCurrentProcess();
|
|
process.PriorityClass = ProcessPriorityClass.High;
|
|
|
|
Program.WriteDataDump();
|
|
Log.Event("Session exit");
|
|
|
|
this.notifyIconMain.Visible = false;
|
|
//this.notifyIconMain.Icon = null;
|
|
|
|
Log.Exit();
|
|
Program.Stop();
|
|
Application.Exit();
|
|
}
|
|
|
|
private void Upgrade()
|
|
{
|
|
Program.WriteDataDump();
|
|
|
|
string batFile = Path.Combine(Program.AppdataFolder, "pw_upgrade.bat");
|
|
Process.Start(batFile);
|
|
Exit();
|
|
}
|
|
|
|
private void CaptureWindowToDisk(object sender, EventArgs e)
|
|
{
|
|
Program.CaptureToDisk();
|
|
restoreToolStripMenuItem.Image = null;
|
|
}
|
|
|
|
private void RestoreWindowFromDisk(object sender, EventArgs e)
|
|
{
|
|
Program.RestoreFromDisk(restoreToolStripMenuItem.Image != null);
|
|
}
|
|
|
|
private void CaptureSnapshot(object sender, EventArgs e)
|
|
{
|
|
bool shift_key_pressed = (User32.GetKeyState(0x10) & 0x8000) != 0;
|
|
char snapshot_char = Program.EnterSnapshotName();
|
|
int id = Program.SnapshotCharToId(snapshot_char);
|
|
if (id != -1)
|
|
Program.CaptureSnapshot(id, prompt : false, delayCapture: shift_key_pressed);
|
|
}
|
|
|
|
private void RestoreSnapshot(object sender, EventArgs e)
|
|
{
|
|
char snapshot_char = Program.EnterSnapshotName();
|
|
int id = Program.SnapshotCharToId(snapshot_char);
|
|
if (id != -1)
|
|
{
|
|
// for debug issue #109 only
|
|
//Program.ChangeZorderMethod();
|
|
|
|
Program.RestoreSnapshot(id);
|
|
}
|
|
}
|
|
|
|
|
|
private void PauseResumeAutoRestore(object sender, EventArgs e)
|
|
{
|
|
if (pauseAutoRestore)
|
|
{
|
|
Program.ResumeAutoRestore();
|
|
pauseAutoRestore = false;
|
|
pauseResumeToolStripMenuItem.Text = "Pause auto restore";
|
|
}
|
|
else
|
|
{
|
|
pauseAutoRestore = true;
|
|
Program.PauseAutoRestore();
|
|
pauseResumeToolStripMenuItem.Text = "Resume auto restore";
|
|
}
|
|
}
|
|
|
|
private void WebCommander(object sender, EventArgs e)
|
|
{
|
|
if ((User32.GetKeyState(0x11) & 0x8000) != 0)
|
|
HotKeyForm.InvokeFromMenu();
|
|
else if (this.invokeWebCommander.Text.Contains("Disable"))
|
|
{
|
|
File.Create(Program.DisableWebpageCommander);
|
|
this.invokeWebCommander.Text = "Enable webpage commander";
|
|
HotKeyForm.Stop();
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
File.Delete(Program.DisableWebpageCommander);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex.ToString());
|
|
}
|
|
|
|
this.invokeWebCommander.Text = "Disable webpage commander";
|
|
HotKeyForm.Start(Program.hotkey);
|
|
}
|
|
}
|
|
|
|
private void ToggleIcon(object sender, EventArgs e)
|
|
{
|
|
if (toggleIcon)
|
|
{
|
|
notifyIconMain.Icon = Program.IdleIcon;
|
|
toggleIcon = !toggleIcon;
|
|
toggleIconMenuItem.Text = "Try customized icon";
|
|
}
|
|
else
|
|
{
|
|
using (OpenFileDialog openFileDialog = new OpenFileDialog())
|
|
{
|
|
//openFileDialog.InitialDirectory = "c:\\";
|
|
openFileDialog.Filter = "*.ico, *.png|*.ico;*.png| *.ico | *.ico | *.png | *.png";
|
|
openFileDialog.FilterIndex = 1;
|
|
openFileDialog.RestoreDirectory = true;
|
|
|
|
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
//Get the path of specified file
|
|
string filePath = openFileDialog.FileName;
|
|
if (String.IsNullOrEmpty(filePath))
|
|
return;
|
|
if (filePath.EndsWith(".png"))
|
|
{
|
|
var bitmap = new Bitmap(filePath); // or get it from resource
|
|
notifyIconMain.Icon = Icon.FromHandle(bitmap.GetHicon());
|
|
}
|
|
else
|
|
notifyIconMain.Icon = new Icon(filePath);
|
|
toggleIcon = !toggleIcon;
|
|
toggleIconMenuItem.Text = "Disable customized icon";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void PauseResumeUpgradeNotice(Object sender, EventArgs e)
|
|
{
|
|
if (upgradeNoticeMenuItem.Text.Contains("Upgrade to"))
|
|
{
|
|
Upgrade();
|
|
}
|
|
else if (upgradeNoticeMenuItem.Text.Contains("Enable"))
|
|
{
|
|
upgradeNoticeMenuItem.Text = "Disable upgrade notice";
|
|
CheckUpgradeSafe();
|
|
try
|
|
{
|
|
File.Delete(Program.DisableUpgradeNotice);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex.ToString());
|
|
}
|
|
}
|
|
else //menu is "Disable upgrade notice"
|
|
{
|
|
File.Create(Program.DisableUpgradeNotice);
|
|
upgradeNoticeMenuItem.Text = "Enable upgrade notice";
|
|
}
|
|
}
|
|
|
|
private void AboutToolStripMenuItemClickHandler(object sender, EventArgs e)
|
|
{
|
|
Process.Start(Program.ProjectUrl + "/blob/master/Help.md");
|
|
}
|
|
|
|
private void ExitToolStripMenuItemClickHandler(object sender, EventArgs e)
|
|
{
|
|
bool ctrl_key_pressed = (User32.GetKeyState(0x11) & 0x8000) != 0;
|
|
if (ctrl_key_pressed)
|
|
Program.Restart(2, hidden:false);
|
|
Exit();
|
|
}
|
|
|
|
private void IconMouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (!doubleClick && e.Button == MouseButtons.Left)
|
|
{
|
|
firstClick = true;
|
|
clickTime = DateTime.Now;
|
|
Console.WriteLine("MouseClick");
|
|
|
|
// clear memory of keyboard input
|
|
for (Keys i = Keys.D0; i <= Keys.D9; ++i)
|
|
{
|
|
User32.GetAsyncKeyState((int)i);
|
|
}
|
|
|
|
for (Keys i = Keys.A; i <= Keys.Z; ++i)
|
|
{
|
|
User32.GetAsyncKeyState((int)i);
|
|
}
|
|
|
|
User32.GetAsyncKeyState((int)Keys.Oem3);
|
|
}
|
|
}
|
|
|
|
private void IconMouseDoubleClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left)
|
|
{
|
|
DateTime now = DateTime.Now;
|
|
var ms = now.Subtract(clickTime).TotalMilliseconds;
|
|
Console.WriteLine("{0}", ms);
|
|
if (ms < 30 || ms > SystemInformation.DoubleClickTime / 2)
|
|
{
|
|
Program.LogError($"ignore bogus double click {ms} ms");
|
|
return;
|
|
}
|
|
|
|
doubleClick = true;
|
|
Console.WriteLine("MouseDoubleClick");
|
|
}
|
|
}
|
|
|
|
private void IconMouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left)
|
|
{
|
|
Console.WriteLine("Down");
|
|
|
|
if ((User32.GetKeyState(0x11) & 0x8000) != 0)
|
|
ctrlKeyPressed++;
|
|
|
|
if ((User32.GetKeyState(0x10) & 0x8000) != 0)
|
|
shiftKeyPressed++;
|
|
|
|
if ((User32.GetKeyState(0x12) & 0x8000) != 0)
|
|
altKeyPressed++;
|
|
}
|
|
}
|
|
|
|
private void IconMouseUp(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left)
|
|
{
|
|
Console.WriteLine("Up");
|
|
|
|
clickCount++;
|
|
StartTimer(SystemInformation.DoubleClickTime);
|
|
}
|
|
else if (e.Button == MouseButtons.Middle)
|
|
{
|
|
notifyIconMain.Icon = Program.IdleIcon;
|
|
}
|
|
}
|
|
}
|
|
}
|