diff --git a/GoToSleep.slnx b/GoToSleep.slnx
new file mode 100644
index 0000000..b7bfb4c
--- /dev/null
+++ b/GoToSleep.slnx
@@ -0,0 +1,3 @@
+
+
+
diff --git a/GoToSleep/CountdownForm.Designer.cs b/GoToSleep/CountdownForm.Designer.cs
new file mode 100644
index 0000000..0ec1ec3
--- /dev/null
+++ b/GoToSleep/CountdownForm.Designer.cs
@@ -0,0 +1,112 @@
+namespace GoToSleep
+{
+ partial class CountdownForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ countdown = new Label();
+ cancel = new Button();
+ execNow = new Button();
+ tableLayoutPanel1 = new TableLayoutPanel();
+ tableLayoutPanel1.SuspendLayout();
+ SuspendLayout();
+ //
+ // countdown
+ //
+ countdown.AutoSize = true;
+ tableLayoutPanel1.SetColumnSpan(countdown, 2);
+ countdown.Dock = DockStyle.Fill;
+ countdown.Font = new Font("Segoe UI", 27.75F, FontStyle.Regular, GraphicsUnit.Point, 238);
+ countdown.Location = new Point(3, 0);
+ countdown.Name = "countdown";
+ countdown.Size = new Size(478, 63);
+ countdown.TabIndex = 0;
+ countdown.Text = "Time Remaining: 99:99:99";
+ countdown.TextAlign = ContentAlignment.MiddleCenter;
+ countdown.Click += countdown_Click;
+ //
+ // cancel
+ //
+ cancel.Anchor = AnchorStyles.Left;
+ cancel.Location = new Point(245, 68);
+ cancel.Name = "cancel";
+ cancel.Size = new Size(75, 23);
+ cancel.TabIndex = 1;
+ cancel.Text = "Cancel";
+ cancel.UseVisualStyleBackColor = true;
+ cancel.Click += cancel_Click;
+ //
+ // execNow
+ //
+ execNow.Anchor = AnchorStyles.Right;
+ execNow.Location = new Point(164, 68);
+ execNow.Name = "execNow";
+ execNow.Size = new Size(75, 23);
+ execNow.TabIndex = 2;
+ execNow.Text = "Execute";
+ execNow.UseVisualStyleBackColor = true;
+ execNow.Click += execNow_Click;
+ //
+ // tableLayoutPanel1
+ //
+ tableLayoutPanel1.ColumnCount = 2;
+ tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
+ tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50F));
+ tableLayoutPanel1.Controls.Add(countdown, 0, 0);
+ tableLayoutPanel1.Controls.Add(cancel, 1, 1);
+ tableLayoutPanel1.Controls.Add(execNow, 0, 1);
+ tableLayoutPanel1.Dock = DockStyle.Fill;
+ tableLayoutPanel1.Location = new Point(0, 0);
+ tableLayoutPanel1.Name = "tableLayoutPanel1";
+ tableLayoutPanel1.RowCount = 2;
+ tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
+ tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.Absolute, 33F));
+ tableLayoutPanel1.Size = new Size(484, 96);
+ tableLayoutPanel1.TabIndex = 3;
+ //
+ // CountdownForm
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(484, 96);
+ Controls.Add(tableLayoutPanel1);
+ MinimumSize = new Size(500, 135);
+ Name = "CountdownForm";
+ Text = "CountdownForm";
+ tableLayoutPanel1.ResumeLayout(false);
+ tableLayoutPanel1.PerformLayout();
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private Label countdown;
+ private Button cancel;
+ private Button execNow;
+ private TableLayoutPanel tableLayoutPanel1;
+ }
+}
\ No newline at end of file
diff --git a/GoToSleep/CountdownForm.cs b/GoToSleep/CountdownForm.cs
new file mode 100644
index 0000000..f125da1
--- /dev/null
+++ b/GoToSleep/CountdownForm.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.ComponentModel.Design;
+using System.Data;
+using System.Drawing;
+using System.Text;
+using System.Windows.Forms;
+using System.Threading;
+
+namespace GoToSleep
+{
+ public partial class CountdownForm : Form
+ {
+ public bool active = true;
+ private PowerDownData task;
+ private Thread taskThread;
+ public CountdownForm(PowerDownData taskData)
+ {
+ task = taskData;
+ InitializeComponent();
+ this.Text = task.actionType.ToString() + " Countdown";
+ countdown.Text = getTimerText();
+ taskThread = new Thread(threadFunction);
+ taskThread.Start();
+ }
+ string getTimerText()
+ {
+ var timeRemaining = task.when - DateTime.Now;
+ return $"Time Remaining: {(int)timeRemaining.TotalHours:D2}:{timeRemaining.Minutes:D2}:{timeRemaining.Seconds:D2}";
+ }
+
+ void updateTimer()
+ {
+
+ try
+ {
+ countdown.Invoke((MethodInvoker)delegate
+ {
+ countdown.Text = getTimerText();
+ });
+ }
+ catch (Exception e)
+ {
+ //the window most likely has been closed
+ return;
+ }
+ }
+
+ void threadFunction()
+ {
+ while (DateTime.Now < task.when)
+ {
+ Thread.Sleep(1000);
+ if (!active)
+ {
+ return;
+ }
+ updateTimer();
+
+ }
+ executeStateChange();
+ }
+
+ void executeStateChange()
+ {
+ active = false;
+ task.onCountdownEnd();
+
+ this.Invoke((MethodInvoker)delegate
+ {
+ this.Close();
+ });
+
+ }
+
+ private void execNow_Click(object sender, EventArgs e)
+ {
+ executeStateChange();
+ }
+
+ private void cancel_Click(object sender, EventArgs e)
+ {
+ active = false;
+ this.Close();
+ }
+
+ protected override void OnFormClosing(FormClosingEventArgs e)
+ {
+ base.OnFormClosing(e);
+ active = false;
+ }
+
+ private void countdown_Click(object sender, EventArgs e)
+ {
+
+ }
+ }
+}
diff --git a/GoToSleep/CountdownForm.resx b/GoToSleep/CountdownForm.resx
new file mode 100644
index 0000000..8b2ff64
--- /dev/null
+++ b/GoToSleep/CountdownForm.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/GoToSleep/GoToSleep.Designer.cs b/GoToSleep/GoToSleep.Designer.cs
new file mode 100644
index 0000000..e8611a1
--- /dev/null
+++ b/GoToSleep/GoToSleep.Designer.cs
@@ -0,0 +1,147 @@
+namespace GoToSleep
+{
+ partial class GoToSleep
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ comboBox1 = new ComboBox();
+ shutdownButton = new Button();
+ suspendButton = new Button();
+ hibernateButton = new Button();
+ textBox1 = new TextBox();
+ tableLayoutPanel2 = new TableLayoutPanel();
+ flowLayoutPanel1 = new FlowLayoutPanel();
+ tableLayoutPanel2.SuspendLayout();
+ flowLayoutPanel1.SuspendLayout();
+ SuspendLayout();
+ //
+ // comboBox1
+ //
+ comboBox1.FormattingEnabled = true;
+ comboBox1.Items.AddRange(new object[] { "In", "At" });
+ comboBox1.Location = new Point(3, 3);
+ comboBox1.MinimumSize = new Size(50, 0);
+ comboBox1.Name = "comboBox1";
+ comboBox1.Size = new Size(50, 23);
+ comboBox1.TabIndex = 0;
+ comboBox1.SelectedIndexChanged += comboBox1_SelectedIndexChanged;
+ //
+ // shutdownButton
+ //
+ shutdownButton.Location = new Point(185, 3);
+ shutdownButton.Margin = new Padding(3, 3, 0, 3);
+ shutdownButton.Name = "shutdownButton";
+ shutdownButton.Size = new Size(75, 23);
+ shutdownButton.TabIndex = 1;
+ shutdownButton.Text = "Shutdown";
+ shutdownButton.UseVisualStyleBackColor = true;
+ shutdownButton.Click += shutdownButton_Click;
+ //
+ // suspendButton
+ //
+ suspendButton.Location = new Point(104, 3);
+ suspendButton.Name = "suspendButton";
+ suspendButton.Size = new Size(75, 23);
+ suspendButton.TabIndex = 2;
+ suspendButton.Text = "Suspend";
+ suspendButton.UseVisualStyleBackColor = true;
+ suspendButton.Click += suspendButton_Click;
+ //
+ // hibernateButton
+ //
+ hibernateButton.Location = new Point(23, 3);
+ hibernateButton.Name = "hibernateButton";
+ hibernateButton.Size = new Size(75, 23);
+ hibernateButton.TabIndex = 3;
+ hibernateButton.Text = "Hibernate";
+ hibernateButton.UseVisualStyleBackColor = true;
+ hibernateButton.Click += hibernateButton_Click;
+ //
+ // textBox1
+ //
+ textBox1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
+ textBox1.Location = new Point(59, 3);
+ textBox1.Name = "textBox1";
+ textBox1.Size = new Size(422, 23);
+ textBox1.TabIndex = 4;
+ //
+ // tableLayoutPanel2
+ //
+ tableLayoutPanel2.AutoSizeMode = AutoSizeMode.GrowAndShrink;
+ tableLayoutPanel2.ColumnCount = 2;
+ tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle());
+ tableLayoutPanel2.ColumnStyles.Add(new ColumnStyle());
+ tableLayoutPanel2.Controls.Add(comboBox1, 0, 0);
+ tableLayoutPanel2.Controls.Add(textBox1, 1, 0);
+ tableLayoutPanel2.Controls.Add(flowLayoutPanel1, 1, 1);
+ tableLayoutPanel2.Dock = DockStyle.Fill;
+ tableLayoutPanel2.Location = new Point(0, 0);
+ tableLayoutPanel2.Name = "tableLayoutPanel2";
+ tableLayoutPanel2.RowCount = 2;
+ tableLayoutPanel2.RowStyles.Add(new RowStyle(SizeType.Absolute, 30F));
+ tableLayoutPanel2.RowStyles.Add(new RowStyle());
+ tableLayoutPanel2.Size = new Size(484, 64);
+ tableLayoutPanel2.TabIndex = 6;
+ //
+ // flowLayoutPanel1
+ //
+ flowLayoutPanel1.Anchor = AnchorStyles.Top | AnchorStyles.Right;
+ flowLayoutPanel1.Controls.Add(shutdownButton);
+ flowLayoutPanel1.Controls.Add(suspendButton);
+ flowLayoutPanel1.Controls.Add(hibernateButton);
+ flowLayoutPanel1.FlowDirection = FlowDirection.RightToLeft;
+ flowLayoutPanel1.Location = new Point(221, 33);
+ flowLayoutPanel1.Name = "flowLayoutPanel1";
+ flowLayoutPanel1.Size = new Size(260, 41);
+ flowLayoutPanel1.TabIndex = 7;
+ //
+ // GoToSleep
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(484, 64);
+ Controls.Add(tableLayoutPanel2);
+ MinimumSize = new Size(500, 103);
+ Name = "GoToSleep";
+ Text = "Go To Sleep";
+ tableLayoutPanel2.ResumeLayout(false);
+ tableLayoutPanel2.PerformLayout();
+ flowLayoutPanel1.ResumeLayout(false);
+ ResumeLayout(false);
+ }
+
+ #endregion
+
+ private ComboBox comboBox1;
+ private Button shutdownButton;
+ private Button suspendButton;
+ private Button hibernateButton;
+ private TextBox textBox1;
+ private TableLayoutPanel tableLayoutPanel2;
+ private FlowLayoutPanel flowLayoutPanel1;
+ }
+}
diff --git a/GoToSleep/GoToSleep.cs b/GoToSleep/GoToSleep.cs
new file mode 100644
index 0000000..e06fec1
--- /dev/null
+++ b/GoToSleep/GoToSleep.cs
@@ -0,0 +1,73 @@
+namespace GoToSleep
+{
+ public partial class GoToSleep : Form
+ {
+ string timeSelector = "in";
+ SystemPowerManager manager;
+ public GoToSleep()
+ {
+ InitializeComponent();
+ comboBox1.SelectedIndex = 0;
+ textBox1.Select();
+ manager = new SystemPowerManager(this);
+ }
+
+ private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ switch (comboBox1.SelectedIndex)
+ {
+ case 0:
+ timeSelector = "in";
+ break;
+ case 1:
+ timeSelector = "";
+ break;
+ default:
+ //this should never happen, something went very wrong, the combo box should only have 2 options
+ throw new Exception("Invalid selection index");
+ }
+
+
+ }
+
+ private string getTimeString()
+ {
+ return timeSelector + " " + textBox1.Text;
+ }
+
+ private void shutdownButton_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ manager.shutdown(getTimeString());
+ }
+ catch (Exception ex) {
+ MessageBox.Show(ex.Message);
+ }
+ }
+
+ private void suspendButton_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ manager.suspend(getTimeString());
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.Message);
+ }
+ }
+
+ private void hibernateButton_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ manager.hibernate(getTimeString());
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(ex.Message);
+ }
+ }
+ }
+}
diff --git a/GoToSleep/GoToSleep.csproj b/GoToSleep/GoToSleep.csproj
new file mode 100644
index 0000000..e94f50a
--- /dev/null
+++ b/GoToSleep/GoToSleep.csproj
@@ -0,0 +1,17 @@
+
+
+
+ WinExe
+ net10.0-windows
+ enable
+ true
+ enable
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GoToSleep/GoToSleep.resx b/GoToSleep/GoToSleep.resx
new file mode 100644
index 0000000..8b2ff64
--- /dev/null
+++ b/GoToSleep/GoToSleep.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/GoToSleep/PowerDownData.cs b/GoToSleep/PowerDownData.cs
new file mode 100644
index 0000000..cc77ff6
--- /dev/null
+++ b/GoToSleep/PowerDownData.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+
+namespace GoToSleep
+{
+ public class PowerDownData
+ {
+ public enum PowerDownType
+ {
+ Shutdown,
+ Suspend,
+ Hibernate
+ };
+
+ public PowerDownType actionType { get; }
+
+ public DateTime when { get; }
+
+ public delegate void Action();
+
+ public Action onCountdownEnd { get; }
+
+
+ private PowerDownData(PowerDownType _type, DateTime _when, Action action)
+ {
+ actionType = _type;
+ when = _when;
+ onCountdownEnd = action;
+ }
+ public static PowerDownData Shutdown(DateTime when)
+ {
+ return new PowerDownData(PowerDownType.Shutdown, when, () => {
+ var psi = new ProcessStartInfo("shutdown", "/s /t 0");
+ psi.CreateNoWindow = true;
+ psi.UseShellExecute = false;
+ Process.Start(psi);
+ });
+ }
+ public static PowerDownData Suspend(DateTime when)
+ {
+ return new PowerDownData(PowerDownType.Suspend, when, () => {
+ Application.SetSuspendState(PowerState.Suspend, false, false);
+ });
+ }
+ public static PowerDownData Hibernate(DateTime when)
+ {
+ return new PowerDownData(PowerDownType.Hibernate, when, () => {
+ Application.SetSuspendState(PowerState.Hibernate, false, false);
+ });
+ }
+ }
+}
diff --git a/GoToSleep/Program.cs b/GoToSleep/Program.cs
new file mode 100644
index 0000000..8724daa
--- /dev/null
+++ b/GoToSleep/Program.cs
@@ -0,0 +1,17 @@
+namespace GoToSleep
+{
+ internal static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ // To customize application configuration such as set high DPI settings or default font,
+ // see https://aka.ms/applicationconfiguration.
+ ApplicationConfiguration.Initialize();
+ Application.Run(new GoToSleep());
+ }
+ }
+}
\ No newline at end of file
diff --git a/GoToSleep/SystemPowerManager.cs b/GoToSleep/SystemPowerManager.cs
new file mode 100644
index 0000000..2627b8a
--- /dev/null
+++ b/GoToSleep/SystemPowerManager.cs
@@ -0,0 +1,150 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows.Forms.Design;
+using Chronic;
+using System.Diagnostics;
+using System.Windows.Forms;
+using System.Text.RegularExpressions;
+using Microsoft.Recognizers.Text;
+using Microsoft.Recognizers.Text.DateTime;
+using System.Globalization;
+
+namespace GoToSleep
+{
+ internal class SystemPowerManager
+ {
+ [Serializable]
+ class DatetimeStringException : Exception
+ {
+ public DatetimeStringException(string message) : base(message) { }
+ public DatetimeStringException(Exception e) : base("Conversion failed.", e) { }
+ }
+
+ [Serializable]
+ class DateTimeBeforeException : DatetimeStringException
+ {
+ public DateTimeBeforeException() : base("The entered date was in the past.")
+ {
+ }
+ }
+
+ [Serializable]
+ class ParseFailedException : DatetimeStringException
+ {
+ public ParseFailedException(Exception e) : base(e) { }
+ }
+
+ public SystemPowerManager(GoToSleep pf)
+ {
+ parentForm = pf;
+ }
+ Form parentForm;
+
+ Chronic.Parser parser = new Chronic.Parser();
+
+ string prepareTimeString(string s)
+ {
+ // make sure there are spaces between numbers and units, for the parser
+ s = Regex.Replace(s, "([0-9]+)([a-zA-Z]+)", "$1 $2");
+ s = Regex.Replace(s, "([a-zA-Z]+)([0-9]+)", "$1 $2");
+
+ // replace shorthands with full names, for the parser
+ s = Regex.Replace(s, "( )[hH]([ ]|$)", "$1hours$2");
+
+ s = Regex.Replace(s, "( )[mM]([ ]|$)", "$1minutes$2");
+
+ s = Regex.Replace(s, "( )[sS]([ ]|$)", "$1seconds$2");
+
+ return s;
+ }
+
+ DateTime getTimeOffsetFromString(string timeString)
+ {
+ DateTime result;
+ try
+ {
+ timeString = prepareTimeString(timeString);
+ //var tmp = parser.Parse(timeString);
+
+ var results = DateTimeRecognizer.RecognizeDateTime(timeString, CultureInfo.CurrentCulture.ToString());
+ if (results == null || results.Count == 0)
+ {
+ results = DateTimeRecognizer.RecognizeDateTime(timeString, Culture.English);
+ if (results == null || results.Count == 0)
+ {
+ throw new ArgumentException();
+ }
+ }
+
+ result = DateTime.Parse((results[0].Resolution["values"] as List>)[0]["value"]);
+
+ }
+ catch (Exception e)
+ {
+ throw new ParseFailedException(e);
+ }
+
+ if (result < DateTime.Now)
+ {
+ throw new DateTimeBeforeException();
+ }
+
+ return result;
+ }
+
+ public void shutdown(string timeString)
+ {
+ DateTime target;
+ try
+ {
+ target = getTimeOffsetFromString(timeString);
+ }
+ catch (Exception)
+ {
+ throw;
+ }
+
+ using (var progressPopup = new CountdownForm(PowerDownData.Shutdown(target)))
+ {
+ progressPopup.ShowDialog(parentForm);
+ }
+ }
+
+ public void suspend(string timeString)
+ {
+ DateTime target;
+ try
+ {
+ target = getTimeOffsetFromString(timeString);
+ }
+ catch (Exception)
+ {
+ throw;
+ }
+
+ using (var progressPopup = new CountdownForm(PowerDownData.Suspend(target)))
+ {
+ progressPopup.ShowDialog(parentForm);
+ }
+ }
+
+ public void hibernate(string timeString)
+ {
+ DateTime target;
+ try
+ {
+ target = getTimeOffsetFromString(timeString);
+ }
+ catch (Exception)
+ {
+ throw;
+ }
+
+ using (var progressPopup = new CountdownForm(PowerDownData.Hibernate(target)))
+ {
+ progressPopup.ShowDialog(parentForm);
+ }
+ }
+ }
+}