Skip to content

Instantly share code, notes, and snippets.

@macintoxic
Created May 16, 2025 17:55
Show Gist options
  • Save macintoxic/6cd8c0fcfc71f661e3941a3a5fbd2c0c to your computer and use it in GitHub Desktop.
Save macintoxic/6cd8c0fcfc71f661e3941a3a5fbd2c0c to your computer and use it in GitHub Desktop.
mopheus.override
using System.Runtime.InteropServices;
namespace MorpheusOverride;
class MorpheusApp
{
private NotifyIcon trayIcon;
private System.Timers.Timer keepAwakeTimer;
private AwakeMode currentMode = AwakeMode.Disabled;
private DateTime expirationTime = DateTime.MaxValue;
private bool keepDisplayOn = false;
private int timerHours = 2;
private int timerMinutes = 0;
private CancellationTokenSource tokenSource;
// Custom tray times in seconds
private readonly (string label, int seconds)[] customTrayTimes = new[]
{
("30 minutes", 1800),
("1 hour", 3600),
("2 hours", 7200),
("4 hours", 14400),
("8 hours", 28800)
};
// Initialize application
public void Initialize(string[] args)
{
// Create tray icon and context menu
trayIcon = new NotifyIcon
{
Icon = SystemIcons.Information,
Visible = true,
Text = "Morpheus Override"
};
// Parse command-line arguments
ParseCommandLineArgs(args);
// Create context menu
UpdateContextMenu();
// Initialize keep-awake timer
keepAwakeTimer = new System.Timers.Timer(1000);
keepAwakeTimer.Elapsed += (s, e) => UpdateKeepAwake();
keepAwakeTimer.Start();
// Start in the appropriate mode if specified by arguments
if (currentMode != AwakeMode.Disabled)
{
StartKeepAwake();
}
}
// Parse command-line arguments
private void ParseCommandLineArgs(string[] args)
{
if (args.Length == 0)
{
// Default: indefinite mode if no args provided
currentMode = AwakeMode.Indefinite;
return;
}
for (var i = 0; i < args.Length; i++)
{
var arg = args[i].ToLower();
if (arg == "--help" || arg == "-h")
{
ShowHelp();
Environment.Exit(0);
}
else if (arg == "--display-on" || arg == "-d")
{
keepDisplayOn = true;
}
else if (arg == "--display-off" || arg == "-o")
{
keepDisplayOn = false;
}
else if ((arg == "--time-limit" || arg == "-t") && i + 1 < args.Length)
{
if (TryParseTimeLimit(args[++i], out int hours, out int minutes))
{
currentMode = AwakeMode.Timer;
timerHours = hours;
timerMinutes = minutes;
}
}
else if ((arg == "--expire-at" || arg == "-e") && i + 1 < args.Length)
{
if (TryParseExpireAt(args[++i], out DateTime expireTime))
{
currentMode = AwakeMode.Expirable;
expirationTime = expireTime;
}
}
else if (arg == "--disable" || arg == "-x")
{
currentMode = AwakeMode.Disabled;
}
}
}
// Parse time limit argument (h:mm format)
private bool TryParseTimeLimit(string timeLimit, out int hours, out int minutes)
{
hours = 0;
minutes = 0;
// Try parse h:mm format
var parts = timeLimit.Split(':');
if (parts.Length == 2 && int.TryParse(parts[0], out hours) && int.TryParse(parts[1], out minutes))
{
return true;
}
// Try parse as total minutes
if (int.TryParse(timeLimit, out int totalMinutes))
{
hours = totalMinutes / 60;
minutes = totalMinutes % 60;
return true;
}
Console.WriteLine($"Invalid time format: {timeLimit}. Use h:mm or total minutes.");
return false;
}
// Parse expiration time argument
private bool TryParseExpireAt(string expireAt, out DateTime expireTime)
{
// Try parse as time (HH:mm:ss)
if (TimeSpan.TryParse(expireAt, out TimeSpan timeSpan))
{
DateTime now = DateTime.Now;
expireTime = new DateTime(now.Year, now.Month, now.Day,
timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds);
// If the time is already past for today, set it for tomorrow
if (expireTime < now)
{
expireTime = expireTime.AddDays(1);
}
return true;
}
// Try parse as full datetime
if (DateTime.TryParse(expireAt, out expireTime))
{
return true;
}
Console.WriteLine($"Invalid expiration time format: {expireAt}");
return false;
}
// Show help text
private void ShowHelp()
{
Console.WriteLine("Morpheus Override - Keep your PC awake");
Console.WriteLine("Usage: MorpheusOverride.exe [options]");
Console.WriteLine();
Console.WriteLine("Options:");
Console.WriteLine(" -h, --help Show this help message");
Console.WriteLine(" -d, --display-on Keep display on");
Console.WriteLine(" -o, --display-off Allow display to turn off (default)");
Console.WriteLine(" -t, --time-limit <time> Keep awake for specified time (h:mm or total minutes)");
Console.WriteLine(" -e, --expire-at <time> Keep awake until specified time (HH:mm:ss or full datetime)");
Console.WriteLine(" -x, --disable Disable keep-awake functionality");
Console.WriteLine();
Console.WriteLine("If no arguments are provided, the computer will be kept awake indefinitely.");
}
// Update the tray icon context menu
private void UpdateContextMenu()
{
var menu = new ContextMenuStrip();
// Add mode items
var keepScreenOnItem = new ToolStripMenuItem("Keep screen on");
keepScreenOnItem.Click += (s, e) => {
keepDisplayOn = !keepDisplayOn;
UpdateContextMenu();
UpdateKeepAwake();
};
keepScreenOnItem.Checked = keepDisplayOn;
menu.Items.Add(keepScreenOnItem);
menu.Items.Add(new ToolStripSeparator());
var modeMenu = new ToolStripMenuItem("Mode");
var disabledItem = new ToolStripMenuItem("Disabled");
disabledItem.Click += (s, e) => SwitchMode(AwakeMode.Disabled);
disabledItem.Checked = currentMode == AwakeMode.Disabled;
modeMenu.DropDownItems.Add(disabledItem);
var indefiniteItem = new ToolStripMenuItem("Indefinite");
indefiniteItem.Click += (s, e) => SwitchMode(AwakeMode.Indefinite);
indefiniteItem.Checked = currentMode == AwakeMode.Indefinite;
modeMenu.DropDownItems.Add(indefiniteItem);
// Add timed mode option
var timedMenuItem = new ToolStripMenuItem("Timed");
timedMenuItem.Click += (s, e) => SwitchMode(AwakeMode.Timer);
timedMenuItem.Checked = currentMode == AwakeMode.Timer;
modeMenu.DropDownItems.Add(timedMenuItem);
menu.Items.Add(modeMenu);
// Add custom time selections
var customTimeMenu = new ToolStripMenuItem("Keep awake temporarily");
foreach (var (label, seconds) in customTrayTimes)
{
var tempItem = new ToolStripMenuItem(label);
tempItem.Click += (s, e) => {
SetTempAwakeTime(seconds);
};
customTimeMenu.DropDownItems.Add(tempItem);
}
menu.Items.Add(customTimeMenu);
menu.Items.Add(new ToolStripSeparator());
var exitItem = new ToolStripMenuItem("Exit");
exitItem.Click += (s, e) => ExitApplication();
menu.Items.Add(exitItem);
// Update tray icon
trayIcon.ContextMenuStrip = menu;
UpdateTrayIcon();
}
// Switch between different awake modes
private void SwitchMode(AwakeMode newMode)
{
currentMode = newMode;
switch (newMode)
{
case AwakeMode.Disabled:
StopKeepAwake();
break;
case AwakeMode.Indefinite:
case AwakeMode.Timer:
case AwakeMode.Expirable:
StartKeepAwake();
break;
}
UpdateContextMenu();
}
// Set temporary awake time
private void SetTempAwakeTime(int seconds)
{
currentMode = AwakeMode.Timer;
timerHours = seconds / 3600;
timerMinutes = (seconds % 3600) / 60;
expirationTime = DateTime.Now.AddSeconds(seconds);
StartKeepAwake();
UpdateContextMenu();
}
// Start keep-awake functionality
private void StartKeepAwake()
{
// Create a new cancellation token to stop any previous keep-awake task
tokenSource?.Cancel();
tokenSource = new CancellationTokenSource();
// Start a background task to keep the system awake
Task.Run(() => KeepSystemAwake(tokenSource.Token), tokenSource.Token);
}
// Stop keep-awake functionality
private void StopKeepAwake()
{
// Cancel any running keep-awake task
tokenSource?.Cancel();
// Reset execution state to allow normal power management
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS);
}
// Keep the system awake
private async Task KeepSystemAwake(CancellationToken cancellationToken)
{
try
{
while (!cancellationToken.IsCancellationRequested)
{
// Check if we've reached the expiration time for timer/expirable modes
if ((currentMode == AwakeMode.Timer || currentMode == AwakeMode.Expirable) &&
DateTime.Now >= expirationTime)
{
// Timer expired, switch to disabled mode
currentMode = AwakeMode.Disabled;
StopKeepAwake();
// Show notification (runs on UI thread since NotifyIcon handles this internally)
trayIcon.ShowBalloonTip(3000, "Morpheus Override",
"Keep-awake timer has expired.", ToolTipIcon.Info);
// Update context menu on next access
UpdateContextMenu();
break;
}
// Set thread execution state based on current settings
UpdateKeepAwake();
// Wait before checking again
await Task.Delay(1000, cancellationToken);
}
}
catch (OperationCanceledException)
{
// Task was cancelled, which is fine
}
}
// Update the thread execution state based on current settings
private void UpdateKeepAwake()
{
if (currentMode == AwakeMode.Disabled)
{
// Allow system to enter sleep mode normally
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS);
return;
}
// Set flags based on current mode
EXECUTION_STATE flags = EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_SYSTEM_REQUIRED;
if (keepDisplayOn)
{
flags |= EXECUTION_STATE.ES_DISPLAY_REQUIRED;
}
// Set thread execution state
SetThreadExecutionState(flags);
}
// Update tray icon based on current state
private void UpdateTrayIcon()
{
var tooltip = "Morpheus Override - ";
switch (currentMode)
{
case AwakeMode.Disabled:
trayIcon.Icon = SystemIcons.Information;
tooltip += "Disabled";
break;
case AwakeMode.Indefinite:
trayIcon.Icon = keepDisplayOn ? SystemIcons.Warning : SystemIcons.Shield;
tooltip += "Keeping PC awake indefinitely";
break;
case AwakeMode.Timer:
trayIcon.Icon = keepDisplayOn ? SystemIcons.Warning : SystemIcons.Shield;
TimeSpan remaining = expirationTime - DateTime.Now;
tooltip += $"Keeping PC awake for {remaining.Hours}h {remaining.Minutes}m";
break;
case AwakeMode.Expirable:
trayIcon.Icon = keepDisplayOn ? SystemIcons.Warning : SystemIcons.Shield;
tooltip += $"Keeping PC awake until {expirationTime:HH:mm:ss}";
break;
}
if (keepDisplayOn)
{
tooltip += " (display on)";
}
trayIcon.Text = tooltip;
}
// Exit the application
private void ExitApplication()
{
// Make sure to stop keep-awake before exiting
StopKeepAwake();
// Clean up tray icon
trayIcon.Visible = false;
trayIcon.Dispose();
// Exit application
Application.Exit();
}
#region Native Windows API
// Execution state flags
[Flags]
public enum EXECUTION_STATE : uint
{
ES_AWAYMODE_REQUIRED = 0x00000040,
ES_CONTINUOUS = 0x80000000,
ES_DISPLAY_REQUIRED = 0x00000002,
ES_SYSTEM_REQUIRED = 0x00000001
}
// Import SetThreadExecutionState API from kernel32.dll
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment