$ErrorActionPreference = 'Stop' $csharp = @' using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; using System.Globalization; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Windows.Forms; namespace PortableCaffeine { internal enum RemoteCommandKind { None, AppExit, AppOn, AppOff, AppToggle, AppToggleShowDialog, ShowDialog, ExitForReplace } internal enum ManualOverrideKind { None, ForceActive, ForceInactive } internal enum EffectiveMode { Inactive, ActiveKeyPulse, ActiveStesSystemOnly, ActiveStesSystemAndDisplay } internal sealed class TimeRange { public TimeSpan Start; public TimeSpan End; public bool Contains(TimeSpan time) { if (Start == End) { return true; } if (Start < End) { return time >= Start && time < End; } return time >= Start || time < End; } public override string ToString() { return Start.ToString(@"hh\:mm") + "-" + End.ToString(@"hh\:mm"); } } internal sealed class Options { public bool ShowHelp; public bool StartupEnabled = true; public bool StartupModeExplicit; public bool LockWorkstation; public bool UseStes; public bool AllowScreenSaver; public bool Notify; public bool ShowDialog; public bool OnTaskbar; public bool NoHIcon; public bool ReplaceExisting; public bool OnAcOnly; public bool AllowLocalCompat; public bool KeyWithShift; public string WatchWindowContains; public int? CpuThresholdPercent; public double? ExitAfterMinutes; public double? ActiveForMinutes; public double? InactiveForMinutes; public ushort VirtualKey = 0x7E; // F15 default public List ActivePeriods = new List(); public RemoteCommandKind AppCommand = RemoteCommandKind.None; public List UnknownSwitches = new List(); public List RawArgs = new List(); public bool HasAnyAppCommand { get { return AppCommand != RemoteCommandKind.None; } } } internal static class CommandLine { public static Options Parse(string[] args) { Options options = new Options(); if (args == null) { return options; } for (int i = 0; i < args.Length; i++) { string token = args[i]; if (token == null) { continue; } options.RawArgs.Add(token); if (!token.StartsWith("-") && !token.StartsWith("/")) { options.UnknownSwitches.Add(token); continue; } string body = token.Substring(1); string name = body; string value = null; int colon = body.IndexOf(':'); int equals = body.IndexOf('='); int sep = -1; if (colon >= 0 && equals >= 0) { sep = Math.Min(colon, equals); } else if (colon >= 0) { sep = colon; } else if (equals >= 0) { sep = equals; } if (sep >= 0) { name = body.Substring(0, sep); value = body.Substring(sep + 1); } name = name.Trim().ToLowerInvariant(); if (value != null) { value = value.Trim(); } switch (name) { case "?": case "h": case "help": options.ShowHelp = true; break; case "on": options.StartupEnabled = true; options.StartupModeExplicit = true; break; case "off": options.StartupEnabled = false; options.StartupModeExplicit = true; break; case "lock": options.LockWorkstation = true; break; case "showdlg": options.ShowDialog = true; break; case "ontaskbar": options.OnTaskbar = true; break; case "notify": options.Notify = true; break; case "nohicon": options.NoHIcon = true; break; case "replace": options.ReplaceExisting = true; break; case "onac": options.OnAcOnly = true; break; case "allowlocal": options.AllowLocalCompat = true; break; case "stes": options.UseStes = true; break; case "allowss": options.AllowScreenSaver = true; break; case "watchwindow": if (!string.IsNullOrEmpty(value)) { options.WatchWindowContains = value; } break; case "cpu": { int cpu; if (TryParseInt(value, out cpu)) { if (cpu < 0) cpu = 0; if (cpu > 100) cpu = 100; options.CpuThresholdPercent = cpu; } } break; case "exitafter": options.ExitAfterMinutes = ParseMinutes(value, options.ExitAfterMinutes); break; case "activefor": options.ActiveForMinutes = ParseMinutes(value, options.ActiveForMinutes); break; case "inactivefor": options.InactiveForMinutes = ParseMinutes(value, options.InactiveForMinutes); break; case "activehours": case "activeperiods": if (!string.IsNullOrEmpty(value)) { List parsed = ParseTimeRanges(value); if (parsed.Count > 0) { options.ActivePeriods = parsed; } } break; case "useshift": options.VirtualKey = 0x10; // VK_SHIFT break; case "leftshift": options.VirtualKey = 0xA0; // VK_LSHIFT break; case "key": case "keypress": { ushort vk; if (TryParseVirtualKey(value, out vk)) { options.VirtualKey = vk; } } break; case "keyshift": options.KeyWithShift = true; if (!string.IsNullOrEmpty(value)) { ushort vk; if (TryParseVirtualKey(value, out vk)) { options.VirtualKey = vk; } } break; case "appexit": options.AppCommand = RemoteCommandKind.AppExit; break; case "appon": options.AppCommand = RemoteCommandKind.AppOn; break; case "appoff": options.AppCommand = RemoteCommandKind.AppOff; break; case "apptoggle": options.AppCommand = RemoteCommandKind.AppToggle; break; case "apptoggleshowdlg": options.AppCommand = RemoteCommandKind.AppToggleShowDialog; break; default: options.UnknownSwitches.Add(token); break; } } return options; } private static double? ParseMinutes(string value, double? fallback) { if (string.IsNullOrEmpty(value)) { return fallback; } double minutes; if (double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out minutes)) { return minutes; } return fallback; } private static bool TryParseInt(string value, out int number) { number = 0; if (string.IsNullOrEmpty(value)) { return false; } return int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out number); } private static bool TryParseVirtualKey(string value, out ushort vk) { vk = 0; if (string.IsNullOrEmpty(value)) { return false; } string v = value.Trim(); try { if (v.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) { vk = Convert.ToUInt16(v.Substring(2), 16); return true; } vk = Convert.ToUInt16(v, CultureInfo.InvariantCulture); return true; } catch { return false; } } private static List ParseTimeRanges(string value) { List list = new List(); string[] parts = value.Split(new char[] { ',', ';', '|' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < parts.Length; i++) { string p = parts[i].Trim(); if (p.Length == 0) { continue; } int dash = p.IndexOf('-'); if (dash <= 0 || dash >= p.Length - 1) { continue; } string left = p.Substring(0, dash).Trim(); string right = p.Substring(dash + 1).Trim(); TimeSpan start; TimeSpan end; if (!TryParseTime(left, out start) || !TryParseTime(right, out end)) { continue; } TimeRange range = new TimeRange(); range.Start = start; range.End = end; list.Add(range); } return list; } private static bool TryParseTime(string text, out TimeSpan time) { time = TimeSpan.Zero; if (string.IsNullOrEmpty(text)) { return false; } DateTime dt; string[] formats = new string[] { "H", "HH", "H:mm", "HH:mm", "H.mm", "HH.mm", "Hmm", "HHmm" }; if (DateTime.TryParseExact(text, formats, CultureInfo.InvariantCulture, DateTimeStyles.None, out dt)) { time = dt.TimeOfDay; return true; } int hour; if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out hour) && hour >= 0 && hour <= 23) { time = new TimeSpan(hour, 0, 0); return true; } return false; } } internal static class NativeMethods { public const int WM_COPYDATA = 0x004A; public const uint ES_SYSTEM_REQUIRED = 0x00000001; public const uint ES_DISPLAY_REQUIRED = 0x00000002; public const uint ES_CONTINUOUS = 0x80000000; public const uint KEYEVENTF_KEYUP = 0x0002; [StructLayout(LayoutKind.Sequential)] public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; public IntPtr lpData; } [StructLayout(LayoutKind.Sequential)] public struct SYSTEM_POWER_STATUS { public byte ACLineStatus; public byte BatteryFlag; public byte BatteryLifePercent; public byte SystemStatusFlag; public int BatteryLifeTime; public int BatteryFullLifeTime; } [DllImport("kernel32.dll")] public static extern uint SetThreadExecutionState(uint esFlags); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref COPYDATASTRUCT lParam); [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); [DllImport("user32.dll")] public static extern int GetWindowTextLength(IntPtr hWnd); [DllImport("user32.dll")] public static extern bool LockWorkStation(); [DllImport("kernel32.dll")] public static extern bool GetSystemPowerStatus(out SYSTEM_POWER_STATUS sps); [DllImport("user32.dll")] public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo); [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DestroyIcon(IntPtr hIcon); } internal static class TrayIconFactory { public static Icon CreateCaffeineTrayIcon(bool active) { Bitmap bmp = new Bitmap(16, 16); try { using (Graphics g = Graphics.FromImage(bmp)) { g.SmoothingMode = SmoothingMode.AntiAlias; g.Clear(Color.Transparent); Color cupFill = active ? Color.FromArgb(68, 118, 184) : Color.FromArgb(140, 145, 152); Color cupOutline = active ? Color.FromArgb(35, 62, 102) : Color.FromArgb(84, 88, 94); Color coffeeFill = active ? Color.FromArgb(111, 72, 41) : Color.FromArgb(108, 96, 88); Color steamColor = active ? Color.FromArgb(245, 248, 252) : Color.FromArgb(188, 191, 196); Color saucerColor = active ? Color.FromArgb(54, 77, 101) : Color.FromArgb(106, 110, 116); using (SolidBrush cupBrush = new SolidBrush(cupFill)) using (SolidBrush coffeeBrush = new SolidBrush(coffeeFill)) using (Pen outlinePen = new Pen(cupOutline, 1f)) using (Pen steamPen = new Pen(steamColor, 1.1f)) using (Pen saucerPen = new Pen(saucerColor, 1f)) { // Mug body g.FillRectangle(cupBrush, 3, 7, 7, 5); g.DrawRectangle(outlinePen, 3, 7, 7, 5); // Coffee surface g.FillRectangle(coffeeBrush, 4, 8, 5, 2); // Mug handle g.DrawArc(outlinePen, 8, 7, 4, 4, 285, 255); // Saucer g.DrawLine(saucerPen, 2, 13, 12, 13); // Steam g.DrawBezier(steamPen, 4, 7, 3, 5, 5, 4, 4, 2); g.DrawBezier(steamPen, 7, 7, 6, 5, 8, 4, 7, 2); } if (!active) { using (Pen slashPen = new Pen(Color.FromArgb(210, 186, 53, 53), 1.8f)) { g.DrawLine(slashPen, 3, 13, 13, 3); } } } IntPtr hIcon = bmp.GetHicon(); try { using (Icon tmp = Icon.FromHandle(hIcon)) { return (Icon)tmp.Clone(); } } finally { NativeMethods.DestroyIcon(hIcon); } } catch { return null; } finally { bmp.Dispose(); } } } internal static class IpcTransport { public const string WindowTitle = "PortableCaffeine.HiddenIpcWindow"; public static bool Send(string payload) { IntPtr hwnd = NativeMethods.FindWindow(null, WindowTitle); if (hwnd == IntPtr.Zero) { return false; } IntPtr hGlobal = IntPtr.Zero; try { string data = payload ?? string.Empty; hGlobal = Marshal.StringToHGlobalUni(data); NativeMethods.COPYDATASTRUCT cds = new NativeMethods.COPYDATASTRUCT(); cds.dwData = IntPtr.Zero; cds.cbData = (data.Length + 1) * 2; cds.lpData = hGlobal; NativeMethods.SendMessage(hwnd, NativeMethods.WM_COPYDATA, IntPtr.Zero, ref cds); return true; } catch { return false; } finally { if (hGlobal != IntPtr.Zero) { Marshal.FreeHGlobal(hGlobal); } } } } internal sealed class IpcForm : Form { public delegate void PayloadReceivedHandler(object sender, string payload); public event PayloadReceivedHandler PayloadReceived; public IpcForm() { this.Text = IpcTransport.WindowTitle; this.ShowInTaskbar = false; this.FormBorderStyle = FormBorderStyle.FixedToolWindow; this.StartPosition = FormStartPosition.Manual; this.Size = new Size(1, 1); this.Location = new Point(-32000, -32000); this.Opacity = 0; } protected override void SetVisibleCore(bool value) { base.SetVisibleCore(false); } protected override void OnShown(EventArgs e) { this.Hide(); base.OnShown(e); } protected override void WndProc(ref Message m) { if (m.Msg == NativeMethods.WM_COPYDATA) { try { NativeMethods.COPYDATASTRUCT cds = (NativeMethods.COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam, typeof(NativeMethods.COPYDATASTRUCT)); if (cds.lpData != IntPtr.Zero && cds.cbData > 0) { string payload = Marshal.PtrToStringUni(cds.lpData); if (PayloadReceived != null) { PayloadReceived(this, payload); } } } catch { // Ignore malformed IPC messages. } } base.WndProc(ref m); } } internal sealed class StatusForm : Form { private Label _statusLabel; private Label _detailLabel; private Label _conditionLabel; private Button _toggleButton; private Button _revertButton; private Button _closeButton; public event EventHandler ToggleRequested; public event EventHandler RevertRequested; public StatusForm(bool showInTaskbar) { this.Text = "Portable Caffeine"; this.FormBorderStyle = FormBorderStyle.FixedDialog; this.MaximizeBox = false; this.MinimizeBox = false; this.StartPosition = FormStartPosition.CenterScreen; this.ClientSize = new Size(470, 190); this.ShowInTaskbar = showInTaskbar; _statusLabel = new Label(); _statusLabel.AutoSize = false; _statusLabel.Location = new Point(12, 12); _statusLabel.Size = new Size(446, 28); _statusLabel.Font = new Font(SystemFonts.MessageBoxFont.FontFamily, 11, FontStyle.Bold); _detailLabel = new Label(); _detailLabel.AutoSize = false; _detailLabel.Location = new Point(12, 48); _detailLabel.Size = new Size(446, 44); _conditionLabel = new Label(); _conditionLabel.AutoSize = false; _conditionLabel.Location = new Point(12, 96); _conditionLabel.Size = new Size(446, 42); _toggleButton = new Button(); _toggleButton.Text = "Toggle"; _toggleButton.Location = new Point(12, 148); _toggleButton.Size = new Size(90, 28); _toggleButton.Click += delegate(object sender, EventArgs e) { if (ToggleRequested != null) { ToggleRequested(this, EventArgs.Empty); } }; _revertButton = new Button(); _revertButton.Text = "Revert"; _revertButton.Location = new Point(108, 148); _revertButton.Size = new Size(90, 28); _revertButton.Click += delegate(object sender, EventArgs e) { if (RevertRequested != null) { RevertRequested(this, EventArgs.Empty); } }; _closeButton = new Button(); _closeButton.Text = "Close"; _closeButton.Location = new Point(368, 148); _closeButton.Size = new Size(90, 28); _closeButton.Click += delegate(object sender, EventArgs e) { this.Hide(); }; this.Controls.Add(_statusLabel); this.Controls.Add(_detailLabel); this.Controls.Add(_conditionLabel); this.Controls.Add(_toggleButton); this.Controls.Add(_revertButton); this.Controls.Add(_closeButton); } public void UpdateView(string status, string detail, string condition) { _statusLabel.Text = status ?? string.Empty; _detailLabel.Text = detail ?? string.Empty; _conditionLabel.Text = condition ?? string.Empty; } } internal sealed class CaffeineAppContext : ApplicationContext { private readonly Options _options; private readonly Mutex _instanceMutex; private readonly NotifyIcon _tray; private readonly Icon _trayIconActive; private readonly Icon _trayIconInactive; private readonly ContextMenuStrip _menu; private readonly IpcForm _ipcForm; private readonly System.Windows.Forms.Timer _timer; private readonly DateTime _startedLocal; private DateTime? _exitAtLocal; private DateTime? _startupActiveUntilLocal; private DateTime? _startupInactiveUntilLocal; private DateTime? _manualOverrideUntilLocal; private ManualOverrideKind _manualOverrideKind; private bool _lastEffectiveActive; private bool _hasLastEffectiveActive; private bool _lastConditionsMatch; private string _lastReason = "Initializing"; private string _lastConditionSummary = "Initializing"; private string _lastCpuSummary = "CPU condition not configured."; private DateTime _lastPulseUtc = DateTime.MinValue; private DateTime _lastStesRefreshUtc = DateTime.MinValue; private PerformanceCounter _cpuCounter; private bool _cpuCounterFailed; private bool _cpuCounterPrimed; private float _lastCpuPercent; private StatusForm _statusForm; private bool _lockPending; private bool _disposed; // Menu references for state updates private ToolStripMenuItem _miStatus; private ToolStripMenuItem _miActiveNow; private ToolStripMenuItem _miInactiveNow; private ToolStripMenuItem _miRevert; private ToolStripMenuItem _miShowHide; private ToolStripMenuItem _miTimed5; private ToolStripMenuItem _miTimed15; private ToolStripMenuItem _miTimed30; private ToolStripMenuItem _miTimed60; private ToolStripMenuItem _miTimed120; private ToolStripMenuItem _miTimedInactive5; private ToolStripMenuItem _miTimedInactive15; private ToolStripMenuItem _miTimedInactive30; public CaffeineAppContext(Options options, Mutex instanceMutex) { _options = options; _instanceMutex = instanceMutex; _startedLocal = DateTime.Now; _lockPending = options.LockWorkstation; if (options.ExitAfterMinutes.HasValue) { _exitAtLocal = _startedLocal.AddMinutes(options.ExitAfterMinutes.Value); } if (options.ActiveForMinutes.HasValue) { _startupActiveUntilLocal = _startedLocal.AddMinutes(options.ActiveForMinutes.Value); } if (options.InactiveForMinutes.HasValue) { _startupInactiveUntilLocal = _startedLocal.AddMinutes(options.InactiveForMinutes.Value); } _tray = new NotifyIcon(); _trayIconActive = TrayIconFactory.CreateCaffeineTrayIcon(true); _trayIconInactive = TrayIconFactory.CreateCaffeineTrayIcon(false); _tray.Visible = true; _tray.Text = "Portable Caffeine"; _tray.DoubleClick += delegate(object sender, EventArgs e) { ToggleManual(); }; _menu = new ContextMenuStrip(); _tray.ContextMenuStrip = _menu; BuildMenu(); SetTrayIcon(false); _ipcForm = new IpcForm(); _ipcForm.PayloadReceived += OnIpcPayload; IntPtr dummyHandle = _ipcForm.Handle; _ipcForm.Show(); _ipcForm.Hide(); if (_options.CpuThresholdPercent.HasValue) { TryInitCpuCounter(); } _timer = new System.Windows.Forms.Timer(); _timer.Interval = 1000; _timer.Tick += OnTick; _timer.Start(); if (_options.ShowDialog) { EnsureStatusForm(); ShowStatusForm(true); } // Run one evaluation immediately so state is correct on launch. TickCore(); } private void BuildMenu() { _menu.Items.Clear(); _miStatus = new ToolStripMenuItem("Status: Initializing"); _miStatus.Enabled = false; _miActiveNow = new ToolStripMenuItem("Active (indefinite)"); _miActiveNow.Click += delegate { SetManualOverride(ManualOverrideKind.ForceActive, null); }; _miInactiveNow = new ToolStripMenuItem("Inactive (indefinite)"); _miInactiveNow.Click += delegate { SetManualOverride(ManualOverrideKind.ForceInactive, null); }; _miTimed5 = new ToolStripMenuItem("Active for 5 minutes"); _miTimed5.Click += delegate { SetManualOverride(ManualOverrideKind.ForceActive, 5); }; _miTimed15 = new ToolStripMenuItem("Active for 15 minutes"); _miTimed15.Click += delegate { SetManualOverride(ManualOverrideKind.ForceActive, 15); }; _miTimed30 = new ToolStripMenuItem("Active for 30 minutes"); _miTimed30.Click += delegate { SetManualOverride(ManualOverrideKind.ForceActive, 30); }; _miTimed60 = new ToolStripMenuItem("Active for 60 minutes"); _miTimed60.Click += delegate { SetManualOverride(ManualOverrideKind.ForceActive, 60); }; _miTimed120 = new ToolStripMenuItem("Active for 120 minutes"); _miTimed120.Click += delegate { SetManualOverride(ManualOverrideKind.ForceActive, 120); }; _miTimedInactive5 = new ToolStripMenuItem("Inactive for 5 minutes"); _miTimedInactive5.Click += delegate { SetManualOverride(ManualOverrideKind.ForceInactive, 5); }; _miTimedInactive15 = new ToolStripMenuItem("Inactive for 15 minutes"); _miTimedInactive15.Click += delegate { SetManualOverride(ManualOverrideKind.ForceInactive, 15); }; _miTimedInactive30 = new ToolStripMenuItem("Inactive for 30 minutes"); _miTimedInactive30.Click += delegate { SetManualOverride(ManualOverrideKind.ForceInactive, 30); }; _miRevert = new ToolStripMenuItem("Revert To Parameters"); _miRevert.Click += delegate { RevertToParameters(); }; _miShowHide = new ToolStripMenuItem("Show Status"); _miShowHide.Click += delegate { ToggleStatusForm(); }; ToolStripMenuItem about = new ToolStripMenuItem("About"); about.Click += delegate { ShowAbout(); }; ToolStripMenuItem exit = new ToolStripMenuItem("Exit"); exit.Click += delegate { ExitApplication(); }; _menu.Items.Add(_miStatus); _menu.Items.Add(new ToolStripSeparator()); _menu.Items.Add(_miActiveNow); _menu.Items.Add(_miInactiveNow); _menu.Items.Add(new ToolStripSeparator()); _menu.Items.Add(_miTimed5); _menu.Items.Add(_miTimed15); _menu.Items.Add(_miTimed30); _menu.Items.Add(_miTimed60); _menu.Items.Add(_miTimed120); _menu.Items.Add(new ToolStripSeparator()); _menu.Items.Add(_miTimedInactive5); _menu.Items.Add(_miTimedInactive15); _menu.Items.Add(_miTimedInactive30); _menu.Items.Add(new ToolStripSeparator()); _menu.Items.Add(_miRevert); _menu.Items.Add(_miShowHide); _menu.Items.Add(new ToolStripSeparator()); _menu.Items.Add(about); _menu.Items.Add(exit); } private void EnsureStatusForm() { if (_statusForm != null && !_statusForm.IsDisposed) { return; } _statusForm = new StatusForm(_options.OnTaskbar); _statusForm.ToggleRequested += delegate { ToggleManual(); }; _statusForm.RevertRequested += delegate { RevertToParameters(); }; _statusForm.FormClosing += delegate(object sender, FormClosingEventArgs e) { if (e.CloseReason == CloseReason.UserClosing) { e.Cancel = true; _statusForm.Hide(); UpdateMenuState(); } }; } private void ToggleStatusForm() { EnsureStatusForm(); if (_statusForm.Visible) { _statusForm.Hide(); } else { ShowStatusForm(true); } UpdateMenuState(); } private void ShowStatusForm(bool activate) { EnsureStatusForm(); if (!_statusForm.Visible) { _statusForm.Show(); } if (activate) { _statusForm.WindowState = FormWindowState.Normal; _statusForm.BringToFront(); _statusForm.Activate(); } UpdateMenuState(); } private void ShowAbout() { StringBuilder sb = new StringBuilder(); sb.AppendLine("Portable Caffeine (PowerShell + embedded C#)"); sb.AppendLine("Zhorn Caffeine-compatible portable implementation."); sb.AppendLine(); sb.AppendLine("Method: " + GetMethodSummary()); sb.AppendLine("Key: " + FormatVirtualKey(_options.VirtualKey) + (_options.KeyWithShift ? " (with Shift)" : string.Empty)); if (_options.AllowLocalCompat) { sb.AppendLine("Compatibility flag: -allowlocal recognized."); } if (_options.UnknownSwitches.Count > 0) { sb.AppendLine("Unknown switches ignored: " + string.Join(", ", _options.UnknownSwitches.ToArray())); } MessageBox.Show(sb.ToString(), "About Portable Caffeine", MessageBoxButtons.OK, MessageBoxIcon.Information); } private void OnTick(object sender, EventArgs e) { TickCore(); } private void TickCore() { if (_disposed) { return; } DateTime nowLocal = DateTime.Now; DateTime nowUtc = DateTime.UtcNow; if (_lockPending) { _lockPending = false; try { NativeMethods.LockWorkStation(); } catch { // Ignore lock failures. } } if (_exitAtLocal.HasValue && nowLocal >= _exitAtLocal.Value) { ExitApplication(); return; } ExpireManualOverrideIfNeeded(nowLocal); bool conditionsMatch; string conditionSummary; bool baseShouldBeActive = EvaluateBaseRules(nowLocal, out conditionsMatch, out conditionSummary); bool effectiveActive; string reason; EvaluateEffectiveState(nowLocal, baseShouldBeActive, out effectiveActive, out reason); _lastConditionsMatch = conditionsMatch; _lastReason = reason; _lastConditionSummary = conditionSummary; EffectiveMode mode = effectiveActive ? GetActiveMode() : EffectiveMode.Inactive; ApplyActiveMode(mode, nowUtc); if (!_hasLastEffectiveActive || effectiveActive != _lastEffectiveActive) { _hasLastEffectiveActive = true; _lastEffectiveActive = effectiveActive; SetTrayIcon(effectiveActive); if (_options.Notify) { ShowNotify(effectiveActive ? "Caffeine active" : "Caffeine inactive", reason); } } UpdateMenuState(); UpdateStatusForm(); UpdateTrayTooltip(effectiveActive, reason); } private void ExpireManualOverrideIfNeeded(DateTime nowLocal) { if (_manualOverrideUntilLocal.HasValue && nowLocal >= _manualOverrideUntilLocal.Value) { _manualOverrideKind = ManualOverrideKind.None; _manualOverrideUntilLocal = null; } } private bool EvaluateBaseRules(DateTime nowLocal, out bool conditionsMatch, out string conditionSummary) { List parts = new List(); bool baseMode = _options.StartupEnabled; parts.Add("Base: " + (baseMode ? "On" : "Off")); if (_options.ActivePeriods != null && _options.ActivePeriods.Count > 0) { bool inPeriod = false; TimeSpan current = nowLocal.TimeOfDay; for (int i = 0; i < _options.ActivePeriods.Count; i++) { if (_options.ActivePeriods[i].Contains(current)) { inPeriod = true; break; } } parts.Add("Period: " + (inPeriod ? "matched" : "outside")); if (!inPeriod) { conditionsMatch = false; conditionSummary = string.Join(" | ", parts.ToArray()); return false; } } if (!string.IsNullOrEmpty(_options.WatchWindowContains)) { bool match = ForegroundWindowMatches(_options.WatchWindowContains); parts.Add("WatchWindow: " + (match ? "matched" : "not matched")); if (!match) { conditionsMatch = false; conditionSummary = string.Join(" | ", parts.ToArray()); return false; } } if (_options.OnAcOnly) { bool onAc; string powerSummary; onAc = IsOnAc(out powerSummary); parts.Add(powerSummary); if (!onAc) { conditionsMatch = false; conditionSummary = string.Join(" | ", parts.ToArray()); return false; } } if (_options.CpuThresholdPercent.HasValue) { bool cpuOk; string cpuSummary; cpuOk = IsCpuAtOrAboveThreshold(_options.CpuThresholdPercent.Value, out cpuSummary); _lastCpuSummary = cpuSummary; parts.Add(cpuSummary); if (!cpuOk) { conditionsMatch = false; conditionSummary = string.Join(" | ", parts.ToArray()); return false; } } else { _lastCpuSummary = "CPU condition not configured."; } conditionsMatch = true; conditionSummary = string.Join(" | ", parts.ToArray()); return baseMode; } private void EvaluateEffectiveState(DateTime nowLocal, bool baseShouldBeActive, out bool effectiveActive, out string reason) { string timedSource; ManualOverrideKind timedStartupOverride = GetStartupTimedOverride(nowLocal, out timedSource); if (_manualOverrideKind != ManualOverrideKind.None) { effectiveActive = _manualOverrideKind == ManualOverrideKind.ForceActive; if (_manualOverrideUntilLocal.HasValue) { reason = "Manual " + (effectiveActive ? "active" : "inactive") + " until " + _manualOverrideUntilLocal.Value.ToString("HH:mm:ss"); } else { reason = "Manual " + (effectiveActive ? "active" : "inactive"); } return; } if (timedStartupOverride != ManualOverrideKind.None) { effectiveActive = timedStartupOverride == ManualOverrideKind.ForceActive; reason = timedSource; return; } effectiveActive = baseShouldBeActive; reason = baseShouldBeActive ? "Parameters/rules allow active" : "Parameters/rules inactive"; } private ManualOverrideKind GetStartupTimedOverride(DateTime nowLocal, out string source) { source = null; bool activeLive = _startupActiveUntilLocal.HasValue && nowLocal < _startupActiveUntilLocal.Value; bool inactiveLive = _startupInactiveUntilLocal.HasValue && nowLocal < _startupInactiveUntilLocal.Value; if (!activeLive && !inactiveLive) { return ManualOverrideKind.None; } // If both exist, later end time wins because it was most recently specified in typical use. if (activeLive && inactiveLive) { if (_startupInactiveUntilLocal.Value >= _startupActiveUntilLocal.Value) { source = "Startup inactivefor until " + _startupInactiveUntilLocal.Value.ToString("HH:mm:ss"); return ManualOverrideKind.ForceInactive; } source = "Startup activefor until " + _startupActiveUntilLocal.Value.ToString("HH:mm:ss"); return ManualOverrideKind.ForceActive; } if (activeLive) { source = "Startup activefor until " + _startupActiveUntilLocal.Value.ToString("HH:mm:ss"); return ManualOverrideKind.ForceActive; } source = "Startup inactivefor until " + _startupInactiveUntilLocal.Value.ToString("HH:mm:ss"); return ManualOverrideKind.ForceInactive; } private EffectiveMode GetActiveMode() { if (_options.AllowScreenSaver) { return EffectiveMode.ActiveStesSystemOnly; } if (_options.UseStes) { return EffectiveMode.ActiveStesSystemAndDisplay; } return EffectiveMode.ActiveKeyPulse; } private void ApplyActiveMode(EffectiveMode mode, DateTime nowUtc) { switch (mode) { case EffectiveMode.Inactive: ClearExecutionState(); return; case EffectiveMode.ActiveKeyPulse: PulseKeyIfDue(nowUtc); return; case EffectiveMode.ActiveStesSystemOnly: RefreshStesIfDue(nowUtc, NativeMethods.ES_CONTINUOUS | NativeMethods.ES_SYSTEM_REQUIRED); return; case EffectiveMode.ActiveStesSystemAndDisplay: RefreshStesIfDue(nowUtc, NativeMethods.ES_CONTINUOUS | NativeMethods.ES_SYSTEM_REQUIRED | NativeMethods.ES_DISPLAY_REQUIRED); return; } } private void ClearExecutionState() { try { NativeMethods.SetThreadExecutionState(NativeMethods.ES_CONTINUOUS); } catch { // Ignore. } } private void RefreshStesIfDue(DateTime nowUtc, uint flags) { if ((nowUtc - _lastStesRefreshUtc).TotalSeconds < 15) { return; } _lastStesRefreshUtc = nowUtc; try { NativeMethods.SetThreadExecutionState(flags); } catch { // Ignore. } } private void PulseKeyIfDue(DateTime nowUtc) { if ((nowUtc - _lastPulseUtc).TotalSeconds < 59) { return; } _lastPulseUtc = nowUtc; SendConfiguredKeyPulse(); } private void SendConfiguredKeyPulse() { byte vk = (byte)_options.VirtualKey; bool pressShiftModifier = _options.KeyWithShift; try { if (pressShiftModifier && vk != 0x10 && vk != 0xA0) { NativeMethods.keybd_event(0x10, 0, 0, UIntPtr.Zero); } NativeMethods.keybd_event(vk, 0, 0, UIntPtr.Zero); NativeMethods.keybd_event(vk, 0, NativeMethods.KEYEVENTF_KEYUP, UIntPtr.Zero); if (pressShiftModifier && vk != 0x10 && vk != 0xA0) { NativeMethods.keybd_event(0x10, 0, NativeMethods.KEYEVENTF_KEYUP, UIntPtr.Zero); } } catch { // Ignore. } } private void SetManualOverride(ManualOverrideKind kind, double? minutes) { _manualOverrideKind = kind; if (minutes.HasValue) { _manualOverrideUntilLocal = DateTime.Now.AddMinutes(minutes.Value); } else { _manualOverrideUntilLocal = null; } TickCore(); } private void ToggleManual() { bool currentEffective = _hasLastEffectiveActive && _lastEffectiveActive; SetManualOverride(currentEffective ? ManualOverrideKind.ForceInactive : ManualOverrideKind.ForceActive, null); } private void RevertToParameters() { _manualOverrideKind = ManualOverrideKind.None; _manualOverrideUntilLocal = null; TickCore(); } private void UpdateMenuState() { bool manualActive = _manualOverrideKind == ManualOverrideKind.ForceActive; bool manualInactive = _manualOverrideKind == ManualOverrideKind.ForceInactive; bool dialogVisible = _statusForm != null && !_statusForm.IsDisposed && _statusForm.Visible; _miActiveNow.Checked = manualActive && !_manualOverrideUntilLocal.HasValue; _miInactiveNow.Checked = manualInactive && !_manualOverrideUntilLocal.HasValue; _miTimed5.Checked = manualActive && IsMinutesApproximately(5); _miTimed15.Checked = manualActive && IsMinutesApproximately(15); _miTimed30.Checked = manualActive && IsMinutesApproximately(30); _miTimed60.Checked = manualActive && IsMinutesApproximately(60); _miTimed120.Checked = manualActive && IsMinutesApproximately(120); _miTimedInactive5.Checked = manualInactive && IsMinutesApproximately(5); _miTimedInactive15.Checked = manualInactive && IsMinutesApproximately(15); _miTimedInactive30.Checked = manualInactive && IsMinutesApproximately(30); _miRevert.Enabled = _manualOverrideKind != ManualOverrideKind.None; _miShowHide.Text = dialogVisible ? "Hide Status" : "Show Status"; string stateText = (_hasLastEffectiveActive && _lastEffectiveActive) ? "Active" : "Inactive"; _miStatus.Text = "Status: " + stateText + " | " + GetMethodSummary(); } private bool IsMinutesApproximately(int minutes) { if (!_manualOverrideUntilLocal.HasValue) { return false; } double diff = (_manualOverrideUntilLocal.Value - DateTime.Now).TotalMinutes; return diff > minutes - 1.1 && diff <= minutes + 0.1; } private void UpdateStatusForm() { if (_statusForm == null || _statusForm.IsDisposed) { return; } string state = (_hasLastEffectiveActive && _lastEffectiveActive) ? "ACTIVE" : "INACTIVE"; string detail = "Reason: " + _lastReason + Environment.NewLine + "Mode: " + GetMethodSummary() + " | Key: " + FormatVirtualKey(_options.VirtualKey) + (_options.KeyWithShift ? " + Shift" : string.Empty); if (_manualOverrideKind != ManualOverrideKind.None) { detail += Environment.NewLine + "Manual override: " + _manualOverrideKind.ToString() + (_manualOverrideUntilLocal.HasValue ? (" until " + _manualOverrideUntilLocal.Value.ToString("HH:mm:ss")) : string.Empty); } string condition = _lastConditionSummary; if (_options.CpuThresholdPercent.HasValue) { condition += Environment.NewLine + _lastCpuSummary; } if (_options.UnknownSwitches.Count > 0) { condition += Environment.NewLine + "Unknown switches ignored: " + string.Join(", ", _options.UnknownSwitches.ToArray()); } if (_options.AllowLocalCompat) { condition += Environment.NewLine + "Compatibility flag -allowlocal is recognized (no special handling required for local IPC)."; } _statusForm.UpdateView(state, detail, condition); } private void UpdateTrayTooltip(bool active, string reason) { string text = "Portable Caffeine: " + (active ? "Active" : "Inactive"); if (!string.IsNullOrEmpty(reason)) { text += " | " + reason; } if (text.Length > 63) { text = text.Substring(0, 63); } _tray.Text = text; } private void SetTrayIcon(bool active) { if (active) { _tray.Icon = _trayIconActive ?? SystemIcons.Information; } else { _tray.Icon = _options.NoHIcon ? (_trayIconActive ?? SystemIcons.Information) : (_trayIconInactive ?? SystemIcons.Warning); } } private void ShowNotify(string title, string text) { try { _tray.BalloonTipTitle = title; _tray.BalloonTipText = string.IsNullOrEmpty(text) ? string.Empty : text; _tray.BalloonTipIcon = ToolTipIcon.Info; _tray.ShowBalloonTip(1500); } catch { // Ignore notification failures. } } private void OnIpcPayload(object sender, string payload) { if (string.IsNullOrEmpty(payload)) { return; } string cmd = payload.Trim(); if (cmd.Length == 0) { return; } if (string.Equals(cmd, "EXIT_REPLACE", StringComparison.Ordinal)) { ExitApplication(); return; } if (cmd.StartsWith("APPCMD:", StringComparison.Ordinal)) { string name = cmd.Substring("APPCMD:".Length); ApplyRemoteCommand(name); return; } if (string.Equals(cmd, "SHOW", StringComparison.Ordinal)) { ShowStatusForm(true); } } private void ApplyRemoteCommand(string name) { if (string.IsNullOrEmpty(name)) { return; } if (string.Equals(name, "AppExit", StringComparison.OrdinalIgnoreCase)) { ExitApplication(); return; } if (string.Equals(name, "AppOn", StringComparison.OrdinalIgnoreCase)) { SetManualOverride(ManualOverrideKind.ForceActive, null); return; } if (string.Equals(name, "AppOff", StringComparison.OrdinalIgnoreCase)) { SetManualOverride(ManualOverrideKind.ForceInactive, null); return; } if (string.Equals(name, "AppToggle", StringComparison.OrdinalIgnoreCase)) { ToggleManual(); return; } if (string.Equals(name, "AppToggleShowDialog", StringComparison.OrdinalIgnoreCase)) { ToggleManual(); ShowStatusForm(true); return; } if (string.Equals(name, "ShowDialog", StringComparison.OrdinalIgnoreCase)) { ShowStatusForm(true); } } private void ExitApplication() { if (_disposed) { return; } ExitThread(); } protected override void ExitThreadCore() { if (_disposed) { base.ExitThreadCore(); return; } _disposed = true; try { ClearExecutionState(); } catch { } try { if (_timer != null) { _timer.Stop(); _timer.Dispose(); } } catch { } try { if (_tray != null) { _tray.Visible = false; _tray.Dispose(); } } catch { } try { if (_trayIconActive != null) { _trayIconActive.Dispose(); } if (_trayIconInactive != null) { _trayIconInactive.Dispose(); } } catch { } try { if (_ipcForm != null && !_ipcForm.IsDisposed) { _ipcForm.Close(); _ipcForm.Dispose(); } } catch { } try { if (_statusForm != null && !_statusForm.IsDisposed) { _statusForm.Close(); _statusForm.Dispose(); } } catch { } try { if (_cpuCounter != null) { _cpuCounter.Dispose(); } } catch { } try { if (_instanceMutex != null) { _instanceMutex.ReleaseMutex(); _instanceMutex.Dispose(); } } catch { } base.ExitThreadCore(); } private void TryInitCpuCounter() { try { _cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); _cpuCounter.NextValue(); _cpuCounterPrimed = false; _cpuCounterFailed = false; } catch { _cpuCounterFailed = true; _cpuCounter = null; } } private bool IsCpuAtOrAboveThreshold(int threshold, out string summary) { summary = "CPU >= " + threshold.ToString(CultureInfo.InvariantCulture) + "% required"; if (_cpuCounterFailed) { summary = "CPU counter unavailable (condition not met)"; return false; } if (_cpuCounter == null) { TryInitCpuCounter(); if (_cpuCounter == null) { summary = "CPU counter unavailable (condition not met)"; return false; } } try { float next = _cpuCounter.NextValue(); if (!_cpuCounterPrimed) { _cpuCounterPrimed = true; summary = "CPU warmup sample..."; return false; } _lastCpuPercent = next; bool ok = next >= threshold; summary = "CPU " + next.ToString("0.0", CultureInfo.InvariantCulture) + "% vs threshold " + threshold.ToString(CultureInfo.InvariantCulture) + "% (" + (ok ? "matched" : "below") + ")"; return ok; } catch { _cpuCounterFailed = true; summary = "CPU counter failed (condition not met)"; return false; } } private bool ForegroundWindowMatches(string needle) { try { IntPtr hwnd = NativeMethods.GetForegroundWindow(); if (hwnd == IntPtr.Zero) { return false; } int length = NativeMethods.GetWindowTextLength(hwnd); if (length <= 0) { return false; } StringBuilder sb = new StringBuilder(length + 1); NativeMethods.GetWindowText(hwnd, sb, sb.Capacity); string title = sb.ToString(); if (string.IsNullOrEmpty(title)) { return false; } return title.IndexOf(needle, StringComparison.OrdinalIgnoreCase) >= 0; } catch { return false; } } private bool IsOnAc(out string summary) { summary = "Power: unknown"; try { NativeMethods.SYSTEM_POWER_STATUS sps; if (!NativeMethods.GetSystemPowerStatus(out sps)) { summary = "Power status unavailable"; return false; } if (sps.ACLineStatus == 1) { summary = "Power: on AC"; return true; } if (sps.ACLineStatus == 0) { summary = "Power: on battery"; return false; } summary = "Power: AC unknown (allowing)"; return true; } catch { summary = "Power status error"; return false; } } private string GetMethodSummary() { EffectiveMode mode = GetActiveMode(); switch (mode) { case EffectiveMode.ActiveKeyPulse: return "KeyPulse"; case EffectiveMode.ActiveStesSystemOnly: return "STES(System)"; case EffectiveMode.ActiveStesSystemAndDisplay: return "STES(System+Display)"; default: return "Inactive"; } } private static string FormatVirtualKey(ushort vk) { return "0x" + vk.ToString("X2", CultureInfo.InvariantCulture); } } public static class Program { private const string MutexName = @"Local\PortableCaffeine.ZhornCompat"; [STAThread] public static int Main(string[] args) { return Run(args); } public static int Run(string[] args) { Options options = CommandLine.Parse(args); if (options.ShowHelp) { Console.WriteLine(BuildUsageText()); return 0; } bool createdNew; Mutex instanceMutex = null; try { instanceMutex = new Mutex(true, MutexName, out createdNew); } catch (Exception ex) { Console.Error.WriteLine("Failed to acquire single-instance mutex: " + ex.Message); return 2; } if (!createdNew) { try { if (options.ReplaceExisting) { IpcTransport.Send("EXIT_REPLACE"); instanceMutex.Dispose(); instanceMutex = null; DateTime deadline = DateTime.UtcNow.AddSeconds(8); while (DateTime.UtcNow < deadline) { Thread.Sleep(200); try { instanceMutex = new Mutex(true, MutexName, out createdNew); if (createdNew) { break; } instanceMutex.Dispose(); instanceMutex = null; } catch { // Keep retrying. } } if (!createdNew) { Console.Error.WriteLine("Could not replace existing instance (timeout)."); return 3; } } else { if (options.HasAnyAppCommand) { bool sent = IpcTransport.Send("APPCMD:" + options.AppCommand.ToString()); return sent ? 0 : 1; } bool showSent = IpcTransport.Send("SHOW"); return showSent ? 0 : 1; } } catch (Exception ex) { Console.Error.WriteLine("Failed to communicate with running instance: " + ex.Message); return 1; } } if (createdNew && options.HasAnyAppCommand && !options.ReplaceExisting) { // App commands target an existing instance only; no-op if nothing is running. try { instanceMutex.ReleaseMutex(); } catch { } instanceMutex.Dispose(); return 0; } try { if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) { Console.Error.WriteLine("This script must run in an STA PowerShell host (Windows PowerShell 5.1 console is typically STA)."); return 4; } Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); CaffeineAppContext ctx = null; try { ctx = new CaffeineAppContext(options, instanceMutex); instanceMutex = null; // ownership transferred Application.Run(ctx); } finally { if (ctx != null) { ctx.Dispose(); } } return 0; } catch (Exception ex) { Console.Error.WriteLine(ex.ToString()); return 5; } finally { if (instanceMutex != null) { try { instanceMutex.ReleaseMutex(); } catch { } try { instanceMutex.Dispose(); } catch { } } } } private static string BuildUsageText() { StringBuilder sb = new StringBuilder(); sb.AppendLine("Portable Caffeine (Zhorn-compatible, PowerShell + embedded C#)"); sb.AppendLine(); sb.AppendLine("Common switches:"); sb.AppendLine(" -on / -off Start active or inactive (default active)"); sb.AppendLine(" -activefor:N Force active for N minutes"); sb.AppendLine(" -inactivefor:N Force inactive for N minutes"); sb.AppendLine(" -exitafter:N Exit app after N minutes"); sb.AppendLine(" -showdlg Show status dialog"); sb.AppendLine(" -ontaskbar Show status dialog in taskbar"); sb.AppendLine(" -notify Balloon notifications on state changes"); sb.AppendLine(" -lock Lock workstation after startup"); sb.AppendLine(" -replace Replace a running instance"); sb.AppendLine(" -watchwindow:TEXT Only active when foreground window title contains TEXT"); sb.AppendLine(" -activeperiods:RANGES Active only within local time ranges (e.g. 08:00-12:00,13:00-17:00)"); sb.AppendLine(" -activehours:RANGES Alias of -activeperiods"); sb.AppendLine(" -onac Only active when on AC power"); sb.AppendLine(" -cpu:N Only active when total CPU >= N percent"); sb.AppendLine(" -stes Use SetThreadExecutionState instead of key pulse"); sb.AppendLine(" -allowss Allow screensaver (uses STES system-only mode)"); sb.AppendLine(" -useshift / -leftshift Use Shift / Left Shift instead of F15"); sb.AppendLine(" -key:NN or -keypress:NN Use custom virtual key (decimal or hex, e.g. 0x7E)"); sb.AppendLine(" -keyshift[:NN] Press key with Shift modifier; optional custom key"); sb.AppendLine(" -appexit Ask running instance to exit"); sb.AppendLine(" -appon / -appoff Ask running instance to force active/inactive"); sb.AppendLine(" -apptoggle Ask running instance to toggle"); sb.AppendLine(" -apptoggleshowdlg Toggle and show running instance status dialog"); sb.AppendLine(" -nohicon Use same tray icon while inactive"); sb.AppendLine(" -allowlocal Compatibility flag (recognized)"); return sb.ToString(); } } } '@ if (-not ('PortableCaffeine.Program' -as [type])) { Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing Add-Type -TypeDefinition $csharp -ReferencedAssemblies @( 'System.dll', 'System.Windows.Forms.dll', 'System.Drawing.dll' ) } $exitCode = [PortableCaffeine.Program]::Run([string[]]$args) exit $exitCode