mirror of
https://github.com/Maassoft/ColorControl.git
synced 2026-10-21 08:09:49 -05:00
819 lines
30 KiB
C#
819 lines
30 KiB
C#
using LgTv;
|
|
using Microsoft.Win32;
|
|
using Newtonsoft.Json;
|
|
using NWin32;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
|
|
namespace ColorControl
|
|
{
|
|
class LgService : ServiceBase<LgPreset>
|
|
{
|
|
internal enum PowerOnOffState
|
|
{
|
|
StartUp = 1,
|
|
Resume = 2,
|
|
ScreenSaver = 3,
|
|
ShutDown = 4,
|
|
StandBy = 5
|
|
}
|
|
|
|
internal class ProcessMonitorContext
|
|
{
|
|
public List<LgDevice> Devices { get; set; }
|
|
public bool WasFullScreen { get; set; }
|
|
public Process[] StartedProcesses { get; set; }
|
|
public Process[] StoppedProcesses { get; set; }
|
|
public Process[] RunningProcesses { get; set; }
|
|
public bool IsNotificationDisabled { get; set; }
|
|
public Process ForegroundProcess { get; set; }
|
|
public bool ForegroundProcessIsFullScreen { get; set; }
|
|
public string LastFullScreenProcessName = string.Empty;
|
|
}
|
|
|
|
protected static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
|
|
|
|
public static string LgListAppsJson = "listApps.json";
|
|
|
|
public List<LgDevice> Devices { get; private set; }
|
|
public LgDevice SelectedDevice
|
|
{
|
|
get { return _selectedDevice; }
|
|
set
|
|
{
|
|
_selectedDevice = value;
|
|
Config.PreferredMacAddress = _selectedDevice != null ? _selectedDevice.MacAddress : null;
|
|
}
|
|
}
|
|
|
|
public LgServiceConfig Config { get; private set; }
|
|
|
|
private string _configFilename;
|
|
private bool _allowPowerOn;
|
|
private LgDevice _selectedDevice;
|
|
private string _rcButtonsFilename;
|
|
private List<LgPreset> _remoteControlButtons;
|
|
private List<LgApp> _lgApps = new List<LgApp>();
|
|
|
|
private bool _poweredOffByScreenSaver;
|
|
private int _poweredOffByScreenSaverProcessId;
|
|
private Task _monitorTask;
|
|
private int _monitorTaskCounter;
|
|
private LgPreset _lastTriggeredPreset;
|
|
|
|
public LgService(string dataPath, bool allowPowerOn) : base(dataPath, "LgPresets.json")
|
|
{
|
|
_allowPowerOn = allowPowerOn;
|
|
|
|
LgPreset.LgApps = _lgApps;
|
|
|
|
LoadConfig();
|
|
LoadPresets();
|
|
LoadRemoteControlButtons();
|
|
}
|
|
|
|
~LgService()
|
|
{
|
|
GlobalSave();
|
|
}
|
|
|
|
public static async Task<bool> ExecutePresetAsync(string presetName)
|
|
{
|
|
try
|
|
{
|
|
var lgService = new LgService(Program.DataDir, true);
|
|
await lgService.RefreshDevices(afterStartUp: true);
|
|
|
|
var result = await lgService.ApplyPreset(presetName);
|
|
|
|
if (!result)
|
|
{
|
|
Console.WriteLine("Preset not found or error while executing.");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("Error executing preset: " + ex.ToLogString());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public void GlobalSave()
|
|
{
|
|
SaveConfig();
|
|
SavePresets();
|
|
SaveRemoteControlButtons();
|
|
}
|
|
|
|
public LgPreset CreateNewPreset()
|
|
{
|
|
var preset = new LgPreset();
|
|
var name = "New preset";
|
|
string fullname;
|
|
var number = 1;
|
|
do
|
|
{
|
|
fullname = $"{name} ({number})";
|
|
number++;
|
|
} while (_presets.Any(x => x.name.Equals(fullname)));
|
|
|
|
preset.name = fullname;
|
|
|
|
return preset;
|
|
}
|
|
protected override List<LgPreset> GetDefaultPresets()
|
|
{
|
|
List<LgPreset> presets = null;
|
|
|
|
var defaultPresetsFileName = Path.Combine(Directory.GetCurrentDirectory(), "LgPresets.json");
|
|
if (File.Exists(defaultPresetsFileName))
|
|
{
|
|
var json = File.ReadAllText(defaultPresetsFileName);
|
|
|
|
presets = _JsonDeserializer.Deserialize<List<LgPreset>>(json);
|
|
}
|
|
|
|
return presets;
|
|
}
|
|
|
|
private void LoadConfig()
|
|
{
|
|
_configFilename = Path.Combine(_dataPath, "LgConfig.json");
|
|
if (File.Exists(_configFilename))
|
|
{
|
|
Config = JsonConvert.DeserializeObject<LgServiceConfig>(File.ReadAllText(_configFilename));
|
|
}
|
|
else
|
|
{
|
|
Config = new LgServiceConfig();
|
|
}
|
|
|
|
LgPreset.LgDevices = Config.Devices;
|
|
}
|
|
|
|
private void LoadRemoteControlButtons()
|
|
{
|
|
var defaultButtons = GenerateDefaultRemoteControlButtons();
|
|
|
|
_rcButtonsFilename = Path.Combine(_dataPath, "LgRemoteControlButtons.json");
|
|
//if (File.Exists(_rcButtonsFilename))
|
|
//{
|
|
// var json = File.ReadAllText(_rcButtonsFilename);
|
|
|
|
// _remoteControlButtons = _JsonDeserializer.Deserialize<List<LgPreset>>(json);
|
|
|
|
// var missingButtons = defaultButtons.Where(b => !_remoteControlButtons.Any(x => x.name.Equals(b.name)));
|
|
// _remoteControlButtons.AddRange(missingButtons);
|
|
//}
|
|
//else
|
|
{
|
|
_remoteControlButtons = defaultButtons;
|
|
}
|
|
}
|
|
|
|
public List<LgPreset> GetRemoteControlButtons()
|
|
{
|
|
return _remoteControlButtons;
|
|
}
|
|
|
|
private List<LgPreset> GenerateDefaultRemoteControlButtons()
|
|
{
|
|
var list = new List<LgPreset>();
|
|
|
|
for (var i = 1; i < 11; i++)
|
|
{
|
|
var button = i < 10 ? i : 0;
|
|
list.Add(GeneratePreset(button.ToString()));
|
|
}
|
|
|
|
list.Add(GeneratePreset("Power", step: "POWER"));
|
|
list.Add(GeneratePreset("Home", appId: "com.webos.app.home", key: Keys.H));
|
|
list.Add(GeneratePreset("Settings", appId: "com.palm.app.settings", key: Keys.S));
|
|
list.Add(GeneratePreset("TV Guide", appId: "com.webos.app.livemenu"));
|
|
list.Add(GeneratePreset("List", step: "LIST"));
|
|
list.Add(GeneratePreset("SAP", step: "SAP"));
|
|
|
|
list.Add(GeneratePreset("Vol +", step: "VOLUMEUP", key: Keys.VolumeUp));
|
|
list.Add(GeneratePreset("Vol -", step: "VOLUMEDOWN", key: Keys.VolumeDown));
|
|
list.Add(GeneratePreset("Mute", step: "MUTE", key: Keys.VolumeMute));
|
|
list.Add(GeneratePreset("Channel +", step: "CHANNELUP", key: Keys.MediaNextTrack));
|
|
list.Add(GeneratePreset("Channel -", step: "CHANNELDOWN", key: Keys.MediaPreviousTrack));
|
|
|
|
list.Add(GeneratePreset("Up", step: "UP", key: Keys.Up));
|
|
list.Add(GeneratePreset("Down", step: "DOWN", key: Keys.Down));
|
|
list.Add(GeneratePreset("Left", step: "LEFT", key: Keys.Left));
|
|
list.Add(GeneratePreset("Right", step: "RIGHT", key: Keys.Right));
|
|
|
|
list.Add(GeneratePreset("Enter", step: "ENTER", key: Keys.Enter));
|
|
list.Add(GeneratePreset("Back", step: "BACK", key: Keys.Back));
|
|
list.Add(GeneratePreset("Exit", step: "EXIT", key: Keys.Escape));
|
|
|
|
list.Add(GeneratePreset("Netflix", appId: "netflix"));
|
|
list.Add(GeneratePreset("Inputs", appId: "com.webos.app.homeconnect"));
|
|
list.Add(GeneratePreset("Amazon Prime", appId: "amazon"));
|
|
|
|
list.Add(GeneratePreset("Red", step: "RED"));
|
|
list.Add(GeneratePreset("Green", step: "GREEN"));
|
|
list.Add(GeneratePreset("Yellow", step: "YELLOW"));
|
|
list.Add(GeneratePreset("Blue", step: "BLUE"));
|
|
|
|
list.Add(GeneratePreset("Rakuten TV", appId: "ui30"));
|
|
list.Add(GeneratePreset("Play", step: "PLAY"));
|
|
list.Add(GeneratePreset("Pause", step: "PAUSE"));
|
|
|
|
return list;
|
|
}
|
|
|
|
private LgPreset GeneratePreset(string name, string step = null, string appId = null, Keys key = Keys.None)
|
|
{
|
|
var preset = new LgPreset();
|
|
|
|
var cvt = new KeysConverter();
|
|
var shortcut = key != Keys.None ? (string)cvt.ConvertTo(key, typeof(string)) : null;
|
|
|
|
preset.name = name;
|
|
preset.appId = appId;
|
|
preset.shortcut = shortcut;
|
|
if (appId == null)
|
|
{
|
|
preset.steps.Add(step == null ? name : step);
|
|
}
|
|
|
|
return preset;
|
|
}
|
|
|
|
private void SavePresets()
|
|
{
|
|
try
|
|
{
|
|
var json = _JsonSerializer.Serialize(_presets);
|
|
File.WriteAllText(_presetsFilename, json);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.Error(e.ToLogString());
|
|
}
|
|
}
|
|
|
|
private void SaveConfig()
|
|
{
|
|
Config.PowerOnAfterStartup = Devices?.Any(d => d.PowerOnAfterStartup) ?? false;
|
|
|
|
var json = JsonConvert.SerializeObject(Config);
|
|
File.WriteAllText(_configFilename, json);
|
|
}
|
|
|
|
private void SaveRemoteControlButtons()
|
|
{
|
|
var json = JsonConvert.SerializeObject(_remoteControlButtons);
|
|
File.WriteAllText(_rcButtonsFilename, json);
|
|
}
|
|
|
|
public async Task RefreshDevices(bool connect = true, bool afterStartUp = false)
|
|
{
|
|
Devices = Config.Devices;
|
|
var customIpAddresses = Devices.Where(d => d.IsCustom).Select(d => d.IpAddress);
|
|
|
|
var pnpDevices = await Utils.GetPnpDevices(Config.DeviceSearchKey);
|
|
|
|
var autoDevices = pnpDevices.Where(p => !customIpAddresses.Contains(p.IpAddress)).Select(d => new LgDevice(d.Name, d.IpAddress, d.MacAddress, false)).ToList();
|
|
var autoIpAddresses = pnpDevices.Select(d => d.IpAddress);
|
|
|
|
Devices.RemoveAll(d => !d.IsCustom && !autoIpAddresses.Contains(d.IpAddress));
|
|
|
|
var newAutoDevices = autoDevices.Where(ad => !Devices.Any(d => d.IpAddress.Equals(ad.IpAddress)));
|
|
Devices.AddRange(newAutoDevices);
|
|
|
|
if (Devices.Any())
|
|
{
|
|
var preferredDevice = Devices.FirstOrDefault(x => x.MacAddress != null && x.MacAddress.Equals(Config.PreferredMacAddress)) ?? Devices[0];
|
|
|
|
SelectedDevice = preferredDevice;
|
|
}
|
|
else
|
|
{
|
|
SelectedDevice = null;
|
|
}
|
|
|
|
if (afterStartUp && SelectedDevice == null && Config.PowerOnAfterStartup && !string.IsNullOrEmpty(Config.PreferredMacAddress))
|
|
{
|
|
Logger.Debug("No device has been found, trying to wake it first...");
|
|
|
|
var tempDevice = new LgDevice("Test", string.Empty, Config.PreferredMacAddress);
|
|
tempDevice.Wake();
|
|
|
|
await Task.Delay(4000);
|
|
await RefreshDevices();
|
|
|
|
return;
|
|
}
|
|
|
|
if (connect && SelectedDevice != null)
|
|
{
|
|
if (_allowPowerOn)
|
|
{
|
|
WakeAfterStartupOrResume();
|
|
}
|
|
else
|
|
{
|
|
var _ = SelectedDevice.Connect();
|
|
}
|
|
}
|
|
}
|
|
|
|
public async Task<bool> ApplyPreset(string presetName)
|
|
{
|
|
var preset = _presets.FirstOrDefault(p => p.name.Equals(presetName, StringComparison.OrdinalIgnoreCase));
|
|
if (preset != null)
|
|
{
|
|
return await ApplyPreset(preset);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public async Task<bool> ApplyPreset(LgPreset preset, bool reconnect = false)
|
|
{
|
|
var device = GetPresetDevice(preset);
|
|
|
|
if (device == null)
|
|
{
|
|
Logger.Debug("Cannot apply preset: no device has been selected");
|
|
return false;
|
|
}
|
|
|
|
var result = await device.ExecutePreset(preset, reconnect, Config);
|
|
|
|
_lastAppliedPreset = preset;
|
|
|
|
return result;
|
|
}
|
|
|
|
public LgDevice GetPresetDevice(LgPreset preset)
|
|
{
|
|
var device = string.IsNullOrEmpty(preset.DeviceMacAddress)
|
|
? SelectedDevice
|
|
: Devices.FirstOrDefault(d => d.MacAddress?.Equals(preset.DeviceMacAddress, StringComparison.OrdinalIgnoreCase) ?? false);
|
|
return device;
|
|
}
|
|
|
|
public async Task<LgWebOsMouseService> GetMouseAsync()
|
|
{
|
|
return await SelectedDevice?.GetMouseAsync();
|
|
}
|
|
|
|
public async Task RefreshApps(bool force = false)
|
|
{
|
|
if (SelectedDevice == null)
|
|
{
|
|
Logger.Debug("Cannot refresh apps: no device has been selected");
|
|
return;
|
|
}
|
|
|
|
var apps = await SelectedDevice.GetApps(force);
|
|
|
|
if (apps.Any())
|
|
{
|
|
_lgApps.Clear();
|
|
_lgApps.AddRange(apps);
|
|
}
|
|
}
|
|
|
|
public List<LgApp> GetApps()
|
|
{
|
|
return _lgApps;
|
|
}
|
|
|
|
internal async Task<bool> PowerOff()
|
|
{
|
|
return await SelectedDevice?.PowerOff();
|
|
}
|
|
|
|
internal Task PowerOffOnShutdownOrResume(PowerOnOffState state = PowerOnOffState.ShutDown)
|
|
{
|
|
var devices = Devices.Where(d => state == PowerOnOffState.ShutDown && d.PowerOffOnShutdown ||
|
|
state == PowerOnOffState.StandBy && d.PowerOffOnStandby);
|
|
|
|
var tasks = new List<Task>();
|
|
foreach (var device in devices)
|
|
{
|
|
var task = device.PowerOff();
|
|
|
|
tasks.Add(task);
|
|
}
|
|
|
|
return Task.WhenAll(tasks.ToArray());
|
|
}
|
|
|
|
internal bool WakeSelectedDevice()
|
|
{
|
|
return SelectedDevice?.Wake() ?? false;
|
|
}
|
|
|
|
internal void WakeAfterStartupOrResume(PowerOnOffState state = PowerOnOffState.StartUp, bool checkUserSession = true)
|
|
{
|
|
if (checkUserSession && !UserSessionInfo.UserLocalSession)
|
|
{
|
|
Logger.Debug($"WakeAfterStartupOrResume: not waking because session info indicates no local session");
|
|
return;
|
|
}
|
|
|
|
var wakeDevices = Devices.Where(d => state == PowerOnOffState.StartUp && d.PowerOnAfterStartup ||
|
|
state == PowerOnOffState.Resume && d.PowerOnAfterResume ||
|
|
state == PowerOnOffState.ScreenSaver && d.PowerSwitchOnScreenSaver);
|
|
foreach (var device in wakeDevices)
|
|
{
|
|
if (device.PoweredOffBy == LgDevice.PowerOffSource.Manually)
|
|
{
|
|
Logger.Debug($"[{device.Name}]: device was manually powered off by user, not powering on");
|
|
continue;
|
|
}
|
|
|
|
device.DisposeConnection();
|
|
var _ = device.WakeAndConnectWithRetries(Config.PowerOnRetries);
|
|
}
|
|
}
|
|
|
|
public void InstallEventHandlers()
|
|
{
|
|
SystemEvents.PowerModeChanged -= PowerModeChanged;
|
|
SystemEvents.PowerModeChanged += PowerModeChanged;
|
|
//SystemEvents.SessionEnded -= SessionEnded;
|
|
//SystemEvents.SessionEnded += SessionEnded;
|
|
|
|
UserSessionInfo.UserSessionSwitch -= SessionSwitched;
|
|
UserSessionInfo.UserSessionSwitch += SessionSwitched;
|
|
|
|
MonitorProcesses();
|
|
}
|
|
|
|
private void SessionSwitched(bool toLocal)
|
|
{
|
|
if (toLocal)
|
|
{
|
|
if (_poweredOffByScreenSaver)
|
|
{
|
|
Logger.Debug("User switched to local and screen was powered off due to screensaver: waking up");
|
|
_poweredOffByScreenSaver = false;
|
|
_poweredOffByScreenSaverProcessId = 0;
|
|
WakeAfterStartupOrResume();
|
|
}
|
|
else
|
|
{
|
|
Logger.Debug("User switched to local but screen was not powered off by screensaver: NOT waking up");
|
|
}
|
|
}
|
|
}
|
|
|
|
private void PowerModeChanged(object sender, PowerModeChangedEventArgs e)
|
|
{
|
|
var powerOn = e.Mode == PowerModes.Resume;
|
|
|
|
Logger.Debug($"PowerModeChanged: {e.Mode}");
|
|
|
|
if (powerOn)
|
|
{
|
|
WakeAfterStartupOrResume(PowerOnOffState.Resume);
|
|
return;
|
|
}
|
|
|
|
if (Devices.Any(d => d.PowerOffOnStandby))
|
|
{
|
|
NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS | NativeConstants.ES_SYSTEM_REQUIRED | NativeConstants.ES_AWAYMODE_REQUIRED);
|
|
try
|
|
{
|
|
var standByScript = Path.Combine(Program.DataDir, "StandByScript.bat");
|
|
if (File.Exists(standByScript))
|
|
{
|
|
Utils.StartProcess(standByScript);
|
|
}
|
|
|
|
Logger.Debug("Powering off tv...");
|
|
var task = PowerOffOnShutdownOrResume(PowerOnOffState.StandBy);
|
|
Utils.WaitForTask(task);
|
|
Logger.Debug("Done powering off tv");
|
|
}
|
|
finally
|
|
{
|
|
NativeMethods.SetThreadExecutionState(NativeConstants.ES_CONTINUOUS);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SessionEnded(object sender, SessionEndedEventArgs e)
|
|
{
|
|
//if (e.Reason == SessionEndReasons.SystemShutdown)
|
|
//{
|
|
// Logger.Debug($"SessionEnded: {e.Reason}");
|
|
|
|
// if (Config.PowerOffOnShutdown)
|
|
// {
|
|
// PowerOff();
|
|
// }
|
|
//}
|
|
}
|
|
|
|
private void MonitorProcesses()
|
|
{
|
|
var enableMonitoring = ShouldMonitorProcesses();
|
|
if (enableMonitoring && _monitorTask == null)
|
|
{
|
|
_monitorTask = CheckProcesses();
|
|
}
|
|
else if (!enableMonitoring && _monitorTask != null)
|
|
{
|
|
_monitorTask = null;
|
|
}
|
|
}
|
|
|
|
public bool ShouldMonitorProcesses()
|
|
{
|
|
return Devices.Any(d => d.PowerSwitchOnScreenSaver) || _presets.Any(p => p.Triggers.Any(t => t.Trigger != PresetTriggerType.None));
|
|
}
|
|
|
|
public async Task CheckProcesses()
|
|
{
|
|
var wasConnected = Devices.Any(d => d.PowerSwitchOnScreenSaver && d.IsConnected());
|
|
_monitorTaskCounter++;
|
|
var validCounter = _monitorTaskCounter;
|
|
var lastProcessId = 0;
|
|
|
|
var monitorContext = new ProcessMonitorContext();
|
|
//Process[] lastProcesses = null;
|
|
|
|
while (validCounter == _monitorTaskCounter)
|
|
{
|
|
await Task.Delay(_poweredOffByScreenSaver ? 500 : 1000);
|
|
|
|
try
|
|
{
|
|
var applicableDevices = Devices.Where(d => d.PowerSwitchOnScreenSaver || _presets.Any(p => p.Triggers.Any(t => t.Trigger != PresetTriggerType.None) &&
|
|
((p.DeviceMacAddress == null && d == SelectedDevice) || p.DeviceMacAddress == d.MacAddress)));
|
|
|
|
if (!applicableDevices.Any())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (_poweredOffByScreenSaver && !UserSessionInfo.UserLocalSession)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var processes = Process.GetProcesses();
|
|
|
|
if (_poweredOffByScreenSaver)
|
|
{
|
|
if (processes.Any(p => p.Id == _poweredOffByScreenSaverProcessId))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Logger.Debug("Screensaver stopped, waking");
|
|
_poweredOffByScreenSaver = false;
|
|
_poweredOffByScreenSaverProcessId = 0;
|
|
lastProcessId = 0;
|
|
WakeAfterStartupOrResume(PowerOnOffState.ScreenSaver);
|
|
|
|
continue;
|
|
}
|
|
|
|
var connectedDevices = applicableDevices.Where(d => d.IsConnected()).ToList();
|
|
|
|
if (!connectedDevices.Any())
|
|
{
|
|
if (wasConnected)
|
|
{
|
|
Logger.Debug("Process monitor: TV(s) where connected, but not any longer");
|
|
wasConnected = false;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
var devices = applicableDevices.ToList();
|
|
foreach (var device in devices)
|
|
{
|
|
Logger.Debug($"Process monitor: test connection with {device.Name}...");
|
|
var test = await device.TestConnection();
|
|
Logger.Debug("Process monitor: test connection result: " + test);
|
|
}
|
|
|
|
connectedDevices = applicableDevices.Where(d => d.IsConnected()).ToList();
|
|
|
|
if (!connectedDevices.Any())
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!wasConnected)
|
|
{
|
|
Logger.Debug("Process monitor: TV(s) where not connected, but connection has now been established");
|
|
wasConnected = true;
|
|
}
|
|
|
|
monitorContext.Devices = connectedDevices;
|
|
monitorContext.RunningProcesses = processes;
|
|
//if (lastProcesses != null)
|
|
//{
|
|
// monitorContext.StartedProcesses = processes.Where(p => !lastProcesses.Any(lp => lp.Id == p.Id)).ToArray();
|
|
// monitorContext.StoppedProcesses = lastProcesses.Where(lp => !processes.Any(p => p.Id == lp.Id)).ToArray();
|
|
//}
|
|
//else
|
|
//{
|
|
// monitorContext.StartedProcesses = null;
|
|
// monitorContext.StoppedProcesses = null;
|
|
//}
|
|
|
|
//if (monitorContext.StartedProcesses?.Any() ?? false)
|
|
//{
|
|
// Logger.Debug("Started processes: " + string.Join(", ", monitorContext.StartedProcesses.Select(p => p.ProcessName)));
|
|
//}
|
|
//lastProcesses = processes;
|
|
|
|
var process = processes.FirstOrDefault(p => p.ProcessName.ToLowerInvariant().EndsWith(".scr"));
|
|
|
|
if (process != null)
|
|
{
|
|
var parent = process.Parent();
|
|
|
|
if (parent?.ProcessName.Contains("winlogon") ?? false)
|
|
{
|
|
Logger.Debug($"Screensaver started: {process.ProcessName}, parent: {parent.ProcessName}");
|
|
try
|
|
{
|
|
foreach (var device in connectedDevices)
|
|
{
|
|
Logger.Debug($"Screensaver check: test connection with {device.Name}...");
|
|
var test = await device.TestConnection();
|
|
Logger.Debug("Screensaver check: test connection result: " + test);
|
|
if (!test)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Logger.Debug($"Screensaver check: powering off tv {device.Name} because of screensaver");
|
|
try
|
|
{
|
|
_poweredOffByScreenSaver = await device.PowerOff();
|
|
}
|
|
catch (Exception pex)
|
|
{
|
|
// Assume powering off was successful
|
|
_poweredOffByScreenSaver = true;
|
|
Logger.Error($"Screensaver check: exception while powering off (probably connection closed): " + pex.Message);
|
|
}
|
|
Logger.Debug($"Screensaver check: powered off tv {device.Name}");
|
|
}
|
|
|
|
_poweredOffByScreenSaverProcessId = process.Id;
|
|
lastProcessId = 0;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.Error($"Screensaver check: can't power off: " + e.ToLogString());
|
|
}
|
|
}
|
|
else if (process.Id != lastProcessId)
|
|
{
|
|
Logger.Debug($"Screensaver started: {process.ProcessName}, but invalid parent: {parent?.ProcessName ?? "no parent"}");
|
|
lastProcessId = process.Id;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
await ExecuteProcessPresets(monitorContext);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.Error("CheckProcesses: " + ex.ToLogString());
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task ExecuteProcessPresets(ProcessMonitorContext context)
|
|
{
|
|
var presets = _presets.Where(p => p.Triggers.Any(t => t.Trigger == PresetTriggerType.ProcessSwitch));
|
|
if (!presets.Any())
|
|
{
|
|
return;
|
|
}
|
|
|
|
context.IsNotificationDisabled = Utils.IsNotificationDisabled();
|
|
|
|
var (processId, isFullScreen) = Utils.GetForegroundProcessIdAndIfFullScreen();
|
|
|
|
if (processId > 0)
|
|
{
|
|
context.ForegroundProcess = context.RunningProcesses.FirstOrDefault(p => p.Id == processId);
|
|
context.ForegroundProcessIsFullScreen = isFullScreen;
|
|
}
|
|
else
|
|
{
|
|
context.ForegroundProcess = null;
|
|
context.ForegroundProcessIsFullScreen = false;
|
|
}
|
|
|
|
var changedProcesses = new List<Process>();
|
|
if (context.ForegroundProcess != null)
|
|
{
|
|
changedProcesses.Add(context.ForegroundProcess);
|
|
}
|
|
|
|
if (context.ForegroundProcess != null && context.ForegroundProcessIsFullScreen)
|
|
{
|
|
if (!context.LastFullScreenProcessName.Equals(context.ForegroundProcess.ProcessName))
|
|
{
|
|
context.LastFullScreenProcessName = context.ForegroundProcess.ProcessName;
|
|
//Logger.Debug($"Foreground fullscreen app detected: {context.ForegroundProcess.ProcessName}");
|
|
}
|
|
|
|
presets = presets.Where(p => p.Triggers.Any(t => t.Conditions.HasFlag(PresetConditionType.FullScreen)));
|
|
context.WasFullScreen = true;
|
|
}
|
|
else if (context.WasFullScreen)
|
|
{
|
|
presets = presets.Where(p => p.Triggers.Any(t => !t.Conditions.HasFlag(PresetConditionType.FullScreen)));
|
|
context.WasFullScreen = false;
|
|
context.LastFullScreenProcessName = string.Empty;
|
|
}
|
|
|
|
var isHDRActive = context.Devices.Any(d => d.IsUsingHDRPictureMode());
|
|
|
|
var triggerContext = new PresetTriggerContext
|
|
{
|
|
IsHDRActive = isHDRActive,
|
|
ForegroundProcess = context.ForegroundProcess,
|
|
ForegroundProcessIsFullScreen = context.ForegroundProcessIsFullScreen,
|
|
ChangedProcesses = changedProcesses,
|
|
IsNotificationDisabled = context.IsNotificationDisabled
|
|
};
|
|
|
|
var toApplyPresets = new List<LgPreset>();
|
|
foreach (var preset in presets)
|
|
{
|
|
if (preset.Triggers.Any(t => t.TriggerActive(triggerContext)))
|
|
{
|
|
toApplyPresets.Add(preset);
|
|
}
|
|
}
|
|
|
|
if (toApplyPresets.Any())
|
|
{
|
|
LgPreset toApplyPreset;
|
|
if (toApplyPresets.Count > 1)
|
|
{
|
|
toApplyPreset = toApplyPresets.FirstOrDefault(p => p.Triggers.Any(t => !t.IncludedProcesses.Contains("*")));
|
|
toApplyPreset = toApplyPreset != null ? toApplyPreset : toApplyPresets.First();
|
|
}
|
|
else
|
|
{
|
|
toApplyPreset = toApplyPresets.First();
|
|
}
|
|
|
|
if (_lastTriggeredPreset != toApplyPreset)
|
|
{
|
|
await ApplyPreset(toApplyPreset);
|
|
|
|
_lastTriggeredPreset = toApplyPreset;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal void AddCustomDevice(LgDevice device)
|
|
{
|
|
Devices.Add(device);
|
|
}
|
|
|
|
internal void RemoveCustomDevice(LgDevice device)
|
|
{
|
|
Devices.Remove(device);
|
|
|
|
if (!string.IsNullOrEmpty(device.MacAddress))
|
|
{
|
|
var presets = _presets.Where(p => !string.IsNullOrEmpty(p.DeviceMacAddress) && p.DeviceMacAddress.Equals(device.MacAddress)).ToList();
|
|
presets.ForEach(preset =>
|
|
{
|
|
preset.DeviceMacAddress = null;
|
|
});
|
|
}
|
|
|
|
if (SelectedDevice == device)
|
|
{
|
|
SelectedDevice = Devices.Any() ? Devices.First() : null;
|
|
}
|
|
}
|
|
}
|
|
}
|