public static void OffIfIdle(int idleTimeMs, bool mute) { if (LastInput.GetLastInputAgeMs() >= idleTimeMs) { Off(mute); } }
private static void PartialWakeLogic(bool mute, int totalInputs = 1, PartialWakeNotifier pwn = null, int iterations = 0) { double inputsRequired = BPMath.Clamp(Program.settings.inputsRequiredToWake, 1, 50); const int maxIterations = 100; const int iterationInterval = 100; if (totalInputs >= inputsRequired) { // Input requirements met. Full Wake. if (pwn != null) { pwn.Terminate(); } } else if (iterations < maxIterations) { // Waiting for more inputs. if (pwn == null) { pwn = new PartialWakeNotifier(); pwn.Progress = (int)((totalInputs / inputsRequired) * 100); SetTimeout.OnBackground(() => { Application.Run(pwn); }, 0); } pwn.SetSecondsRemaining((int)(((maxIterations - iterations) * iterationInterval) / 1000.0)); SetTimeout.OnBackground(() => { if (LastInput.GetLastInputAgeMs() < maxIterations) { totalInputs++; pwn.Progress = (int)((totalInputs / inputsRequired) * 100); } PartialWakeLogic(mute, totalInputs, pwn, iterations + 1); }, iterationInterval); } else { // Input requires not met. Go back to sleep. if (pwn != null) { pwn.Terminate(); } Off(mute); } }
private static void WaitForWakeProcedure(object arg) { try { dynamic args = arg; uint lastInputAge = args.lastInputAge; Stopwatch sleepTimer = Stopwatch.StartNew(); int timesToSetOff = 12; // In theory the last input counter will roll over after 49.7102696 days. Or maybe it'll just stop incrementing? Either way, lets hope the PC doesn't stay idle that long. while (true) { uint inputAge = LastInput.GetLastInputAgeMs(); if (inputAge < lastInputAge || currentMonitorStatus != "off") { break; } lastInputAge = inputAge; Thread.Sleep(1000); if (timesToSetOff > 0 && sleepTimer.ElapsedMilliseconds >= 5000) { sleepTimer.Restart(); timesToSetOff--; SetMonitorInState(2); } } bool doPartialWakeLogic = Program.settings.inputsRequiredToWake > 1 && currentMonitorStatus == "off"; bool lastOffDidMute = didMute; currentMonitorStatus = "on"; UnmuteIfNeeded(); if (doPartialWakeLogic) { PartialWakeLogic(lastOffDidMute); } } catch (ThreadAbortException) { } catch (Exception ex) { Logger.Debug(ex); } }
public static void Off(bool mute) { UnmuteIfNeeded(); currentMonitorStatus = "off"; SetMonitorInState(2); uint lastInputAge = LastInput.GetLastInputAgeMs(); lock (myLock) { didMute = false; if (mute && !AudioManager.GetMasterVolumeMute()) { AudioManager.SetMasterVolumeMute(true); didMute = true; } StopMonitorOffThread(); StopWaitForWakeThread(); StartWaitForWakeThread(new { lastInputAge }); } }
public override void handleGETRequest(HttpProcessor p) { if (!Program.settings.IpIsWhitelisted(p.RemoteIPAddressStr)) { p.writeFailure("403 Forbidden"); return; } string successMessage = "<div>" + p.requestedPage + " command successful</div>"; List <KeyValuePair <string, string> > additionalHeaders = new List <KeyValuePair <string, string> >(); additionalHeaders.Add(new KeyValuePair <string, string>("Access-Control-Allow-Origin", "*")); if (p.requestedPage == "on") { On(p); } else if (p.requestedPage == "off") { int idleTimeMs = p.GetIntParam("ifidle", 0); int delayMs = p.GetIntParam("delay", 0); Action setOff = () => { if (idleTimeMs <= 0 || LastInput.GetLastInputAgeMs() >= idleTimeMs) { Off(p.GetBoolParam("mute")); } }; if (delayMs > 0) { SetTimeout.OnBackground(setOff, delayMs); } else { setOff(); } } else if (p.requestedPage == "off_if_idle") { OffIfIdle(Program.settings.idleTimeMs, p.GetBoolParam("mute")); } else if (p.requestedPage == "standby") { currentMonitorStatus = "off"; SetMonitorInState(1); } else if (p.requestedPage == "status") { p.writeSuccess("text/plain", additionalHeaders: additionalHeaders); p.outputStream.Write(currentMonitorStatus); return; } else if (p.requestedPage == "idle") { p.writeSuccess("text/plain", additionalHeaders: additionalHeaders); p.outputStream.Write(LastInput.GetLastInputAgeMs()); return; } else if (p.requestedPage == "smarttoggle") { if (currentMonitorStatus == "on") { OffIfIdle(Program.settings.idleTimeMs, p.GetBoolParam("mute")); } else { On(p); } } else if (p.requestedPage == "cancel") { StopMonitorOffThread(); } else if (p.requestedPage == "getvolume") { int level = 0; try { level = (int)Math.Round(AudioManager.GetMasterVolume()); //level = Audio.GetVolume(); } catch (Exception ex) { p.writeSuccess("text/plain; charset=utf-8", responseCode: "500 Internal Server Error"); p.outputStream.Write(ex.ToString()); return; } p.writeSuccess("text/plain"); p.outputStream.Write(level); } else if (p.requestedPage == "setvolume") { int level = p.GetIntParam("level"); level = level.Clamp(0, 100); try { AudioManager.SetMasterVolume(level); //Audio.SetVolume(level); } catch (Exception ex) { p.writeSuccess("text/plain; charset=utf-8", responseCode: "500 Internal Server Error"); p.outputStream.Write(ex.ToString()); return; } p.writeSuccess("text/plain"); p.outputStream.Write(level); } else if (p.requestedPage == "mute") { try { AudioManager.SetMasterVolumeMute(true); //Audio.SetMute(true); } catch (Exception ex) { p.writeSuccess("text/plain; charset=utf-8", responseCode: "500 Internal Server Error"); p.outputStream.Write(ex.ToString()); return; } p.writeSuccess("text/plain"); p.outputStream.Write("muted"); } else if (p.requestedPage == "unmute") { try { AudioManager.SetMasterVolumeMute(false); //Audio.SetMute(false); } catch (Exception ex) { p.writeSuccess("text/plain; charset=utf-8", responseCode: "500 Internal Server Error"); p.outputStream.Write(ex.ToString()); return; } p.writeSuccess("text/plain"); p.outputStream.Write("unmuted"); } else if (p.requestedPage == "getmute") { bool muted = false; try { muted = AudioManager.GetMasterVolumeMute(); //muted = Audio.GetMute(); } catch (Exception ex) { p.writeSuccess("text/plain; charset=utf-8", responseCode: "500 Internal Server Error"); p.outputStream.Write(ex.ToString()); return; } p.writeSuccess("text/plain"); p.outputStream.Write(muted ? "muted" : "unmuted"); } else if (p.requestedPage == "mousemove") { int dx = p.GetIntParam("dx"); // x change int dy = p.GetIntParam("dy"); // y change int delay = p.GetIntParam("delay").Clamp(1, 200); // Approximate milliseconds between movements. int times = p.GetIntParam("times").Clamp(1, 5000 / delay); // Number of times to perform the change. Limited to about 5 seconds of movement. try { DragMouse(dx, dy, delay, times); } catch (Exception ex) { p.writeSuccess("text/plain; charset=utf-8", responseCode: "500 Internal Server Error"); p.outputStream.Write(ex.ToString()); return; } p.writeSuccess("text/plain; charset=utf-8"); p.outputStream.Write("move complete. moved " + dx + "," + dy + " " + times + " times with " + delay + " ms delay"); } else if (p.requestedPage == "AllowLocalOverride") { Program.settings.syncAllowLocalOverride = true; Program.settings.Save(); p.writeSuccess("text/plain; charset=utf-8"); p.outputStream.Write("✅ Allow local input to override synced state"); } else if (p.requestedPage == "DisallowLocalOverride") { Program.settings.syncAllowLocalOverride = false; Program.settings.Save(); p.writeSuccess("text/plain; charset=utf-8"); p.outputStream.Write("❌ Allow local input to override synced state"); } else { successMessage = ""; } if (p.responseWritten) { return; } p.writeSuccess(additionalHeaders: additionalHeaders); p.outputStream.Write("<html><head><title>Monitor Control Service</title></head>" + "<style type=\"text/css\">" + " table { border-collapse: collapse; }" + " th, td { border: 1px solid black; padding: 3px 5px; }" + "</style>" + "<body>" + "<p class=\"result\">" + successMessage + "</p>" + "<p class=\"syncStatus\">(Remote server \"" + Program.settings.syncAddress + "\") " + HttpUtility.HtmlEncode(MonitorControlService.syncedServerStatus) + "</p>" + "<table>" //+ "<thead>" //+ "<tr><th></th><th></th></tr>" //+ "</thead>" + "<tbody>" + BuildRow("on", "turn displays on") + BuildRow("on?offAfterSecs=15", "turn displays on, then after 15 seconds, off") + BuildRow("cancel", "cancel a scheduled monitor off command (see above)") + BuildRow("off", "turn displays off") + BuildRow("off?ifidle=3000", "turn displays off if idle for 3000ms") + BuildRow("off?delay=3000&ifidle=2900", "wait 3000ms, then turn displays off if idle for 2900ms") + BuildRow("off?delay=3000&ifidle=2900&mute=1", "wait 3000ms, then turn displays off if idle for 2900ms, and also mute until the computer is no longer idle") + BuildRow("off_if_idle", "turn displays off if idle for the configured idle time (" + Program.settings.idleTimeMs + " ms)") + BuildRow("off_if_idle?mute=1", "turn displays off if idle for the configured idle time (" + Program.settings.idleTimeMs + " ms). Also mute until the computer is no longer idle.") + BuildRow("standby", "change displays to standby state -- probably does nothing") + BuildRow("status", "return the current status (\"on\" or \"off\")") + BuildRow("idle", "return the time in milliseconds since the last user input") + BuildRow("smarttoggle", "if status is \"on\" then <b>off_if_idle</b>, else <b>on</b>. Also supports the <b>mute</b> boolean argument.") + BuildRow("getvolume", "returns default audio device volume from 0 to 100") + BuildRow("setvolume?level=10", "sets default audio device volume from 0 to 100") + BuildRow("mute", "mutes default audio device") + BuildRow("unmute", "unmutes default audio device") + BuildRow("getmute", "returns \"muted\" or \"unmuted\"") + BuildRow("mousemove?dx=2&dy=-2&delay=4×=5", "moves the mouse cursor up 2px and to the right 2px, 5 times, waiting 4ms between each movement. Max delay 200ms. Max 5 seconds movement per command.") + BuildRow("AllowLocalOverride", "Enables the setting \"Allow local input to override synced state\"") + BuildRow("DisallowLocalOverride", "Disables the setting \"Allow local input to override synced state\"") + "</tbody>" + "</table>" + "</body>" + "</html>"); }