diff --git a/.idea/.idea.LittleBigMouse/.idea/avalonia.xml b/.idea/.idea.LittleBigMouse/.idea/avalonia.xml new file mode 100644 index 00000000..1c057753 --- /dev/null +++ b/.idea/.idea.LittleBigMouse/.idea/avalonia.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/.idea.LittleBigMouse/.idea/projectSettingsUpdater.xml b/.idea/.idea.LittleBigMouse/.idea/projectSettingsUpdater.xml index 4bb9f4d2..ef20cb08 100644 --- a/.idea/.idea.LittleBigMouse/.idea/projectSettingsUpdater.xml +++ b/.idea/.idea.LittleBigMouse/.idea/projectSettingsUpdater.xml @@ -1,6 +1,8 @@ - \ No newline at end of file diff --git a/.idea/.idea.LittleBigMouse/.idea/workspace.xml b/.idea/.idea.LittleBigMouse/.idea/workspace.xml index ff9885ce..c44583f4 100644 --- a/.idea/.idea.LittleBigMouse/.idea/workspace.xml +++ b/.idea/.idea.LittleBigMouse/.idea/workspace.xml @@ -4,6 +4,9 @@ HLab.Avalonia/HLab.Base.Avalonia.UITest/HLab.Base.Avalonia.UITest.csproj HLab.Core/HLab.ColorTools.Benchmark/HLab.ColorTools.Benchmark.csproj LittleBigMouse.Daemon/LittleBigMouse.Hook/LittleBigMouse.Hook.vcxproj + LittleBigMouse.Server/LittleBigMouse.Server.csproj + LittleBigMouse.Server/LittleBigMouse.Server.csproj + LittleBigMouse.Ui.Loader/LittleBigMouse.Ui.Loader.csproj LittleBigMouse.Ui/LittleBigMouse.Ui.Avalonia/LittleBigMouse.Ui.Avalonia.csproj LittleBigMouse.Ui/LittleBigMouse.Ui.Avalonia/LittleBigMouse.Ui.Avalonia.csproj @@ -12,29 +15,29 @@ - - - - - - - - - - + + + - - + + + + + + + - + - + - + - + - + - + - + - + - + + + + + + + + + @@ -280,4 +381,46 @@ + + + + + file://$PROJECT_DIR$/LittleBigMouse.Hook/Geometry/Geometry.h + 2 + + + + + + + + + + + + + + + + file://$PROJECT_DIR$/LittleBigMouse.Ui/LittleBigMouse.Ui.Avalonia/MonitorFrame/MonitorFrameView.axaml.cs + 34 + + + + + + + + + + \ No newline at end of file diff --git a/HLab.Avalonia b/HLab.Avalonia index cc49b761..d4ea9fe6 160000 --- a/HLab.Avalonia +++ b/HLab.Avalonia @@ -1 +1 @@ -Subproject commit cc49b761c4a86b39b428ea5fd0f1c9a803182502 +Subproject commit d4ea9fe6c57b2a6e59ebe5b8fcc1e827eb473e6d diff --git a/HLab.Core b/HLab.Core index a76029e0..5ce89054 160000 --- a/HLab.Core +++ b/HLab.Core @@ -1 +1 @@ -Subproject commit a76029e08c0182544a822f74e4c313f2a81518a6 +Subproject commit 5ce890549c85280be39d55cde57c465540293b86 diff --git a/HLab.Sys/HLab.Sys.Argyll/ArgyllProbe.cs b/HLab.Sys/HLab.Sys.Argyll/ArgyllProbe.cs index 5339078f..220a0d58 100644 --- a/HLab.Sys/HLab.Sys.Argyll/ArgyllProbe.cs +++ b/HLab.Sys/HLab.Sys.Argyll/ArgyllProbe.cs @@ -31,417 +31,419 @@ namespace HLab.Sys.Argyll; public class ArgyllProbe : ReactiveObject { - public ArgyllProbe() - { - ConfigFromDipcalGUI(); - } - public ArgyllProbe(bool autoconfig = true) - { - if(autoconfig) ConfigFromDipcalGUI(); - } - - - private static IniFile _dispcalIni; - private static IniFile DispcalIni - { - get - { - if (_dispcalIni == null) - _dispcalIni = new IniFile( - Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), - @"DisplayCAL\DisplayCAL.ini" - )); - - return _dispcalIni; - } - - } - - - private readonly double[] _xyz = { 0, 0, 0 }; - // private readonly double[] _lab = { 0, 0, 0 }; - - private static void ArgyllSendKey(Process p, String key) - { - //System.Threading.Thread.Sleep(300); - p.StandardInput.Flush(); - p.StandardInput.Write(key); - p.StandardInput.Flush(); - } - - private bool _calibrating = false; - private bool _spectrum = false; - - public string Name - { - get => _name; - set => this.RaiseAndSetIfChanged(ref _name, value); - } - string _name; - - public double SpectrumFrom - { - get => _spectrumFrom; - set => this.RaiseAndSetIfChanged(ref _spectrumFrom, value); - } - double _spectrumFrom; - - public double SpectrumTo - { - get => _spectrumTo; - set => this.RaiseAndSetIfChanged(ref _spectrumTo, value); - } - double _spectrumTo;//c => c.Default(720.0)); - - public int SpectrumSteps - { - get => _spectrumSteps; - set => this.RaiseAndSetIfChanged(ref _spectrumSteps, value); - } - int _spectrumSteps; - - public double Cct - { - get => _cct; - set => this.RaiseAndSetIfChanged(ref _cct, value); - } - double _cct; - - public double Cri - { - get => _cri; - set => this.RaiseAndSetIfChanged(ref _cri, value); - } - double _cri; - - public double Tlci - { - get => _tlci; - set => this.RaiseAndSetIfChanged(ref _tlci, value); - } - double _tlci; - - public double Lux - { - get => _lux; - set => this.RaiseAndSetIfChanged(ref _lux, value); - } - double _lux; - - public ObservableCollection Spectrum { get; set; } = new ObservableCollection {0}; - - public ObservableCollection WaveLength { get; set; } = new ObservableCollection {0}; - private void ArgyllOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) - { - System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); - - var line = outLine.Data; - - Console.WriteLine(line); - - if (line == null) return; - - if (sendingProcess is not Process p) return; - - if (_spectrum) - { - var s = line.Split(','); - - Spectrum.Clear(); - WaveLength.Clear(); - - var nm = SpectrumFrom; - var step = (SpectrumTo - SpectrumFrom)/(SpectrumSteps - 1); - - foreach (var t in s) - { - Spectrum.Add( double.Parse(t)); - WaveLength.Add(nm); - nm += step; - } - _spectrum = false; - } - - - if (line.Contains("Spectrum from")) - { - var pos = line.IndexOf("Spectrum from", StringComparison.Ordinal); - var sub = line[(pos + 14)..]; - var s = sub.Split(' '); - SpectrumFrom = double.Parse(s[0]); - SpectrumTo = double.Parse(s[2]); - SpectrumSteps = int.Parse(s[5]); - _spectrum = true; - } - - if (line.Contains("Ambient")) - { - string[] s = line.Split(' '); - Lux = double.Parse(s[3]); - Cct = double.Parse(s[7].Replace("K","")); - } - - if (line.Contains("(Ra)")) - { - string[] s = line.Split(' '); - Cri = double.Parse(s[6]); - } - - if (line.Contains("(Qa)")) - { - string[] s = line.Split(' '); - Tlci = double.Parse(s[8]); - } - - if (line.Contains("Error - Opening USB port")) - ArgyllSendKey(p, "q"); - - if (line.Contains("calibration position")) - { - if (!_calibrating) - { - // TODO - //var result = MessageBox.Show("Place instrument in calibration position", "Instrument", - // MessageBoxButton.OKCancel, MessageBoxImage.Information); - //ArgyllSendKey(p, result == MessageBoxResult.OK ? "k" : "q"); - - _calibrating = true; - } - else ArgyllSendKey(p, "k"); - } - - if (line.Contains("Place instrument")) - { - System.Threading.Thread.Sleep(300); - p.StandardInput.Flush(); - //var result = MessageBox.Show("Place instrument in measure position", "Instrument", + public ArgyllProbe() + { + ConfigFromDipcalGUI(); + } + public ArgyllProbe(bool autoconfig = true) + { + if (autoconfig) ConfigFromDipcalGUI(); + } + + + private static IniFile _dispcalIni; + private static IniFile DispcalIni + { + get + { + if (_dispcalIni == null) + _dispcalIni = new IniFile( + Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + @"DisplayCAL\DisplayCAL.ini" + )); + + return _dispcalIni; + } + + } + + + private readonly double[] _xyz = { 0, 0, 0 }; + // private readonly double[] _lab = { 0, 0, 0 }; + + private static void ArgyllSendKey(Process p, String key) + { + //System.Threading.Thread.Sleep(300); + p.StandardInput.Flush(); + p.StandardInput.Write(key); + p.StandardInput.Flush(); + } + + private bool _calibrating = false; + private bool _spectrum = false; + + public string Name + { + get => _name; + set => this.RaiseAndSetIfChanged(ref _name, value); + } + string _name; + + public double SpectrumFrom + { + get => _spectrumFrom; + set => this.RaiseAndSetIfChanged(ref _spectrumFrom, value); + } + double _spectrumFrom; + + public double SpectrumTo + { + get => _spectrumTo; + set => this.RaiseAndSetIfChanged(ref _spectrumTo, value); + } + double _spectrumTo;//c => c.Default(720.0)); + + public int SpectrumSteps + { + get => _spectrumSteps; + set => this.RaiseAndSetIfChanged(ref _spectrumSteps, value); + } + int _spectrumSteps; + + public double Cct + { + get => _cct; + set => this.RaiseAndSetIfChanged(ref _cct, value); + } + double _cct; + + public double Cri + { + get => _cri; + set => this.RaiseAndSetIfChanged(ref _cri, value); + } + double _cri; + + public double Tlci + { + get => _tlci; + set => this.RaiseAndSetIfChanged(ref _tlci, value); + } + double _tlci; + + public double Lux + { + get => _lux; + set => this.RaiseAndSetIfChanged(ref _lux, value); + } + double _lux; + + public string Message + { + get => _message; + set => this.RaiseAndSetIfChanged(ref _message, value); + } + string _message; + + public ObservableCollection Spectrum { get; set; } = new ObservableCollection { 0 }; + + public ObservableCollection WaveLength { get; set; } = new ObservableCollection { 0 }; + private void ArgyllOutputHandler(object sendingProcess, DataReceivedEventArgs outLine) + { + System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); + + var line = outLine.Data; + + Console.WriteLine(line); + + if (line == null) return; + + if (sendingProcess is not Process p) return; + + if (_spectrum) + { + var s = line.Split(','); + + Spectrum.Clear(); + WaveLength.Clear(); + + var nm = SpectrumFrom; + var step = (SpectrumTo - SpectrumFrom) / (SpectrumSteps - 1); + + foreach (var t in s) + { + Spectrum.Add(double.Parse(t)); + WaveLength.Add(nm); + nm += step; + } + _spectrum = false; + } + + + if (line.Contains("Spectrum from")) + { + var pos = line.IndexOf("Spectrum from", StringComparison.Ordinal); + var sub = line[(pos + 14)..]; + var s = sub.Split(' '); + SpectrumFrom = double.Parse(s[0]); + SpectrumTo = double.Parse(s[2]); + SpectrumSteps = int.Parse(s[5]); + _spectrum = true; + } + + if (line.Contains("Ambient")) + { + string[] s = line.Split(' '); + Lux = double.Parse(s[3]); + Cct = double.Parse(s[7].Replace("K", "")); + } + + if (line.Contains("(Ra)")) + { + string[] s = line.Split(' '); + Cri = double.Parse(s[6]); + } + + if (line.Contains("(Qa)")) + { + string[] s = line.Split(' '); + Tlci = double.Parse(s[8]); + } + + if (line.Contains("Error - Opening USB port")) + ArgyllSendKey(p, "q"); + + if (line.Contains("calibration position")) + { + if (!_calibrating) + { + // TODO + //var result = MessageBox.Show("Place instrument in calibration position", "Instrument", // MessageBoxButton.OKCancel, MessageBoxImage.Information); - //ArgyllSendKey(p, result == MessageBoxResult.OK ? "0" : "q"); - ArgyllSendKey(p, "0"); - } - - if (line.Contains("Result is XYZ:")) - { - int pos = line.IndexOf("XYZ: ", StringComparison.Ordinal); - string sub = line.Substring(pos + 5); - sub = sub.Remove(sub.IndexOf(',')); - string[] s = sub.Split(' '); - for (int i = 0; i < 3; i++) - { - try - { - _xyz[i] = Double.Parse(s[i]); - } - catch { _xyz[i] = 0; } - } - - _calibrating = false; - //if (line.Contains("D50 Lab:")) - //{ - // pos = line.IndexOf("D50 Lab:", StringComparison.Ordinal); - // sub = line.Substring(pos + 9); - // //sub.Remove(sub.IndexOf(',')); - // s = sub.Split(' '); - // for (int i = 0; i < 3; i++) - // { - // try - // { - // _lab[i] = Double.Parse(s[i]); - // } - // catch { _lab[i] = 0; } - // } - - //} - - //((Process)sendingProcess).Kill(); - } - } - - public enum MeasurementMode - { - Emissive, - Projector, - Ambiant, - Flash - } - - public enum ObserverEnum - { - CIE_1931_2, - CIE_1964_10, - CIE_2012_10, - CIE_2012_2, - SB_1955_2, - JV_1978_2, - Shaw, - } - - public static string ArgyllPath { get; set; } - - public int ColorTemp { get; set; } = 6500; - public MeasurementMode Mode { get; set; } = MeasurementMode.Emissive; - public bool HighResolution { get; set; } = true; - public bool Adaptive { get; set; } = true; - public bool ReadSpectrum { get; set; } = false; - public bool ReadCri { get; set; } = false; - - private ObserverEnum Observer { get; set; } = ObserverEnum.CIE_1931_2; - - public static void PathFromDispcalGUI() - { - ArgyllPath = DispcalIni.ReadValue("Default", "argyll.dir", ""); - } - - public void ConfigFromDipcalGUI() - { - PathFromDispcalGUI(); - - ColorTemp = - int.Parse(DispcalIni.ReadValue("Default", "whitepoint.colortemp", "5000")); - - switch (DispcalIni.ReadValue("Default", "measurement_mode", "1")) - { - case "c": // CRT ??? - break; - case "p": // CRT ??? - Mode = MeasurementMode.Projector; - break; - case "1": - Mode = MeasurementMode.Emissive; - break; - } - - HighResolution = (DispcalIni.ReadValue("Default", "measurement_mode.highres", "0") == "1"); - - Adaptive = (DispcalIni.ReadValue("Default", "measurement_mode.adaptive", "1") == "1"); - - string obs = DispcalIni.ReadValue("Default", "observer", "1931_2"); - switch (obs) - { - case "1931_2": - Observer = ObserverEnum.CIE_1931_2; - break; - case "1964_10": - Observer = ObserverEnum.CIE_1964_10; - break; - case "1955_2": - Observer = ObserverEnum.SB_1955_2; - break; - case "shaw": - Observer = ObserverEnum.Shaw; - break; - case "1978_2": - Observer = ObserverEnum.JV_1978_2; - break; - case "2012_2": - Observer = ObserverEnum.CIE_2012_2; - break; - case "2012_10": - Observer = ObserverEnum.CIE_2012_10; - break; - } - } - - public string SpotReadArgs - { - get - { - string s = " -N"; - switch (Mode) - { - case MeasurementMode.Projector: - s += " -pb"; - break; - case MeasurementMode.Emissive: - s += " -e"; - break; - case MeasurementMode.Ambiant: - s += " -a"; - break; - case MeasurementMode.Flash: - s += " -f"; - break; - } - - - - if (HighResolution) s += " -H"; - - if (!Adaptive) s += " -Y A"; - - s += " -O"; - - s += " -Q"; - - switch (Observer) - { - case ObserverEnum.CIE_1931_2: - s += " 1931_2"; - break; - case ObserverEnum.CIE_1964_10: - s += " 1964_10"; - break; - case ObserverEnum.SB_1955_2: - s += " 1955_2"; - break; - case ObserverEnum.Shaw: - s += " shaw"; - break; - case ObserverEnum.JV_1978_2: - s += " 1978_2"; - break; - default: - throw new ArgumentOutOfRangeException(); - } - - if (ReadSpectrum) s += " -s"; - if (ReadCri) s += " -T"; - return s; - } - } - - - public bool Installed => ArgyllPath != ""; - - public bool SpotRead() - { - if (!Installed) return false; - - do - { - ExecSpotRead(); - } while (_calibrating); - - return true; - } - - public ProbedColor ProbedColor => new ProbedColorXYZ - { - Illuminant = ProbedColor.DIlluminant(ColorTemp), - X = _xyz[0], - Y = _xyz[1], - Z = _xyz[2] - }; - - public void ExecSpotRead() - { - var aProc = Process.GetProcessesByName("Spotread"); - foreach (var t in aProc) - { + //ArgyllSendKey(p, result == MessageBoxResult.OK ? "k" : "q"); + + Message = "Place instrument in calibration position"; + + _calibrating = true; + } + else ArgyllSendKey(p, "k"); + } + + if (line.Contains("Place instrument")) + { + System.Threading.Thread.Sleep(300); + p.StandardInput.Flush(); + + Message = "Place instrument in measure position"; + //var result = MessageBox.Show("Place instrument in measure position", "Instrument", + // MessageBoxButton.OKCancel, MessageBoxImage.Information); + //ArgyllSendKey(p, result == MessageBoxResult.OK ? "0" : "q"); + ArgyllSendKey(p, "0"); + } + + if (line.Contains("Result is XYZ:")) + { + int pos = line.IndexOf("XYZ: ", StringComparison.Ordinal); + string sub = line.Substring(pos + 5); + sub = sub.Remove(sub.IndexOf(',')); + string[] s = sub.Split(' '); + for (int i = 0; i < 3; i++) + { try { - t.Kill(); - if (!t.HasExited) - t.WaitForExit(); - + _xyz[i] = Double.Parse(s[i]); } - catch (Exception) { } - } - - var p = new Process - { - StartInfo = + catch { _xyz[i] = 0; } + } + + _calibrating = false; + //if (line.Contains("D50 Lab:")) + //{ + // pos = line.IndexOf("D50 Lab:", StringComparison.Ordinal); + // sub = line.Substring(pos + 9); + // //sub.Remove(sub.IndexOf(',')); + // s = sub.Split(' '); + // for (int i = 0; i < 3; i++) + // { + // try + // { + // _lab[i] = Double.Parse(s[i]); + // } + // catch { _lab[i] = 0; } + // } + + //} + + //((Process)sendingProcess).Kill(); + } + } + + public enum MeasurementMode + { + Emissive, + Projector, + Ambiant, + Flash + } + + public enum ObserverEnum + { + CIE_1931_2, + CIE_1964_10, + CIE_2012_10, + CIE_2012_2, + SB_1955_2, + JV_1978_2, + Shaw, + } + + public static string ArgyllPath { get; set; } + + public int ColorTemp { get; set; } = 6500; + public MeasurementMode Mode { get; set; } = MeasurementMode.Emissive; + public bool HighResolution { get; set; } = true; + public bool Adaptive { get; set; } = true; + public bool ReadSpectrum { get; set; } = false; + public bool ReadCri { get; set; } = false; + + private ObserverEnum Observer { get; set; } = ObserverEnum.CIE_1931_2; + + public static void PathFromDispcalGUI() + { + ArgyllPath = DispcalIni.ReadValue("Default", "argyll.dir", ""); + } + + public void ConfigFromDipcalGUI() + { + PathFromDispcalGUI(); + + ColorTemp = + int.Parse(DispcalIni.ReadValue("Default", "whitepoint.colortemp", "5000")); + + switch (DispcalIni.ReadValue("Default", "measurement_mode", "1")) + { + case "c": // CRT ??? + break; + case "p": // CRT ??? + Mode = MeasurementMode.Projector; + break; + case "1": + Mode = MeasurementMode.Emissive; + break; + } + + HighResolution = (DispcalIni.ReadValue("Default", "measurement_mode.highres", "0") == "1"); + + Adaptive = (DispcalIni.ReadValue("Default", "measurement_mode.adaptive", "1") == "1"); + + string obs = DispcalIni.ReadValue("Default", "observer", "1931_2"); + switch (obs) + { + case "1931_2": + Observer = ObserverEnum.CIE_1931_2; + break; + case "1964_10": + Observer = ObserverEnum.CIE_1964_10; + break; + case "1955_2": + Observer = ObserverEnum.SB_1955_2; + break; + case "shaw": + Observer = ObserverEnum.Shaw; + break; + case "1978_2": + Observer = ObserverEnum.JV_1978_2; + break; + case "2012_2": + Observer = ObserverEnum.CIE_2012_2; + break; + case "2012_10": + Observer = ObserverEnum.CIE_2012_10; + break; + } + } + + public string SpotReadArgs + { + get + { + string s = " -N"; + switch (Mode) + { + case MeasurementMode.Projector: + s += " -pb"; + break; + case MeasurementMode.Emissive: + s += " -e"; + break; + case MeasurementMode.Ambiant: + s += " -a"; + break; + case MeasurementMode.Flash: + s += " -f"; + break; + } + + + + if (HighResolution) s += " -H"; + + if (!Adaptive) s += " -Y A"; + + s += " -O"; + + s += " -Q"; + + s += Observer switch + { + ObserverEnum.CIE_1931_2 => " 1931_2", + ObserverEnum.CIE_1964_10 => " 1964_10", + ObserverEnum.SB_1955_2 => " 1955_2", + ObserverEnum.Shaw => " shaw", + ObserverEnum.JV_1978_2 => " 1978_2", + ObserverEnum.CIE_2012_2 => " 2012_2", + ObserverEnum.CIE_2012_10 => " 2012_10", + _ => throw new ArgumentOutOfRangeException() + }; + + if (ReadSpectrum) s += " -s"; + if (ReadCri) s += " -T"; + return s; + } + } + + + public bool Installed => ArgyllPath != ""; + + public bool SpotRead() + { + if (!Installed) return false; + + do + { + ExecSpotRead(); + } while (_calibrating); + + return true; + } + + public ProbedColor ProbedColor => new ProbedColorXYZ + { + Illuminant = ProbedColor.DIlluminant(ColorTemp), + X = _xyz[0], + Y = _xyz[1], + Z = _xyz[2] + }; + + public void ExecSpotRead() + { + var aProc = Process.GetProcessesByName("Spotread"); + foreach (var t in aProc) + { + try + { + t.Kill(); + if (!t.HasExited) + t.WaitForExit(); + + } + catch (Exception) { } + } + + var p = new Process + { + StartInfo = { FileName = Path.Combine(ArgyllPath, @"Spotread.exe"), Arguments = SpotReadArgs, @@ -451,90 +453,90 @@ public void ExecSpotRead() RedirectStandardInput = true, CreateNoWindow = true } - }; - - // p.StartInfo.Arguments = "-N -O -Y A"; - - try - { - p.StartInfo.EnvironmentVariables.Add("ARGYLL_NOT_INTERACTIVE", "yes"); - } - catch - { - } - - p.ErrorDataReceived += ArgyllOutputHandler; - p.OutputDataReceived += ArgyllOutputHandler; - - p.Start(); - p.BeginErrorReadLine(); - p.BeginOutputReadLine(); - - if (!p.HasExited) p.WaitForExit(); - } - - //TODO - - public void Save() - { - // Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog(); - // dlg.DefaultExt = ".probe"; - // dlg.Filter = "Probe documents (.probe)|*.probe"; - // bool? result = dlg.ShowDialog(); - // if (result == true) - // { - // // Open document - // string filename = dlg.FileName; - // Save(filename); - // } - } - - public void Save(string path) - { - XmlSerializer serializer = new XmlSerializer(typeof(ArgyllProbe)); - using (TextWriter writer = new StreamWriter(path)) - { - serializer.Serialize(writer, this); - } - } - - - public static ArgyllProbe Load() - { - //TODO - //Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog(); - //dlg.DefaultExt = ".probe"; - //dlg.Filter = "Probe documents (.probe)|*.probe"; - //bool? result = dlg.ShowDialog(); - //if (result == true) - //{ - // // Open document - // string filename = dlg.FileName; - // return Load(filename); - //} - return null; - } - - - public static ArgyllProbe Load(string path) - { - ArgyllProbe probe = null; - - XmlSerializer deserializer = new XmlSerializer(typeof(ArgyllProbe)); - - try - { - TextReader reader = new StreamReader(path); - probe = (ArgyllProbe)deserializer.Deserialize(reader); - reader.Close(); - } - catch (FileNotFoundException) - { - - } - - return probe; - } + }; + + // p.StartInfo.Arguments = "-N -O -Y A"; + + try + { + p.StartInfo.EnvironmentVariables.Add("ARGYLL_NOT_INTERACTIVE", "yes"); + } + catch + { + } + + p.ErrorDataReceived += ArgyllOutputHandler; + p.OutputDataReceived += ArgyllOutputHandler; + + p.Start(); + p.BeginErrorReadLine(); + p.BeginOutputReadLine(); + + if (!p.HasExited) p.WaitForExit(); + } + + //TODO + + public void Save() + { + // Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog(); + // dlg.DefaultExt = ".probe"; + // dlg.Filter = "Probe documents (.probe)|*.probe"; + // bool? result = dlg.ShowDialog(); + // if (result == true) + // { + // // Open document + // string filename = dlg.FileName; + // Save(filename); + // } + } + + public void Save(string path) + { + XmlSerializer serializer = new XmlSerializer(typeof(ArgyllProbe)); + using (TextWriter writer = new StreamWriter(path)) + { + serializer.Serialize(writer, this); + } + } + + + public static ArgyllProbe Load() + { + //TODO + //Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog(); + //dlg.DefaultExt = ".probe"; + //dlg.Filter = "Probe documents (.probe)|*.probe"; + //bool? result = dlg.ShowDialog(); + //if (result == true) + //{ + // // Open document + // string filename = dlg.FileName; + // return Load(filename); + //} + return null; + } + + + public static ArgyllProbe Load(string path) + { + ArgyllProbe probe = null; + + XmlSerializer deserializer = new XmlSerializer(typeof(ArgyllProbe)); + + try + { + TextReader reader = new StreamReader(path); + probe = (ArgyllProbe)deserializer.Deserialize(reader); + reader.Close(); + } + catch (FileNotFoundException) + { + + } + + return probe; + } } diff --git a/HLab.Sys/HLab.Sys.Argyll/HLab.Sys.Argyll.csproj b/HLab.Sys/HLab.Sys.Argyll/HLab.Sys.Argyll.csproj index 209e50fa..2dce7de1 100644 --- a/HLab.Sys/HLab.Sys.Argyll/HLab.Sys.Argyll.csproj +++ b/HLab.Sys/HLab.Sys.Argyll/HLab.Sys.Argyll.csproj @@ -1,15 +1,15 @@  - net8.0 + net10.0 AnyCPU;x64;x86 Debug;Release;ReleaseDebug - 2.4.0.0 + 2.5.0.0 - - + + diff --git a/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/DrawingContextExtention.cs b/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/DrawingContextExtention.cs index ded79c71..34490836 100644 --- a/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/DrawingContextExtention.cs +++ b/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/DrawingContextExtention.cs @@ -14,9 +14,9 @@ public static void DrawContrast(this DrawingContext dc, Color colorA, Color col { var hz = orientation == Orientation.Horizontal; var length = (hz?area.Width:area.Height)/count; - var w = (hz?area.Height:area.Width)/2; + var w = (hz?area.Height:area.Width); - var location = area.TopLeft; // was Location + var location = area.TopLeft; var size = hz?new Size(length,w):new Size(w,length); var move = hz ? new Vector(length, 0) : new Vector(0, length); @@ -24,7 +24,6 @@ public static void DrawContrast(this DrawingContext dc, Color colorA, Color col var dG = colorA.G < colorB.G ? +1 : colorA.G > colorB.G? -1 : 0; var dB = colorA.B < colorB.B ? +1 : colorA.B > colorB.B? -1 : 0; - var color = colorA; for (var i = 0; i < count; i++) { @@ -32,22 +31,6 @@ public static void DrawContrast(this DrawingContext dc, Color colorA, Color col dc.RenderCircle(color,colorA,new Rect(location,size)); location += move; } - - location = area.TopLeft + (hz ? new Vector(0,w) : new Vector(w,0)); - - dR = -dR; - dG = -dG; - dB = -dB; - - color = colorB; - for (var i = 0; i < count; i++) - { - color = new Color(0xFF,(byte)((int)color.R+dR), (byte)((int)color.G + dG) , (byte)((int)color.B + dB)); - dc.RenderCircle(color,colorB,new Rect(location,size)); - location += move; - } - - } public static void DrawChessboard(this DrawingContext dc, Color colorA, Color colorB, Rect area, Size size) @@ -100,9 +83,9 @@ double _g(double value, double gg) } var startColor = - new ColorRGB(1.0, _g(colorA.Red / 2.0, startGamma), _g(colorA.Green / 2.0, startGamma), _g(colorA.Blue / 2.0, startGamma)); + HLabColors.RGB(1.0, _g(colorA.Red / 2.0, startGamma), _g(colorA.Green / 2.0, startGamma), _g(colorA.Blue / 2.0, startGamma)); var endColor = - new ColorRGB(1.0, _g(colorA.Red/2.0, endGamma), _g(colorA.Green/2.0, endGamma), _g(colorA.Blue/2.0, endGamma)); + HLabColors.RGB(1.0, _g(colorA.Red/2.0, endGamma), _g(colorA.Green/2.0, endGamma), _g(colorA.Blue/2.0, endGamma)); // var startColor = Color.FromScRgb(f1.0, _g(colorA.ScG/2.0f, startGamma), _g(colorA.ScB/2.0f, startGamma)); // var endColor = Color.FromScRgb(1.0f, _g(colorA.ScR/2.0f, endGamma), _g(colorA.ScG/2.0f, endGamma), _g(colorA.ScB/2.0f, endGamma)); @@ -205,15 +188,10 @@ public static void DrawGradient(this DrawingContext dc, IColor colorA, I { var gc = new GradientCalculator(colorA,colorB,gamma); - var brush = new SolidColorBrush(); - var length = orientation == Orientation.Horizontal ? area.Width : area.Height; if (length>500) { } - var bench = new Stopwatch(); - bench.Start(); - if (orientation == Orientation.Horizontal) { for (var p = 0.0; p < length; p++) @@ -231,10 +209,6 @@ public static void DrawGradient(this DrawingContext dc, IColor colorA, I } } - - bench.Stop(); - Debug.WriteLine("Gradient : " + area + " : " + bench.ElapsedTicks); - } class GradientCalculator @@ -270,12 +244,12 @@ public GradientCalculator(IColor c1, IColor c2, double gamma) _db = (colorB.Blue - _ba); } - float g(double value) => (float)Math.Pow(value, _invgamma); + double g(double value) => Math.Pow(value, _invgamma); public ColorRGB Get(double p) { - return new ColorRGB( + return HLabColors.RGB( g(_aa + _da * p), g(_ra + _dr * p), g(_ga + _dg * p), diff --git a/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/HLab.Sys.Windows.MonitorVcp.Avalonia.csproj b/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/HLab.Sys.Windows.MonitorVcp.Avalonia.csproj index 26ada263..6acf6c1c 100644 --- a/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/HLab.Sys.Windows.MonitorVcp.Avalonia.csproj +++ b/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/HLab.Sys.Windows.MonitorVcp.Avalonia.csproj @@ -1,19 +1,17 @@  - net8.0 + net10.0 + false enable enable - AnyCPU;x64;x86 - 2.4.0.0 + x64 + 2.5.0.0 - - - - + diff --git a/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/TestPattern.cs b/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/TestPattern.cs index 3780cd0e..4ea27fc7 100644 --- a/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/TestPattern.cs +++ b/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/TestPattern.cs @@ -37,7 +37,8 @@ public enum TestPatternType Solid, Gradient, Circle, - Circles, + Contrast, + ContrastBoth, Grid, Gamma } @@ -54,7 +55,7 @@ public Window GetWindow(PixelPoint location, double width, double height) { return new Window { - SystemDecorations = SystemDecorations.None, + WindowDecorations = WindowDecorations.None, CanResize = false, Position = location, Height = height, @@ -123,23 +124,45 @@ public Color PatternColorB { c._onRender = e.NewValue.Value switch { - TestPatternType.Solid => (dc, rect, colorA, colorB, orient) + TestPatternType.Solid => (dc, rect, colorA, colorB, orientation) => dc.DrawRectangle(new SolidColorBrush(colorA), null, rect), - TestPatternType.Gradient => (dc, rect, colorA, colorB, orient) - => dc.DrawGradient(colorA.ToColor(), colorB.ToColor(), rect, orient, 1.0 / 2.2 /*2.124*/), + TestPatternType.Gradient => (dc, rect, colorA, colorB, orientation) + => dc.DrawGradient(colorA.ToColor(), colorB.ToColor(), rect, orientation, 1.0 / 2.2 /*2.124*/), - TestPatternType.Circle => (dc, rect, colorA, colorB, orient) + TestPatternType.Circle => (dc, rect, colorA, colorB, orientation) => dc.RenderCircle(colorA, colorB, rect), - TestPatternType.Circles => (dc, rect, colorA, colorB, orient) - => dc.DrawContrast(colorA, colorB, rect, 5, orient), + TestPatternType.ContrastBoth => (dc, rect, colorA, colorB, orientation) + => + { + Rect rectA, rectB; + if (orientation == Orientation.Vertical) + { + rectA = new Rect(rect.X, rect.Y, rect.Width / 2, rect.Height); + rectB = new Rect(rect.X + rect.Width / 2, rect.Y, rect.Width / 2, rect.Height); + } + else + { + rectA = new Rect(rect.X, rect.Y, rect.Width, rect.Height / 2); + rectB = new Rect(rect.X, rect.Y + rect.Height / 2, rect.Width, rect.Height / 2); + } + + dc.DrawContrast(colorB, colorA, rectA, 5, orientation); + dc.DrawContrast(colorA, colorB, rectB, 5, orientation); + }, + + TestPatternType.Contrast => (dc, rect, colorA, colorB, orientation) + => + { + dc.DrawContrast(colorA, colorB, rect, 5, orientation); + }, - TestPatternType.Grid => (dc, rect, colorA, colorB, orient) + TestPatternType.Grid => (dc, rect, colorA, colorB, orientation) => dc.DrawHomeCinemaPattern(rect), - TestPatternType.Gamma => (dc, rect, colorA, colorB, orient) - => dc.DrawGamma(colorA.ToColor(), colorB.ToColor(), rect, orient), + TestPatternType.Gamma => (dc, rect, colorA, colorB, orientation) + => dc.DrawGamma(colorA.ToColor(), colorB.ToColor(), rect, orientation), _ => throw new ArgumentOutOfRangeException() }; diff --git a/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/TestPatternWindow.axaml b/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/TestPatternWindow.axaml index 7ebba162..a89e5657 100644 --- a/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/TestPatternWindow.axaml +++ b/HLab.Sys/HLab.Sys.Windows.MonitorVcp.Avalonia/TestPatternWindow.axaml @@ -7,7 +7,7 @@ xmlns:avalonia="clr-namespace:HLab.Sys.Windows.MonitorVcp.Avalonia" mc:Ignorable="d" Title="TestPatternWindow" Height="300" Width="300" - SystemDecorations="None" + WindowDecorations="None" ShowInTaskbar="False" > diff --git a/HLab.Sys/HLab.Sys.Windows.MonitorVcp/HLab.Sys.Windows.MonitorVcp.csproj b/HLab.Sys/HLab.Sys.Windows.MonitorVcp/HLab.Sys.Windows.MonitorVcp.csproj index bf9f8a16..25f3b1f5 100644 --- a/HLab.Sys/HLab.Sys.Windows.MonitorVcp/HLab.Sys.Windows.MonitorVcp.csproj +++ b/HLab.Sys/HLab.Sys.Windows.MonitorVcp/HLab.Sys.Windows.MonitorVcp.csproj @@ -1,10 +1,10 @@  - net8.0 + net10.0 x64;x86;AnyCpu Debug;Release - 2.4.0.0 + 2.5.0.0 diff --git a/HLab.Sys/HLab.Sys.Windows.MonitorVcp/MonitorRgbLevel.cs b/HLab.Sys/HLab.Sys.Windows.MonitorVcp/MonitorRgbLevel.cs index 44c8f4a3..e02611d9 100644 --- a/HLab.Sys/HLab.Sys.Windows.MonitorVcp/MonitorRgbLevel.cs +++ b/HLab.Sys/HLab.Sys.Windows.MonitorVcp/MonitorRgbLevel.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using Avalonia.Styling; using ReactiveUI; @@ -6,26 +8,48 @@ namespace HLab.Sys.Windows.MonitorVcp; public class MonitorRgbLevel : ReactiveObject { - readonly MonitorLevel[] _values = new MonitorLevel[3]; - - public MonitorRgbLevel(CommandWorker parser, VcpGetter getter, VcpSetter setter) - { - for (var i = 0; i < 3; i++) - _values[i] = new MonitorLevel(parser, getter, setter, (VcpComponent)i); - } - - public MonitorRgbLevel Start() - { - foreach (var level in _values) - level.Start(); - - return this; - } - - public MonitorLevel Channel(uint channel) { return _values[channel]; } - - public MonitorLevel Red => Channel(0); - public MonitorLevel Green => Channel(1); - public MonitorLevel Blue => Channel(2); - + readonly MonitorLevel[] _values = new MonitorLevel[3]; + + public MonitorRgbLevel(CommandWorker parser, VcpGetter getter, VcpSetter setter) + { + for (var i = 0; i < 3; i++) + _values[i] = new MonitorLevel(parser, getter, setter, (VcpComponent)i); + } + + public MonitorRgbLevel Start() + { + foreach (var level in _values) + level.Start(); + + return this; + } + + public MonitorLevel Channel(uint channel) { return _values[channel]; } + + public MonitorLevel Red => Channel(0); + public MonitorLevel Green => Channel(1); + public MonitorLevel Blue => Channel(2); + + public void SetToMax() + { + foreach (var level in _values) + level.SetToMax(); + } + + public void SetToMin() + { + foreach (var level in _values) + level.SetToMin(); + } + + public void SetTo(uint[] value) + { + for (var i = 0; i < value.Length; i++) + { + if(_values.Length <= i) break; + _values[i].Value = value[i]; + } + } + + public uint[] GetValues() => _values.Select(t => t.Value).ToArray(); } \ No newline at end of file diff --git a/HLab.Sys/HLab.Sys.Windows.MonitorVcp/ProbeLut.cs b/HLab.Sys/HLab.Sys.Windows.MonitorVcp/ProbeLut.cs index a2b5c62f..266dcf79 100644 --- a/HLab.Sys/HLab.Sys.Windows.MonitorVcp/ProbeLut.cs +++ b/HLab.Sys/HLab.Sys.Windows.MonitorVcp/ProbeLut.cs @@ -24,9 +24,13 @@ You should have received a copy of the GNU General Public License #nullable enable using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; using System.Linq; +using System.Reactive.Linq; using System.Xml.Serialization; +using DynamicData; +using DynamicData.Binding; using HLab.Sys.Argyll; using HLab.Sys.Windows.Monitors; using ReactiveUI; @@ -35,213 +39,315 @@ namespace HLab.Sys.Windows.MonitorVcp; public class ProbeLut : ReactiveObject { - public ProbedColor DIlluminant { get; } + //public ProbedColor DIlluminant { get; } + + readonly MonitorDevice _monitor; + + readonly SourceList _lut = new(); + + + readonly ReadOnlyObservableCollection _sortedLut; + public ReadOnlyObservableCollection SortedLut => _sortedLut; + + readonly SourceList _smoothLut = new(); + readonly ReadOnlyObservableCollection _smoothLutCollection; + public ReadOnlyObservableCollection SmoothLut => _smoothLutCollection; + + internal ProbeLut(MonitorDevice monitor) + { + _monitor = monitor; + Vcp = _monitor.Vcp(); + + _luminance = this.WhenAnyValue( + e => e.Vcp.Brightness.Value, + selector: e => GetLuminance() + ).ToProperty(this, _ => _.Luminance); + + _lut + .Connect() + .Sort(SortExpressionComparer.Ascending(t => t.Y)) + .ObserveOn(RxSchedulers.MainThreadScheduler) + .Bind(out _sortedLut) + .Subscribe(); + + _smoothLut + .Connect() + .Sort(SortExpressionComparer.Ascending(t => t.Y)) + .ObserveOn(RxSchedulers.MainThreadScheduler) + .Bind(out _smoothLutCollection) + .Subscribe(); + } + + public (double Slope, double Intercept) LinearRegression(IEnumerablelist, Func getX, Func getY) + { + var sumX = 0.0; + var sumY = 0.0; + var sumXY = 0.0; + var sumX2 = 0.0; + var n = _sortedLut.Count; + + foreach (var tune in list) + { + var x = getX(tune); + var y = getY(tune); + + sumX += x; + sumY += y; + sumXY += x * y; + sumX2 += x * x; + } + + var slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX); + var intercept = (sumY - slope * sumX) / n; + + return (slope, intercept); + } + + public void GenerateSmoothedCurve() + { + _smoothLut.Clear(); + + var(slopeY,interceptY) = LinearRegression(_sortedLut, t => t.Brightness, t => t.Y); + var(slopeR,interceptR) = LinearRegression(_sortedLut, t => t.Brightness, t => t.Red); + var(slopeG,interceptG) = LinearRegression(_sortedLut, t => t.Brightness, t => t.Green); + var(slopeB,interceptB) = LinearRegression(_sortedLut, t => t.Brightness, t => t.Blue); + + var start = (int)_sortedLut.First().Brightness; + var end = (int)_sortedLut.Last().Brightness; + + for (var i=start; i x.Brightness == brightness); + if (t == null) return false; - List _lut = new(); + _lut.Remove(t); + return true; + } - internal ProbeLut(MonitorDevice monitor) - { - _monitor = monitor; - - _luminance = this.WhenAnyValue( - e => e.Vcp.Brightness.Value, - selector: e => GetLuminance() - ).ToProperty(this, _ => _.Luminance); - } - - public VcpControl Vcp => _monitor.Vcp(); - - public bool RemoveBrightness(double brightness) - { - var t = _lut.FirstOrDefault(x => x.Brightness == brightness); - if (t == null) return false; - - _lut.Remove(t); - return true; - } - - public bool RemoveLowBrightness(double maxGain) - { - var t = _lut.FirstOrDefault(x => (x.Brightness == 0 && x.MaxGain == maxGain)); - if (t == null) return false; - - _lut.Remove(t); - return true; - } - - public void Add(Tune tune) - { - _lut.Add(tune); - - _lut = _lut.OrderBy(x => x.Y).ToList(); - } - - public Tune FromLuminance(double luminance) - { - if (_lut.Count == 0) return Current; - - Tune tSup = null; - Tune tInf = null; - - var i = 0; - for (; i < _lut.Count && _lut[i].Y < luminance; i++) - tInf = _lut[i]; - - // luminance is more than monitor capabilities - if (i >= _lut.Count) return tInf; - - tSup = _lut[i]; - - if (tInf == null) return tSup; - - var dist = tSup.Y - tInf.Y; - var ratio = (luminance - tInf.Y) / dist; - - var t = new Tune - { - Y = (uint)Math.Round(tInf.Y + (tSup.Y - tInf.Y) * ratio, 0), - x = (uint)Math.Round(tInf.x + (tSup.x - tInf.x) * ratio, 0), - y = (uint)Math.Round(tInf.y + (tSup.y - tInf.y) * ratio, 0), - - Brightness = (uint)Math.Round(tInf.Brightness + (tSup.Brightness - tInf.Brightness) * ratio, 0), - Contrast = (uint)Math.Round(tInf.Contrast + (tSup.Contrast - tInf.Contrast) * ratio, 0), - - Red = (uint)Math.Round(tInf.Red + (tSup.Red - tInf.Red) * ratio, 0), - Blue = (uint)Math.Round(tInf.Blue + (tSup.Blue - tInf.Blue) * ratio, 0), - Green = (uint)Math.Round(tInf.Green + (tSup.Green - tInf.Green) * ratio, 0), - }; - - return t; - } - - public Tune FromBrightness(double brightness) - { - if (_lut.Count == 0) return Current; - - Tune tSup = null; - Tune tInf = null; - - var i = 0; - for (; i < _lut.Count && _lut[i].Brightness < brightness; i++) - tInf = _lut[i]; - - // luminance is more than monitor capabilities - if (i >= _lut.Count) return tInf; - - tSup = _lut[i]; - - if (tInf == null) return tSup; - - var dist = tSup.Brightness - tInf.Brightness; - var ratio = (brightness - tInf.Brightness) / dist; - - var t = new Tune - { - Y = (uint)Math.Round(tInf.Y + (tSup.Y - tInf.Y) * ratio, 0), - x = (uint)Math.Round(tInf.x + (tSup.x - tInf.x) * ratio, 0), - y = (uint)Math.Round(tInf.y + (tSup.y - tInf.y) * ratio, 0), - - Brightness = (uint)Math.Round(tInf.Brightness + (tSup.Brightness - tInf.Brightness) * ratio, 0), - Contrast = (uint)Math.Round(tInf.Contrast + (tSup.Contrast - tInf.Contrast) * ratio, 0), - - Red = (uint)Math.Round(tInf.Red + (tSup.Red - tInf.Red) * ratio, 0), - Blue = (uint)Math.Round(tInf.Blue + (tSup.Blue - tInf.Blue) * ratio, 0), - Green = (uint)Math.Round(tInf.Green + (tSup.Green - tInf.Green) * ratio, 0), - }; - - return t; - } - - double GetLuminance() => FromBrightness(Vcp.Brightness.Value).Y; - - void SetLuminance(double luminance) - { - var t = FromLuminance(luminance); - Vcp.Brightness.Value = (uint)Math.Round(t.Brightness, 0); - Vcp.Contrast.Value = (uint)Math.Round(t.Contrast, 0); - Vcp.Gain.Red.Value = (uint)Math.Round(t.Red, 0); - Vcp.Gain.Blue.Value = (uint)Math.Round(t.Blue, 0); - Vcp.Gain.Green.Value = (uint)Math.Round(t.Green, 0); - } - - public Tune Current => new Tune - { - Brightness = Vcp.Brightness.Value, - Contrast = Vcp.Contrast.Value, - Red = Vcp.Gain.Red.Value, - Blue = Vcp.Gain.Blue.Value, - Green = Vcp.Gain.Green.Value, - }; - - public double Luminance - { - get => _luminance.Value; - set => SetLuminance(value); - } - readonly ObservableAsPropertyHelper _luminance; - - public double MaxLuminance => - (_lut.Count == 0) ? 1 : _lut.Last().Y; - - public double MinLuminance => - (_lut.Count == 0) ? 0 : _lut.First().Y; - - string GetConfigPath(bool create = false) - { - var path = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "Mgth", "LittleBigMouse" - ); - path = Path.Combine(path, _monitor.Id); - path = Path.Combine(path, "Luminance.xml"); - - if(create) Directory.CreateDirectory(path); - - return path; - } - - public void Save() - { - var serializer = new XmlSerializer(typeof(List)); - using TextWriter writer = new StreamWriter(GetConfigPath(true)); - - serializer.Serialize(writer, _lut); - } - - public void Load() - { - var deserializer = new XmlSerializer(typeof(List)); - try - { - using TextReader reader = new StreamReader(GetConfigPath()); - _lut = (List)deserializer.Deserialize(reader); + public bool RemoveLowBrightness(double maxGain) + { + var t = _sortedLut.FirstOrDefault(x => (x.Brightness == 0 && x.MaxGain == maxGain)); + if (t == null) return false; + + _lut.Remove(t); + return true; + } + + public void Add(Tune tune) + { + _lut.Add(tune); + } + + public Tune FromLuminance(double luminance) + { + if (_sortedLut.Count == 0) return Current; + + Tune tSup = null; + Tune tInf = null; + + var i = 0; + for (; i < _sortedLut.Count && _sortedLut[i].Y < luminance; i++) + tInf = _sortedLut[i]; + + // luminance is more than monitor capabilities + if (i >= _sortedLut.Count) return tInf; + + tSup = _sortedLut[i]; + + if (tInf == null) return tSup; + + var dist = tSup.Y - tInf.Y; + var ratio = (luminance - tInf.Y) / dist; + + var t = new Tune + { + Date = tSup.Date > tInf.Date ? tSup.Date : tInf.Date, + + Y = (uint)Math.Round(tInf.Y + (tSup.Y - tInf.Y) * ratio, 0), + x = (uint)Math.Round(tInf.x + (tSup.x - tInf.x) * ratio, 0), + y = (uint)Math.Round(tInf.y + (tSup.y - tInf.y) * ratio, 0), + + Brightness = (uint)Math.Round(tInf.Brightness + (tSup.Brightness - tInf.Brightness) * ratio, 0), + Contrast = (uint)Math.Round(tInf.Contrast + (tSup.Contrast - tInf.Contrast) * ratio, 0), + + Red = (uint)Math.Round(tInf.Red + (tSup.Red - tInf.Red) * ratio, 0), + Blue = (uint)Math.Round(tInf.Blue + (tSup.Blue - tInf.Blue) * ratio, 0), + Green = (uint)Math.Round(tInf.Green + (tSup.Green - tInf.Green) * ratio, 0), + }; + + return t; + } + + public Tune FromBrightness(double brightness) + { + if (_sortedLut is null) return Current; + if (_sortedLut.Count == 0) return Current; + + Tune tSup = null; + Tune tInf = null; + + var i = 0; + for (; i < _sortedLut.Count && _sortedLut[i].Brightness < brightness; i++) + tInf = _sortedLut[i]; + + // luminance is more than monitor capabilities + if (i >= _lut.Count) return tInf; + + tSup = _sortedLut[i]; + + if (tInf == null) return tSup; + + var dist = tSup.Brightness - tInf.Brightness; + var ratio = (brightness - tInf.Brightness) / dist; + + var t = new Tune + { + Date = tSup.Date > tInf.Date ? tSup.Date : tInf.Date, + + Y = (uint)Math.Round(tInf.Y + (tSup.Y - tInf.Y) * ratio, 0), + x = (uint)Math.Round(tInf.x + (tSup.x - tInf.x) * ratio, 0), + y = (uint)Math.Round(tInf.y + (tSup.y - tInf.y) * ratio, 0), + + Brightness = (uint)Math.Round(tInf.Brightness + (tSup.Brightness - tInf.Brightness) * ratio, 0), + Contrast = (uint)Math.Round(tInf.Contrast + (tSup.Contrast - tInf.Contrast) * ratio, 0), + + Red = (uint)Math.Round(tInf.Red + (tSup.Red - tInf.Red) * ratio, 0), + Blue = (uint)Math.Round(tInf.Blue + (tSup.Blue - tInf.Blue) * ratio, 0), + Green = (uint)Math.Round(tInf.Green + (tSup.Green - tInf.Green) * ratio, 0), + }; + + return t; + } + + double GetLuminance() => FromBrightness(Vcp.Brightness.Value).Y; + + void SetLuminance(double luminance) + { + var t = FromLuminance(luminance); + Vcp.Brightness.Value = (uint)Math.Round(t.Brightness, 0); + Vcp.Contrast.Value = (uint)Math.Round(t.Contrast, 0); + Vcp.Gain.Red.Value = (uint)Math.Round(t.Red, 0); + Vcp.Gain.Blue.Value = (uint)Math.Round(t.Blue, 0); + Vcp.Gain.Green.Value = (uint)Math.Round(t.Green, 0); + } + + public Tune Current + { + get + { + var vcp = Vcp; + var gain = vcp?.Gain; + if (vcp is null || gain is null) return new(); + return new() + { + Date = DateTime.Now, + Brightness = vcp.Brightness?.Value??0, + Contrast = vcp.Contrast?.Value??0, + Red = gain.Red.Value, + Blue = gain.Blue.Value, + Green = gain.Green.Value, + }; + } + } + + public double Luminance + { + get => _luminance.Value; + set => SetLuminance(value); + } + readonly ObservableAsPropertyHelper _luminance; + + public double MaxLuminance => + (_sortedLut.Count == 0) ? 1 : _sortedLut.Last().Y; + + public double MinLuminance => + (_sortedLut.Count == 0) ? 0 : _sortedLut.First().Y; + + string GetConfigPath(bool create = false) + { + var path = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), + "Mgth", "LittleBigMouse" + ); + path = Path.Combine(path, _monitor.Id); + if (create) Directory.CreateDirectory(path); + + path = Path.Combine(path, "Luminance.xml"); + + return path; + } + + public void Save() + { + var serializer = new XmlSerializer(typeof(List)); + using TextWriter writer = new StreamWriter(GetConfigPath(true)); + + serializer.Serialize(writer, SortedLut.ToList()); + } + + public void Load() + { + var deserializer = new XmlSerializer(typeof(List)); + try + { + using TextReader reader = new StreamReader(GetConfigPath()); + try + { + var lut = deserializer.Deserialize(reader) as IEnumerable; + if(lut is null) throw new Exception(); + + _lut.Clear(); + foreach (var tune in lut) _lut.Add(tune); + + GenerateSmoothedCurve(); + } + finally + { reader.Close(); - } - catch (IOException ex) when(ex is FileNotFoundException or DirectoryNotFoundException) - { - _lut = new List - { - new() - { - Brightness = MinLuminance, - Y = 0, - Red = Vcp.Gain?.Red.Value ?? 0, - Blue = Vcp.Gain?.Blue.Value ?? 0, - Green = Vcp.Gain?.Green.Value ?? 0, - Contrast = Vcp.Contrast?.Value ?? 0 - }, - new() - { - Brightness = MaxLuminance, - Y = 160, - Red = Vcp.Gain?.Red.Value ?? 0, - Blue = Vcp.Gain?.Blue.Value ?? 0, - Green = Vcp.Gain?.Green.Value ?? 0, - Contrast = Vcp.Contrast?.Value ?? 0 - }, - }; - } - } + } + + } + catch (IOException ex) when (ex is FileNotFoundException or DirectoryNotFoundException) + { + _lut.Clear(); + + _lut.Add(new() + { + Brightness = MinLuminance, + Y = 0, + Red = Vcp.Gain?.Red.Value ?? 0, + Blue = Vcp.Gain?.Blue.Value ?? 0, + Green = Vcp.Gain?.Green.Value ?? 0, + Contrast = Vcp.Contrast?.Value ?? 0 + } + ); + + _lut.Add(new() + { + Brightness = MaxLuminance, + Y = 160, + Red = Vcp.Gain?.Red.Value ?? 0, + Blue = Vcp.Gain?.Blue.Value ?? 0, + Green = Vcp.Gain?.Green.Value ?? 0, + Contrast = Vcp.Contrast?.Value ?? 0 + } + ); + } + } } \ No newline at end of file diff --git a/HLab.Sys/HLab.Sys.Windows.MonitorVcp/Tune.cs b/HLab.Sys/HLab.Sys.Windows.MonitorVcp/Tune.cs index fc079efd..8b20ca23 100644 --- a/HLab.Sys/HLab.Sys.Windows.MonitorVcp/Tune.cs +++ b/HLab.Sys/HLab.Sys.Windows.MonitorVcp/Tune.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Xml.Serialization; namespace HLab.Sys.Windows.MonitorVcp; @@ -21,6 +22,8 @@ public class Tune public double Green; [XmlAttribute] public double Blue; + [XmlAttribute] + public DateTime Date; public double MaxGain => new[]{Red, Green, Blue}.Max(); public double MinGain => new[] { Red, Green, Blue }.Min(); diff --git a/HLab.Sys/HLab.Sys.Windows.Monitors/DeviceCaps.cs b/HLab.Sys/HLab.Sys.Windows.Monitors/DeviceCaps.cs index f3dcecfc..d4b74f59 100644 --- a/HLab.Sys/HLab.Sys.Windows.Monitors/DeviceCaps.cs +++ b/HLab.Sys/HLab.Sys.Windows.Monitors/DeviceCaps.cs @@ -21,7 +21,7 @@ You should have received a copy of the GNU General Public License http://www.mgth.fr */ -using Avalonia; +using HLab.Geo; namespace HLab.Sys.Windows.Monitors; diff --git a/HLab.Sys/HLab.Sys.Windows.Monitors/DisplayDevice.cs b/HLab.Sys/HLab.Sys.Windows.Monitors/DisplayDevice.cs index 786d6cdb..1a89bf67 100644 --- a/HLab.Sys/HLab.Sys.Windows.Monitors/DisplayDevice.cs +++ b/HLab.Sys/HLab.Sys.Windows.Monitors/DisplayDevice.cs @@ -24,19 +24,31 @@ You should have received a copy of the GNU General Public License using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; -using DynamicData; +using System.Xml.Serialization; namespace HLab.Sys.Windows.Monitors; +[XmlInclude(typeof(PhysicalAdapter))] +[XmlInclude(typeof(MonitorDeviceConnection))] public class DisplayDevice { public override string ToString() => $"{GetType().Name} {DeviceName} {DeviceString}"; + [XmlIgnore] readonly List _children = []; - internal void AddChild(DisplayDevice device) + bool IsChildOf(DisplayDevice device) + { + if (Parent == device) return true; + if (Parent == null) return false; + return Parent.IsChildOf(device); + } + + + internal void AddChild(DisplayDevice device) { - _children.Add(device); + if(device.Parent!=this) return; + _children.Add(device); } public IEnumerable AllChildren() where T : DisplayDevice @@ -55,10 +67,15 @@ public IEnumerable AllMonitorDevices() .Select(e => e.First()) .OrderBy(e => e.PhysicalId); + [XmlIgnore] [JsonIgnore] public DisplayDevice? Parent { get; set; } - public IEnumerable Children => _children; + public List Children + { + get => _children; + set => throw new System.NotImplementedException(); + } /// /// Device name as returned by EnumDisplayDevices : @@ -84,21 +101,25 @@ public IEnumerable AllMonitorDevices() /// public string DeviceKey { get; init; } = ""; - public SourceList DisplayModes { get; } = new (); + [XmlIgnore] + public List DisplayModes { get; set; } = new (); /// /// Device mode as returned by EnumDisplaySettingsEx : /// /// + [XmlIgnore] public DisplayMode CurrentMode { get; init; } + [XmlIgnore] public DeviceCaps Capabilities { get; init; } + [XmlIgnore] public DeviceState State { get; init; } public DisplayMode GetBestDisplayMode() { - var best = DisplayModes.Items.FirstOrDefault(); - foreach (var mode in DisplayModes.Items) + var best = DisplayModes.FirstOrDefault(); + foreach (var mode in DisplayModes) { if (mode.BitsPerPixel < best.BitsPerPixel) continue; if (mode.DisplayFrequency < best.DisplayFrequency) continue; diff --git a/HLab.Sys/HLab.Sys.Windows.Monitors/DisplayMode.cs b/HLab.Sys/HLab.Sys.Windows.Monitors/DisplayMode.cs index 32c61321..d422eb02 100644 --- a/HLab.Sys/HLab.Sys.Windows.Monitors/DisplayMode.cs +++ b/HLab.Sys/HLab.Sys.Windows.Monitors/DisplayMode.cs @@ -22,7 +22,7 @@ You should have received a copy of the GNU General Public License */ using System.Runtime.Serialization; -using Avalonia; +using HLab.Geo; namespace HLab.Sys.Windows.Monitors; diff --git a/HLab.Sys/HLab.Sys.Windows.Monitors/Edid.cs b/HLab.Sys/HLab.Sys.Windows.Monitors/Edid.cs index 6ddf55d3..15ac273e 100644 --- a/HLab.Sys/HLab.Sys.Windows.Monitors/Edid.cs +++ b/HLab.Sys/HLab.Sys.Windows.Monitors/Edid.cs @@ -21,8 +21,8 @@ You should have received a copy of the GNU General Public License http://www.mgth.fr */ -using Avalonia; using System.Runtime.Serialization; +using HLab.Geo; namespace HLab.Sys.Windows.Monitors; @@ -66,45 +66,47 @@ public interface IEdid int Checksum { get; } } - -public class Edid : IEdid +public static class EdidParser { - public Edid(string key, byte[] edid) + public static Edid Parse(string key, byte[] edid) { - HKeyName = key; + var e = new Edid + { + HKeyName = key + }; - if (edid.Length <= 9) return; + if (edid.Length <= 9) return e; - ManufacturerCode = "" + (char)(64 + ((edid[8] >> 2) & 0x1F)) + e.ManufacturerCode = "" + (char)(64 + ((edid[8] >> 2) & 0x1F)) + (char)(64 + (((edid[8] << 3) | (edid[9] >> 5)) & 0x1F)) + (char)(64 + (edid[9] & 0x1F)); - if (edid.Length <= 11) return; + if (edid.Length <= 11) return e; - ProductCode = (edid[10] + (edid[11] << 8)).ToString("X4"); + e.ProductCode = (edid[10] + (edid[11] << 8)).ToString("X4"); - if (edid.Length <= 15) return; + if (edid.Length <= 15) return e; var serial = ""; for (var i = 12; i <= 15; i++) serial = edid[i].ToString("X2") + serial; - Serial = serial; + e.Serial = serial; - if (edid.Length <= 16) return; - Week = edid[16]; + if (edid.Length <= 16) return e; + e.Week = edid[16]; - if (edid.Length < 18) return; - Year = edid[17] + 1990; + if (edid.Length < 18) return e; + e.Year = edid[17] + 1990; - if (edid.Length <= 19) return; - Version = edid[18] + "." + edid[19]; + if (edid.Length <= 19) return e; + e.Version = edid[18] + "." + edid[19]; - if (edid.Length <= 20) return; + if (edid.Length <= 20) return e; - Digital = (edid[20] >> 7) == 1; - if (Digital) + e.Digital = (edid[20] >> 7) == 1; + if (e.Digital) { - BitDepth = 4 + ((edid[20] & 0b01110000) >> 3); - VideoInterface = (edid[20] & 0b1111) switch + e.BitDepth = 4 + ((edid[20] & 0b01110000) >> 3); + e.VideoInterface = (edid[20] & 0b1111) switch { 0 => "undefined", 2 => "HDMIa", @@ -119,42 +121,41 @@ public Edid(string key, byte[] edid) { } - if (edid.Length <= 21) return; + if (edid.Length <= 21) return e; - var h = edid[21] * 10; + e.PhysicalWidth = edid[21] * 10; - if (edid.Length <= 22) return; + if (edid.Length <= 22) return e; - var v = edid[22] * 10; + e.PhysicalHeight = edid[22] * 10; - PhysicalSize = new Size(h, v); - if (edid.Length <= 23) return; + if (edid.Length <= 23) return e; if (edid[23] < 255) { - Gamma = 1.0 + edid[23] / 100.0; + e.Gamma = 1.0 + edid[23] / 100.0; } else { // todo : else check DI-EXT block } - if (edid.Length <= 24) return; - DpmsStandbySupported = (edid[24] & (0b1 << 7)) > 0; - DpmsSuspendSupported = (edid[24] & (0b1 << 6)) > 0; - DpmsActiveOffSupported = (edid[24] & (0b1 << 5)) > 0; + if (edid.Length <= 24) return e; + e.DpmsStandbySupported = (edid[24] & (0b1 << 7)) > 0; + e.DpmsSuspendSupported = (edid[24] & (0b1 << 6)) > 0; + e.DpmsActiveOffSupported = (edid[24] & (0b1 << 5)) > 0; - if (Digital) + if (e.Digital) { - YCrCb422Support = (edid[24] & (0b1 << 4)) > 0; - YCrCb444Support = (edid[24] & (0b1 << 3)) > 0; + e.YCrCb422Support = (edid[24] & (0b1 << 4)) > 0; + e.YCrCb444Support = (edid[24] & (0b1 << 3)) > 0; } else { // todo : analog display } - if (edid.Length <= 34) return; + if (edid.Length <= 34) return e; if ((edid[24] & (0b1 << 2)) > 0) { @@ -168,111 +169,115 @@ public Edid(string key, byte[] edid) var whiteX = ((edid[26] >> 2) & 0b11) | (((int)edid[33]) << 2); var whiteY = (edid[26] & 0b11) | (((int)edid[34]) << 2); - RedX = ((double)redX) / 1024.0; - RedY = ((double)redY) / 1024.0; - GreenX = ((double)greenX) / 1024.0; - GreenY = ((double)greenY) / 1024.0; - BlueX = ((double)blueX) / 1024.0; - BlueY = ((double)blueY) / 1024.0; - WhiteX = ((double)whiteX) / 1024.0; - WhiteY = ((double)whiteY) / 1024.0; + e.RedX = ((double)redX) / 1024.0; + e.RedY = ((double)redY) / 1024.0; + e.GreenX = ((double)greenX) / 1024.0; + e.GreenY = ((double)greenY) / 1024.0; + e.BlueX = ((double)blueX) / 1024.0; + e.BlueY = ((double)blueY) / 1024.0; + e.WhiteX = ((double)whiteX) / 1024.0; + e.WhiteY = ((double)whiteY) / 1024.0; } - if (edid.Length <= 68) return; - - PhysicalSize = new Size( - ((edid[68] & 0xF0) << 4) + edid[66], - ((edid[68] & 0x0F) << 8) + edid[67] - ); + if (edid.Length <= 68) return e; - Model = Block((char)0xFC, edid); + e.PhysicalWidth = ((edid[68] & 0xF0) << 4) + edid[66]; + e.PhysicalHeight = ((edid[68] & 0x0F) << 8) + edid[67]; - SerialNumber = Block((char)0xFF, edid); + e.Model = Block((char)0xFC, edid); - if (edid.Length <= 127) return; - Checksum = edid[127]; + e.SerialNumber = Block((char)0xFF, edid); + if (edid.Length <= 127) return e; + e.Checksum = edid[127]; + return e; + } + static string Block(char code, byte[] edid) + { + for (var i = 54; i <= 108; i += 18) + { + if (i >= edid.Length || edid[i] != 0 || edid[i + 1] != 0 || edid[i + 2] != 0 || + edid[i + 3] != code) continue; + var s = ""; + for (var j = i + 5; j < i + 18; j++) + { + var c = (char)edid[j]; + if (c == (char)0x0A) break; + if (c == (char)0x00) break; + s += c; + } + return s; + } + return ""; } + +} + + +public class Edid +{ [DataMember] - public string HKeyName { get; } + public string HKeyName { get; set; } [DataMember] - public string ProductCode { get; } + public string ProductCode { get; set; } [DataMember] - public string Serial { get; } + public string Serial { get; set; } [DataMember] - public Size PhysicalSize { get; } + public double PhysicalWidth { get; set; } [DataMember] - public string ManufacturerCode { get; } + public double PhysicalHeight { get; set; } [DataMember] - public string Model { get; } + public string ManufacturerCode { get; set; } [DataMember] - public string SerialNumber { get; } + public string Model { get; set; } [DataMember] - public int Week { get; } + public string SerialNumber { get; set; } [DataMember] - public int Year { get; } + public int Week { get; set; } [DataMember] - public string Version { get; } + public int Year { get; set; } [DataMember] - public bool Digital { get; } + public string Version { get; set; } + [DataMember] + public bool Digital { get; set; } [DataMember] - public int BitDepth { get; } + public int BitDepth { get; set; } [DataMember] - public string VideoInterface { get; } + public string VideoInterface { get; set; } [DataMember] - public double Gamma { get; } + public double Gamma { get; set; } [DataMember] - public bool DpmsStandbySupported { get; } + public bool DpmsStandbySupported { get; set; } [DataMember] - public bool DpmsSuspendSupported { get; } + public bool DpmsSuspendSupported { get; set; } [DataMember] - public bool DpmsActiveOffSupported { get; } + public bool DpmsActiveOffSupported { get; set; } [DataMember] - public bool YCrCb444Support { get; } + public bool YCrCb444Support { get; set; } [DataMember] - public bool YCrCb422Support { get; } + public bool YCrCb422Support { get; set; } [DataMember] - public double sRGB { get; } + public double sRGB { get; set; } [DataMember] - public double RedX { get; } + public double RedX { get; set; } [DataMember] - public double RedY { get; } + public double RedY { get; set; } [DataMember] - public double GreenX { get; } + public double GreenX { get; set; } [DataMember] - public double GreenY { get; } + public double GreenY { get; set; } [DataMember] - public double BlueX { get; } + public double BlueX { get; set; } [DataMember] - public double BlueY { get; } + public double BlueY { get ; set; } [DataMember] - public double WhiteX { get; } + public double WhiteX { get; set; } [DataMember] - public double WhiteY { get; } + public double WhiteY { get; set; } [DataMember] - public int Checksum { get; } - - static string Block(char code, byte[] edid) - { - for (var i = 54; i <= 108; i += 18) - { - if (i >= edid.Length || edid[i] != 0 || edid[i + 1] != 0 || edid[i + 2] != 0 || - edid[i + 3] != code) continue; - var s = ""; - for (var j = i + 5; j < i + 18; j++) - { - var c = (char)edid[j]; - if (c == (char)0x0A) break; - if (c == (char)0x00) break; - s += c; - } - return s; - } - return ""; - } - + public int Checksum { get; set; } } \ No newline at end of file diff --git a/HLab.Sys/HLab.Sys.Windows.Monitors/Factory/MonitorDeviceHelper.cs b/HLab.Sys/HLab.Sys.Windows.Monitors/Factory/MonitorDeviceHelper.cs index 67152838..3548397e 100644 --- a/HLab.Sys/HLab.Sys.Windows.Monitors/Factory/MonitorDeviceHelper.cs +++ b/HLab.Sys/HLab.Sys.Windows.Monitors/Factory/MonitorDeviceHelper.cs @@ -4,8 +4,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; -using DynamicData; -using Avalonia; +using HLab.Geo; using Microsoft.Win32; using HLab.Sys.Windows.API; @@ -282,7 +281,7 @@ public static string GetSourceId(string deviceId, Edid edid) : $"{pnpCode}{edid.SerialNumber}_{edid.Week:X2}_{edid.Year:X4}_{edid.Checksum:X2}"; } - public static Edid GetEdid(string deviceId) + public static Edid? GetEdid(string deviceId) { var devInfo = SetupDiGetClassDevsEx( ref GUID_CLASS_MONITOR, //class GUID @@ -330,7 +329,7 @@ public static Edid GetEdid(string deviceId) using var keyEdid = RegistryKey(hEdidRegKey); var edid = (byte[])keyEdid.GetValue("EDID"); - return edid != null ? new Edid(hKeyName, edid) : null; + return edid != null ? EdidParser.Parse(hKeyName, edid) : null; } } } diff --git a/HLab.Sys/HLab.Sys.Windows.Monitors/HLab.Sys.Windows.Monitors.csproj b/HLab.Sys/HLab.Sys.Windows.Monitors/HLab.Sys.Windows.Monitors.csproj index f475baed..8b97f634 100644 --- a/HLab.Sys/HLab.Sys.Windows.Monitors/HLab.Sys.Windows.Monitors.csproj +++ b/HLab.Sys/HLab.Sys.Windows.Monitors/HLab.Sys.Windows.Monitors.csproj @@ -1,22 +1,24 @@  - net8.0 + net10.0 x64;x86;AnyCpu enable HLab.Sys.Windows.Monitors Debug;Release true 12 - 2.4.0.0 + 2.5.0.0 - - + + + + diff --git a/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorDevice.cs b/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorDevice.cs index b8a4df45..7f25f480 100644 --- a/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorDevice.cs +++ b/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorDevice.cs @@ -1,200 +1,28 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.Runtime.Serialization; -using Avalonia; -using Avalonia.Controls; -using Microsoft.Win32; +using System.Xml.Serialization; namespace HLab.Sys.Windows.Monitors; public class MonitorDevice : IEquatable { - [DataMember] public string Id { get; init; } = ""; - [DataMember] public string PnpCode { get; init; } = ""; - [DataMember] public string PhysicalId { get; set; } = ""; - [DataMember] public string SourceId { get; set; } = ""; - [DataMember] public IEdid Edid { get; init; } - [DataMember] public string MonitorNumber { get; set; } = ""; + public string Id { get; init; } = ""; + public string PnpCode { get; init; } = ""; + public string PhysicalId { get; set; } = ""; + public string SourceId { get; set; } = ""; + public Edid Edid { get; set; } + public string MonitorNumber { get; set; } = ""; - public List Connections = new (); + [XmlIgnore] + public List Connections = new(); - public override bool Equals(object obj) - { - if(obj is MonitorDevice other) return Id == other.Id; - return base.Equals(obj); - } + public override bool Equals(object obj) + { + if (obj is MonitorDevice other) return Id == other.Id; + return base.Equals(obj); + } - public override int GetHashCode() => HashCode.Combine(Id); - - public bool Equals(MonitorDevice other) => Id == other.Id; -} - -public class MonitorDeviceConnection : DisplayDevice -{ - public new PhysicalAdapter Parent - { - get { - if (base.Parent is PhysicalAdapter adapter) return adapter; - throw new InvalidOperationException("Parent is not a PhysicalAdapter"); - } - set => base.Parent = value; - } - - public MonitorDevice Monitor { get; set; } - - class EdidDesign : IEdid - { - public EdidDesign() - { - if(!Design.IsDesignMode) throw new InvalidOperationException("Only for design mode"); - } - - public string HKeyName => "HKLM://"; - public string ManufacturerCode => "SAM"; - public string ProductCode { get; } - public string Serial { get; } - public int Week => 42; - public int Year { get; } - public string Version { get; } - public bool Digital { get; } - public int BitDepth { get; } - public string VideoInterface { get; } - public Size PhysicalSize => new Size(600, 340); - public string Model => "S24D300"; - public string SerialNumber => "S/N: 123456789"; - public double Gamma => 2.2; - public bool DpmsStandbySupported => true; - public bool DpmsSuspendSupported => true; - public bool DpmsActiveOffSupported => true; - public bool YCrCb444Support => true; - public bool YCrCb422Support => true; - public double sRGB => 0.98; - public double RedX => 0.64; - public double RedY => 0.33; - public double GreenX => 0.3; - public double GreenY => 0.6; - public double BlueX => 0.15; - public double BlueY => 0.06; - public double WhiteX => 0.3127; - public double WhiteY => 0.3127; - public int Checksum => int.MinValue; - } - - public static MonitorDeviceConnection MonitorDesign - { - get - { - if(!Design.IsDesignMode) throw new InvalidOperationException("Only for design mode"); - - return new MonitorDeviceConnection - { - //Edid = new EdidDesign() - }; - } - } - - //------------------------------------------------------------------------ - public override bool Equals(object obj) => obj is MonitorDeviceConnection other ? Id == other.Id : base.Equals(obj); - - - public override int GetHashCode() { - return ("DisplayMonitor" + Id).GetHashCode(); - } - - void OpenRegKey(string keyString) { - - keyString = keyString.Replace(@"\MACHINE\",@"\HKEY_LOCAL_MACHINE\"); - keyString = keyString.Replace(@"\USER\",@"\HKEY_CURRENT_USER\"); - - using (var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Applets\Regedit", true)) { - - if(key == null) return; - var value = key.GetValue("LastKey").ToString(); - - var list = value.Split('\\'); - if(list.Length > 0) - { - keyString = keyString.Replace(@"\REGISTRY\",@$"{list[0]}\"); - key.SetValue("LastKey", keyString); - } - } - - Process.Start("regedit.exe"); - } - - - public void DisplayValues(Action addValue) { - //addValue("Registry", Edid.HKeyName, () => { OpenRegKey(Edid.HKeyName); }, false); - //addValue("Microsoft Id", PhysicalId, null, false); - - if(Parent != null) - { - // EnumDisplaySettings - addValue("", "EnumDisplaySettings", null, true); - addValue("DisplayOrientation", Parent.CurrentMode?.DisplayOrientation.ToString() ?? "", null, false); - addValue("Position", Parent.CurrentMode?.Position.ToString() ?? "", null, false); - addValue("Pels", Parent.CurrentMode?.Pels.ToString() ?? "", null, false); - addValue("BitsPerPixel", Parent.CurrentMode?.BitsPerPixel.ToString() ?? "", null, false); - addValue("DisplayFrequency", Parent.CurrentMode?.DisplayFrequency.ToString() ?? "", null, false); - addValue("DisplayFlags", Parent.CurrentMode?.DisplayFlags.ToString() ?? "", null, false); - addValue("DisplayFixedOutput", Parent.CurrentMode?.DisplayFixedOutput.ToString() ?? "", null, false); - - // GetDeviceCaps - addValue("", "GetDeviceCaps", null, true); - addValue("Size", Parent.Capabilities.Size.ToString(), null, false); - addValue("Res", Parent.Capabilities.Resolution.ToString(), null, false); - addValue("LogPixels", Parent.Capabilities.LogPixels.ToString(), null, false); - addValue("BitsPixel", Parent.Capabilities.BitsPixel.ToString(), null, false); - //AddValue("Color Planes", Monitor.Adapter.DeviceCaps.Planes.ToString()); - addValue("Aspect", Parent.Capabilities.Aspect.ToString(), null, false); - //AddValue("BltAlignment", Monitor.Adapter.DeviceCaps.BltAlignment.ToString()); - - //GetDpiForMonitor - addValue("", "GetDpiForMonitor", null, true); - addValue("EffectiveDpi", Parent.EffectiveDpi.ToString(), null, false); - addValue("AngularDpi", Parent.AngularDpi.ToString(), null, false); - addValue("RawDpi", Parent.RawDpi.ToString(), null, false); - - // GetMonitorInfo - addValue("", "GetMonitorInfo", null, true); - addValue("Primary", Parent.Primary.ToString(), null, false); - addValue("MonitorArea", Parent.MonitorArea.ToString(), null, false); - addValue("WorkArea", Parent.WorkArea.ToString(), null, false); - - - //// EDID - //addValue("", "EDID", null, true); - //addValue("ManufacturerCode", Edid?.ManufacturerCode, null, false); - //addValue("ProductCode", Edid?.ProductCode, null, false); - //addValue("Serial", Edid?.Serial, null, false); - //addValue("Model", Edid?.Model, null, false); - //addValue("SerialNo", Edid?.SerialNumber, null, false); - //addValue("SizeInMm", Edid?.PhysicalSize.ToString(), null, false); - //addValue("VideoInterface", Edid?.VideoInterface.ToString(), null, false); - - // GetScaleFactorForMonitor - addValue("", "GetScaleFactorForMonitor", null, true); - addValue("ScaleFactor", Parent.ScaleFactor.ToString(CultureInfo.CurrentCulture) ?? "", null, false); - - // EnumDisplayDevices - addValue("", "EnumDisplayDevices", null, true); - addValue("DeviceId", Parent.Id, null, false); - addValue("DeviceKey", Parent.DeviceKey, null, false); - addValue("DeviceString", Parent.DeviceString, null, false); - addValue("DeviceName", Parent.DeviceName, null, false); - addValue("StateFlags", Parent.State.ToString(), null, false); - } - - addValue("", "EnumDisplayDevices", null, true); - addValue("DeviceId", Id, null, false); - addValue("DeviceKey", DeviceKey, null, false); - addValue("DeviceString", DeviceString, null, false); - addValue("DeviceName", DeviceName, null, false); - addValue("StateFlags", State.ToString(), null, false); - - } - public override string ToString() => DeviceString; + public override int GetHashCode() => HashCode.Combine(Id); + public bool Equals(MonitorDevice other) => Id == other.Id; } \ No newline at end of file diff --git a/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorDeviceConnection.cs b/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorDeviceConnection.cs new file mode 100644 index 00000000..8007d908 --- /dev/null +++ b/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorDeviceConnection.cs @@ -0,0 +1,186 @@ +using System; +using System.Diagnostics; +using System.Globalization; +using System.Xml.Serialization; +using Microsoft.Win32; + +namespace HLab.Sys.Windows.Monitors; + +public class MonitorDeviceConnection : DisplayDevice +{ + [XmlIgnore] + public new PhysicalAdapter Parent + { + get + { + if (base.Parent is PhysicalAdapter adapter) return adapter; + throw new InvalidOperationException("Parent is not a PhysicalAdapter"); + } + set => base.Parent = value; + } + + public MonitorDevice Monitor { get; set; } + + class EdidDesign : Edid + { + public EdidDesign() + { + //if (!Design.IsDesignMode) throw new InvalidOperationException("Only for design mode"); + HKeyName = "HKLM://"; + ManufacturerCode = "SAM"; + ProductCode = "S24D300"; + Serial= "123456789"; + Week = 42; + Year = 2024; + Version = "1.0"; + Digital = true; + BitDepth = 8; + VideoInterface = "Dvi"; + PhysicalWidth = 600; + PhysicalHeight = 340; + Model = "S24D300"; + SerialNumber = "S/N: 123456789"; + Gamma = 2.2; + DpmsStandbySupported = true; + DpmsSuspendSupported = true; + DpmsActiveOffSupported = true; + YCrCb444Support = true; + YCrCb422Support = true; + sRGB = 0.98; + RedX = 0.64; + RedY = 0.33; + GreenX = 0.3; + GreenY = 0.6; + BlueX = 0.15; + BlueY = 0.06; + WhiteX = 0.3127; + WhiteY = 0.3127; + Checksum = int.MinValue; + } + + } + + public static MonitorDeviceConnection MonitorDesign + { + get + { + //if (!Design.IsDesignMode) throw new InvalidOperationException("Only for design mode"); + + return new MonitorDeviceConnection + { + Monitor = new MonitorDevice + { + Edid = new EdidDesign() + }, + }; + } + } + + //------------------------------------------------------------------------ + public override bool Equals(object obj) => obj is MonitorDeviceConnection other ? Id == other.Id : base.Equals(obj); + + + public override int GetHashCode() + { + return ("DisplayMonitor" + Id).GetHashCode(); + } + + void OpenRegKey(string keyString) + { + + keyString = keyString.Replace(@"\MACHINE\", @"\HKEY_LOCAL_MACHINE\"); + keyString = keyString.Replace(@"\USER\", @"\HKEY_CURRENT_USER\"); + + using (var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Applets\Regedit", true)) + { + + if (key == null) return; + var value = key.GetValue("LastKey").ToString(); + + var list = value.Split('\\'); + if (list.Length > 0) + { + keyString = keyString.Replace(@"\REGISTRY\", @$"{list[0]}\"); + key.SetValue("LastKey", keyString); + } + } + + Process.Start("regedit.exe"); + } + + + public void DisplayValues(Action addValue) + { + //addValue("Registry", Edid.HKeyName, () => { OpenRegKey(Edid.HKeyName); }, false); + //addValue("Microsoft Id", PhysicalId, null, false); + + if (Parent != null) + { + // EnumDisplaySettings + addValue("", "EnumDisplaySettings", null, true); + addValue("DisplayOrientation", Parent.CurrentMode?.DisplayOrientation.ToString() ?? "", null, false); + addValue("Position", Parent.CurrentMode?.Position.ToString() ?? "", null, false); + addValue("Pels", Parent.CurrentMode?.Pels.ToString() ?? "", null, false); + addValue("BitsPerPixel", Parent.CurrentMode?.BitsPerPixel.ToString() ?? "", null, false); + addValue("DisplayFrequency", Parent.CurrentMode?.DisplayFrequency.ToString() ?? "", null, false); + addValue("DisplayFlags", Parent.CurrentMode?.DisplayFlags.ToString() ?? "", null, false); + addValue("DisplayFixedOutput", Parent.CurrentMode?.DisplayFixedOutput.ToString() ?? "", null, false); + + // GetDeviceCaps + addValue("", "GetDeviceCaps", null, true); + addValue("Size", Parent.Capabilities.Size.ToString(), null, false); + addValue("Res", Parent.Capabilities.Resolution.ToString(), null, false); + addValue("LogPixels", Parent.Capabilities.LogPixels.ToString(), null, false); + addValue("BitsPixel", Parent.Capabilities.BitsPixel.ToString(), null, false); + //AddValue("Color Planes", Monitor.Adapter.DeviceCaps.Planes.ToString()); + addValue("Aspect", Parent.Capabilities.Aspect.ToString(), null, false); + //AddValue("BltAlignment", Monitor.Adapter.DeviceCaps.BltAlignment.ToString()); + + //GetDpiForMonitor + addValue("", "GetDpiForMonitor", null, true); + addValue("EffectiveDpi", Parent.EffectiveDpi.ToString(), null, false); + addValue("AngularDpi", Parent.AngularDpi.ToString(), null, false); + addValue("RawDpi", Parent.RawDpi.ToString(), null, false); + + // GetMonitorInfo + addValue("", "GetMonitorInfo", null, true); + addValue("Primary", Parent.Primary.ToString(), null, false); + addValue("MonitorArea", Parent.MonitorArea.ToString(), null, false); + addValue("WorkArea", Parent.WorkArea.ToString(), null, false); + + + //// EDID + addValue("", "EDID", null, true); + addValue("ManufacturerCode", Monitor?.Edid?.ManufacturerCode, null, false); + addValue("ProductCode", Monitor?.Edid?.ProductCode, null, false); + addValue("Serial", Monitor?.Edid?.Serial, null, false); + addValue("Model", Monitor?.Edid?.Model, null, false); + addValue("SerialNo", Monitor?.Edid?.SerialNumber, null, false); + addValue("SizeInMm H", Monitor?.Edid?.PhysicalWidth.ToString(), null, false); + addValue("SizeInMm V", Monitor?.Edid?.PhysicalHeight.ToString(), null, false); + addValue("VideoInterface", Monitor?.Edid?.VideoInterface.ToString(), null, false); + + // GetScaleFactorForMonitor + addValue("", "GetScaleFactorForMonitor", null, true); + addValue("ScaleFactor", Parent.ScaleFactor.ToString(CultureInfo.CurrentCulture) ?? "", null, false); + + // EnumDisplayDevices + addValue("", "EnumDisplayDevices", null, true); + addValue("DeviceId", Parent.Id, null, false); + addValue("DeviceKey", Parent.DeviceKey, null, false); + addValue("DeviceString", Parent.DeviceString, null, false); + addValue("DeviceName", Parent.DeviceName, null, false); + addValue("StateFlags", Parent.State.ToString(), null, false); + } + + addValue("", "EnumDisplayDevices", null, true); + addValue("DeviceId", Id, null, false); + addValue("DeviceKey", DeviceKey, null, false); + addValue("DeviceString", DeviceString, null, false); + addValue("DeviceName", DeviceName, null, false); + addValue("StateFlags", State.ToString(), null, false); + + } + public override string ToString() => DeviceString; + +} \ No newline at end of file diff --git a/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorDeviceDesign.cs b/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorDeviceDesign.cs index 922e1083..918e940a 100644 --- a/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorDeviceDesign.cs +++ b/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorDeviceDesign.cs @@ -1,5 +1,4 @@ using System; -using Avalonia.Controls; namespace HLab.Sys.Windows.Monitors; @@ -7,7 +6,7 @@ public class MonitorDeviceDesign : MonitorDeviceConnection { MonitorDeviceDesign() { - if(!Design.IsDesignMode) throw new InvalidOperationException("Only for design mode"); + //if(!Design.IsDesignMode) throw new InvalidOperationException("Only for design mode"); Monitor = new MonitorDevice{ diff --git a/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorsService.cs b/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorsService.cs index 23d61cfc..161c8ac9 100644 --- a/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorsService.cs +++ b/HLab.Sys/HLab.Sys.Windows.Monitors/MonitorsService.cs @@ -27,7 +27,7 @@ You should have received a copy of the GNU General Public License using System; using System.IO; using System.Runtime.Serialization; -using Avalonia.Media; +using HLab.ColorTools; using HLab.Sys.Windows.API; using HLab.Sys.Windows.Monitors.Factory; @@ -55,7 +55,7 @@ public void UpdateDevices() _root = null; } - [DataMember] public Color Background { get; set; } + [DataMember] public ColorRGB Background { get; set; } [DataMember] public DesktopWallpaperPosition WallpaperPosition { get; set; } diff --git a/HLab.Sys/HLab.Sys.Windows.Monitors/PhysicalAdapter.cs b/HLab.Sys/HLab.Sys.Windows.Monitors/PhysicalAdapter.cs index 3e419a04..76330f97 100644 --- a/HLab.Sys/HLab.Sys.Windows.Monitors/PhysicalAdapter.cs +++ b/HLab.Sys/HLab.Sys.Windows.Monitors/PhysicalAdapter.cs @@ -1,11 +1,13 @@ -using Avalonia; -using System.Runtime.Serialization; +using System.Runtime.Serialization; using HLab.Sys.Windows.API; +using System.Xml.Serialization; +using HLab.Geo; namespace HLab.Sys.Windows.Monitors; public class PhysicalAdapter : DisplayDevice { + [XmlIgnore] public nint HMonitor { get; set; } // MONITORINFOEX diff --git a/HLab.Sys/HLab.Sys.Windows.Monitors/WinApiExtentions.cs b/HLab.Sys/HLab.Sys.Windows.Monitors/WinApiExtentions.cs index 3db1de6c..fcad9e86 100644 --- a/HLab.Sys/HLab.Sys.Windows.Monitors/WinApiExtentions.cs +++ b/HLab.Sys/HLab.Sys.Windows.Monitors/WinApiExtentions.cs @@ -1,7 +1,7 @@ -using Avalonia; -using DynamicData; +using DynamicData; using HLab.Sys.Windows.API; using System; +using HLab.Geo; namespace HLab.Sys.Windows.Monitors; diff --git a/LittleBigMouse-Hook-Rust/.idea/.gitignore b/LittleBigMouse-Hook-Rust/.idea/.gitignore new file mode 100644 index 00000000..13566b81 --- /dev/null +++ b/LittleBigMouse-Hook-Rust/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/LittleBigMouse-Hook-Rust/.idea/LittleBigMouse-Hook-Rust.iml b/LittleBigMouse-Hook-Rust/.idea/LittleBigMouse-Hook-Rust.iml new file mode 100644 index 00000000..cf84ae4a --- /dev/null +++ b/LittleBigMouse-Hook-Rust/.idea/LittleBigMouse-Hook-Rust.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/LittleBigMouse-Hook-Rust/.idea/modules.xml b/LittleBigMouse-Hook-Rust/.idea/modules.xml new file mode 100644 index 00000000..b29cd61a --- /dev/null +++ b/LittleBigMouse-Hook-Rust/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/LittleBigMouse-Hook-Rust/.idea/vcs.xml b/LittleBigMouse-Hook-Rust/.idea/vcs.xml new file mode 100644 index 00000000..626bd4b1 --- /dev/null +++ b/LittleBigMouse-Hook-Rust/.idea/vcs.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/LittleBigMouse-Hook-Rust/Cargo.lock b/LittleBigMouse-Hook-Rust/Cargo.lock new file mode 100644 index 00000000..e9259fdf --- /dev/null +++ b/LittleBigMouse-Hook-Rust/Cargo.lock @@ -0,0 +1,25 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "LittleBigMouse-Hook-Rust" +version = "0.1.0" +dependencies = [ + "num-traits", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] diff --git a/LittleBigMouse-Hook-Rust/Cargo.toml b/LittleBigMouse-Hook-Rust/Cargo.toml new file mode 100644 index 00000000..1dcb2e11 --- /dev/null +++ b/LittleBigMouse-Hook-Rust/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "LittleBigMouse-Hook-Rust" +version = "0.1.0" +edition = "2024" + +[dependencies] +num-traits = "0.2" diff --git a/LittleBigMouse-Hook-Rust/src/engine.rs b/LittleBigMouse-Hook-Rust/src/engine.rs new file mode 100644 index 00000000..202308a0 --- /dev/null +++ b/LittleBigMouse-Hook-Rust/src/engine.rs @@ -0,0 +1,135 @@ +use std::collections::HashMap; + +// Supposant que ces modules existent ailleurs dans le projet +use crate::geometry::{Point, Rect}; +use crate::xml::tinyxml2; +use crate::zones::zone_link::ZoneLink; +use crate::zones::zones_layout::ZonesLayout; + +pub struct Zone { + travels: HashMap<*const Zone, Vec>>, + pixels_bounds: Rect, + physical_bounds: Rect, + physical_inside: Rect, + pub id: i32, + pub device_id: String, + pub name: String, + pub main: Option<*mut Zone>, + pub left_zones: Option<*mut ZoneLink>, + pub top_zones: Option<*mut ZoneLink>, + pub right_zones: Option<*mut ZoneLink>, + pub bottom_zones: Option<*mut ZoneLink>, + pub dpi: f64, +} + +impl PartialEq for Zone { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} + +impl Zone { + fn get_travel_pixels(&self, zones: &[*const Zone], target: *const Zone) -> Vec> { + // Implémentation à ajouter + Vec::new() + } + + pub fn new( + id: i32, + device_id: String, + name: String, + pixels_bounds: Rect, + physical_bounds: Rect, + main: Option<*mut Zone>, + ) -> Self { + Zone { + travels: HashMap::new(), + pixels_bounds, + physical_bounds, + physical_inside: physical_bounds, // À ajuster selon les besoins + id, + device_id, + name, + main, + left_zones: None, + top_zones: None, + right_zones: None, + bottom_zones: None, + dpi: 0.0, + } + } + + pub fn pixels_bounds(&self) -> Rect { + self.pixels_bounds + } + + pub fn physical_bounds(&self) -> Rect { + self.physical_bounds + } + + pub fn physical_inside(&self) -> Rect { + self.physical_inside + } + + pub fn is_main(&self) -> bool { + self.main.is_none() + } + + pub fn compute_dpi(&mut self) { + // Implémentation à ajouter + } + + pub fn init_zone_links(&self, layout: &ZonesLayout) { + // Implémentation à ajouter + } + + pub fn to_physical(&self, px: Point) -> Point { + // Implémentation à ajouter + Point::new(0.0, 0.0) + } + + pub fn to_pixels(&self, mm: Point) -> Point { + // Implémentation à ajouter + Point::new(0, 0) + } + + pub fn center_pixel(&self) -> Point { + // Implémentation à ajouter + Point::new(0, 0) + } + + pub fn contains(&self, point: &Point) -> bool { + // Implémentation à ajouter + false + } + + pub fn contains_mm(&self, mm: &Point) -> bool { + // Implémentation à ajouter + false + } + + pub fn inside_pixels_bounds(&self, px: Point) -> Point { + // Implémentation à ajouter + Point::new(0, 0) + } + + pub fn inside_physical_bounds(&self, mm: Point) -> Point { + // Implémentation à ajouter + Point::new(0.0, 0.0) + } + + pub fn travel_pixels(&mut self, zones: &[*const Zone], target: *const Zone) -> &mut Vec> { + // Implémentation à ajouter + self.travels.entry(target).or_insert_with(Vec::new) + } + + pub fn horizontal_reachable(&self, mm: &Point) -> bool { + // Implémentation à ajouter + false + } + + pub fn vertical_reachable(&self, mm: &Point) -> bool { + // Implémentation à ajouter + false + } +} diff --git a/LittleBigMouse-Hook-Rust/src/line.rs b/LittleBigMouse-Hook-Rust/src/line.rs new file mode 100644 index 00000000..b9874fd5 --- /dev/null +++ b/LittleBigMouse-Hook-Rust/src/line.rs @@ -0,0 +1,112 @@ +use crate::point::Point; + +#[derive(Debug)] +pub struct Line { + // Y = slope * X + origin + slope: f64, + // y pour x==0 + origin: T, +} + +impl Line +where + T: Copy + std::ops::Div + std::ops::Mul + + std::ops::Sub + std::ops::Add + + PartialEq + From +{ + pub fn new(slope: f64, y_for_x0: T) -> Self { + Line { + slope, + origin: y_for_x0, + } + } + + pub fn new_vertical(x: T) -> Self { + Line { + slope: f64::MAX, + origin: x, + } + } + + pub fn is_vertical(&self) -> bool { + !(self.slope < f64::MAX) + } + + pub fn slope(&self) -> f64 { + self.slope + } + + pub fn x_at_y0(&self) -> T { + if self.is_vertical() { + self.origin + } else { + let slope_t: T = T::from(self.slope); + self.origin / slope_t + } + } + + pub fn y_at_x0(&self) -> T { + if self.is_vertical() { + T::from(0.0) + } else { + self.origin + } + } + + pub fn x(&self, y: T) -> T { + if self.slope == 0.0 { + T::from(0.0) // Erreur + } else if self.is_vertical() { + self.origin + } else { + let slope_t: T = T::from(self.slope); + self.origin - y / slope_t + } + } + + pub fn y(&self, x: T) -> T { + if self.slope == 0.0 { + self.origin + } else if self.is_vertical() { + T::from(0.0) // Erreur + } else { + let slope_t: T = T::from(self.slope); + slope_t * x + self.origin + } + } + + pub fn origin(&self) -> Point { + Point::new(T::from(0.0), self.y_at_x0()) + } + + pub fn is_intersecting(&self, l: &Line) -> Option> { + // Les lignes sont parallèles + if self.slope == l.slope { + // Les lignes sont identiques, retourner le point d'origine + if self.origin == l.origin { + Some(self.origin()) + } else { + // Pas d'intersection + None + } + } else { + let x: T; + let y: T; + + if self.is_vertical() { + x = self.origin; + y = l.y(x); + } else if l.is_vertical() { + x = l.origin; + y = self.y(x); + } else { + let slope_diff: T = T::from(l.slope - self.slope); + x = (self.origin - l.origin) / slope_diff; + y = self.y(x); + } + + Some(Point::new(x, y)) + } + } +} + diff --git a/LittleBigMouse-Hook-Rust/src/main.rs b/LittleBigMouse-Hook-Rust/src/main.rs new file mode 100644 index 00000000..e069931d --- /dev/null +++ b/LittleBigMouse-Hook-Rust/src/main.rs @@ -0,0 +1,9 @@ +mod engine; +mod line; +mod point; +mod rect; +mod segment; + +fn main() { + println!("Hello, world!"); +} diff --git a/LittleBigMouse-Hook-Rust/src/point.rs b/LittleBigMouse-Hook-Rust/src/point.rs new file mode 100644 index 00000000..aeb8d711 --- /dev/null +++ b/LittleBigMouse-Hook-Rust/src/point.rs @@ -0,0 +1,85 @@ +use std::fmt; +use std::ops::{Add, Sub}; +use std::num::Bounded; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Point { + x: T, + y: T, +} + +impl Point { + pub fn new(x: T, y: T) -> Self { + Point { x, y } + } + + pub fn x(&self) -> &T { + &self.x + } + + pub fn y(&self) -> &T { + &self.y + } +} + +impl Default for Point +where + T: Default, +{ + fn default() -> Self { + Point { + x: T::default(), + y: T::default(), + } + } +} + +impl Add for Point +where + T: Add, +{ + type Output = Self; + + fn add(self, other: Self) -> Self { + Point { + x: self.x + other.x, + y: self.y + other.y, + } + } +} + +impl Sub for Point +where + T: Sub, +{ + type Output = Self; + + fn sub(self, other: Self) -> Self { + Point { + x: self.x - other.x, + y: self.y - other.y, + } + } +} + +impl Point +where + T: Ord + Bounded, +{ + pub fn empty() -> Self { + Point { + x: T::max_value(), + y: T::max_value(), + } + } + + pub fn is_empty(&self) -> bool { + !(self.x < T::max_value() || self.y < T::max_value()) + } +} + +impl fmt::Display for Point { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{},{}]", self.x, self.y) + } +} diff --git a/LittleBigMouse-Hook-Rust/src/rect.rs b/LittleBigMouse-Hook-Rust/src/rect.rs new file mode 100644 index 00000000..96199275 --- /dev/null +++ b/LittleBigMouse-Hook-Rust/src/rect.rs @@ -0,0 +1,139 @@ +use std::cmp::{min, max}; +use std::fmt; +use crate::line::Line; +use crate::point::Point; +use crate::segment::Segment; + +pub struct Rect { + left: T, + top: T, + width: T, + height: T, +} + +impl Rect +where + T: Copy + PartialOrd + std::ops::Add, +{ + pub fn new(left: T, top: T, width: T, height: T) -> Self { + Self { + left, + top, + width, + height, + } + } + + pub fn from_points(p1: Point, p2: Point) -> Self { + Self { + left: min(p1.x(), p2.x()), + top: min(p1.y(), p2.y()), + width: max(p1.x(), p2.x()) - min(p1.x(), p2.x()), + height: max(p1.y(), p2.y()) - min(p1.y(), p2.y()), + } + } + + pub fn empty() -> Self + where + T: Default, + { + Self::new(T::default(), T::default(), T::default(), T::default()) + } + + pub fn left(&self) -> T { + self.left + } + + pub fn top(&self) -> T { + self.top + } + + pub fn width(&self) -> T { + self.width + } + + pub fn height(&self) -> T { + self.height + } + + pub fn right(&self) -> T { + self.left + self.width + } + + pub fn bottom(&self) -> T { + self.top + self.height + } + + pub fn top_left(&self) -> Point { + Point::new(self.left(), self.top()) + } + + pub fn top_right(&self) -> Point { + Point::new(self.right(), self.top()) + } + + pub fn bottom_left(&self) -> Point { + Point::new(self.left(), self.bottom()) + } + + pub fn bottom_right(&self) -> Point { + Point::new(self.right(), self.bottom()) + } + + pub fn is_empty(&self) -> bool + where + T: PartialEq + Default, + { + self.width == T::default() || self.height == T::default() + } + + pub fn contains(&self, point: &Point) -> bool { + point.x() >= self.left + && (point.x() - self.width) < self.left + && point.y() >= self.top + && (point.y() - self.height) < self.top + } + + pub fn intersect(&self, line: &Line) -> Vec> + where + T: Clone, + { + let mut result = Vec::new(); + let mut p = Point::default(); + + if Segment::new(self.top_left(), self.bottom_left()).is_intersecting(line, &mut p) { + result.push(p.clone()); + } + if Segment::new(self.top_left(), self.top_right()).is_intersecting(line, &mut p) { + result.push(p.clone()); + } + if Segment::new(self.top_right(), self.bottom_right()).is_intersecting(line, &mut p) { + result.push(p.clone()); + } + if Segment::new(self.bottom_left(), self.bottom_right()).is_intersecting(line, &mut p) { + result.push(p.clone()); + } + result + } +} + +impl PartialEq for Rect { + fn eq(&self, other: &Self) -> bool { + self.left == other.left + && self.top == other.top + && self.width == other.width + && self.height == other.height + } +} + +impl fmt::Display for Rect { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "[{} {}, {}]", + self.top_left(), + self.width, + self.height + ) + } +} diff --git a/LittleBigMouse-Hook-Rust/src/segment.rs b/LittleBigMouse-Hook-Rust/src/segment.rs new file mode 100644 index 00000000..4a8e2b34 --- /dev/null +++ b/LittleBigMouse-Hook-Rust/src/segment.rs @@ -0,0 +1,127 @@ +use std::cmp::{min, max}; +use std::vec::Vec; +use crate::line::Line; +use crate::point::Point; + +#[derive(Clone)] +pub struct Segment { + a: Point, + b: Point +} + +impl Segment +where + T: Copy + std::ops::Sub + std::ops::Add + std::ops::Mul + + PartialOrd + From + Into +{ + pub fn new(a: Point, b: Point) -> Self { + Self { a, b } + } + + pub fn a(&self) -> Point { + self.a + } + + pub fn b(&self) -> Point { + self.b + } + + pub fn to_line(&self) -> Line { + if self.a.x() == self.b.x() { + return Line::vertical(self.a.x()); + } + + let slope = (self.a.y().into() - self.b.y().into()) / (self.a.x().into() - self.b.x().into()); + let origin = self.a.y().into() - slope * self.a.x().into(); + + Line::new(T::from(slope), T::from(origin)) + } + + pub fn size(&self) -> f64 { + (self.size_squared().into() as f64).sqrt() + } + + pub fn size_squared(&self) -> T { + let w = self.b.x() - self.a.x(); + let h = self.b.y() - self.a.y(); + w * w + h * h + } + + pub fn intersect(&self, line: &Line) -> Point { + const EPSILON: f64 = 0.001; + + if let Some(p) = self.to_line().intersect(line) { + if p.x().into() < (min(self.a.x(), self.b.x())).into() - EPSILON { return Point::empty(); } + if p.y().into() < (min(self.a.y(), self.b.y())).into() - EPSILON { return Point::empty(); } + if p.x().into() > (max(self.a.x(), self.b.x())).into() + EPSILON { return Point::empty(); } + if p.y().into() > (max(self.a.y(), self.b.y())).into() + EPSILON { return Point::empty(); } + p + } else { + Point::empty() + } + } + + fn is_outside(n: T, p1: T, p2: T) -> bool { + const EPSILON: f64 = 0.001; + let n_f: f64 = n.into(); + let p1_f: f64 = p1.into(); + let p2_f: f64 = p2.into(); + + if n_f < p1_f - EPSILON && n_f < p2_f - EPSILON { return true; } + if n_f > p1_f + EPSILON && n_f > p2_f + EPSILON { return true; } + false + } + + pub fn is_intersecting(&self, line: &Line) -> Option> { + self.to_line().intersect(line).and_then(|p| { + if Self::is_outside(p.x(), self.a.x(), self.b.x()) || + Self::is_outside(p.y(), self.a.y(), self.b.y()) { + None + } else { + Some(p) + } + }) + } + + pub fn intersect_list(&self, line: &Line) -> Vec> { + self.is_intersecting(line) + .map(|p| vec![p]) + .unwrap_or_default() + } + + pub fn intersect_segment(&self, other: &Segment) -> Point { + if let Some(p) = other.is_intersecting(&self.to_line()) { + const EPSILON: f64 = 0.001; + + if p.x().into() < (min(self.a.x(), self.b.x())).into() - EPSILON { return Point::empty(); } + if p.y().into() < (min(self.a.y(), self.b.y())).into() - EPSILON { return Point::empty(); } + if p.x().into() > (max(self.a.x(), self.b.x())).into() + EPSILON { return Point::empty(); } + if p.y().into() > (max(self.a.y(), self.b.y())).into() + EPSILON { return Point::empty(); } + p + } else { + Point::empty() + } + } +} + +impl std::ops::Add> for &Segment +where + T: Copy + std::ops::Add +{ + type Output = Segment; + + fn add(self, rhs: Point) -> Self::Output { + Segment::new(self.a + rhs, self.b + rhs) + } +} + +impl std::ops::Sub> for &Segment +where + T: Copy + std::ops::Sub +{ + type Output = Segment; + + fn sub(self, rhs: Point) -> Self::Output { + Segment::new(self.a - rhs, self.b - rhs) + } +} diff --git a/LittleBigMouse-Hook-Rust/target/.rustc_info.json b/LittleBigMouse-Hook-Rust/target/.rustc_info.json new file mode 100644 index 00000000..4f9eee38 --- /dev/null +++ b/LittleBigMouse-Hook-Rust/target/.rustc_info.json @@ -0,0 +1 @@ +{"rustc_fingerprint":3197475470732821073,"outputs":{"17313545009459141857":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\user\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\nfmt_debug=\"full\"\noverflow_checks\npanic=\"unwind\"\nproc_macro\nrelocation_model=\"pic\"\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"lahfsahf\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_feature=\"x87\"\ntarget_has_atomic\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_equal_alignment=\"128\"\ntarget_has_atomic_equal_alignment=\"16\"\ntarget_has_atomic_equal_alignment=\"32\"\ntarget_has_atomic_equal_alignment=\"64\"\ntarget_has_atomic_equal_alignment=\"8\"\ntarget_has_atomic_equal_alignment=\"ptr\"\ntarget_has_atomic_load_store\ntarget_has_atomic_load_store=\"128\"\ntarget_has_atomic_load_store=\"16\"\ntarget_has_atomic_load_store=\"32\"\ntarget_has_atomic_load_store=\"64\"\ntarget_has_atomic_load_store=\"8\"\ntarget_has_atomic_load_store=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_thread_local\ntarget_vendor=\"pc\"\nub_checks\nwindows\n","stderr":""},"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.85.1 (4eb161250 2025-03-15)\nbinary: rustc\ncommit-hash: 4eb161250e340c8f48f66e2b929ef4a5bed7c181\ncommit-date: 2025-03-15\nhost: x86_64-pc-windows-msvc\nrelease: 1.85.1\nLLVM version: 19.1.7\n","stderr":""}},"successes":{}} \ No newline at end of file diff --git a/LittleBigMouse-Hook-Rust/target/CACHEDIR.TAG b/LittleBigMouse-Hook-Rust/target/CACHEDIR.TAG new file mode 100644 index 00000000..20d7c319 --- /dev/null +++ b/LittleBigMouse-Hook-Rust/target/CACHEDIR.TAG @@ -0,0 +1,3 @@ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by cargo. +# For information about cache directory tags see https://bford.info/cachedir/ diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/BorderResistance.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/BorderResistance.cs new file mode 100644 index 00000000..e12e69f5 --- /dev/null +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/BorderResistance.cs @@ -0,0 +1,15 @@ +using HLab.Base.ReactiveUI; +using LittleBigMouse.Zoning; + +namespace LittleBigMouse.DisplayLayout.Dimensions; + +public class BorderResistance : SavableReactiveModel, IBorderResistance +{ + public double Left { get; set => SetUnsavedValue(ref field, value); } + + public double Top { get; set => SetUnsavedValue(ref field, value); } + + public double Right { get; set => SetUnsavedValue(ref field, value); } + + public double Bottom { get; set => SetUnsavedValue(ref field, value); } +} \ No newline at end of file diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayBorders.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayBorders.cs new file mode 100644 index 00000000..c8400681 --- /dev/null +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayBorders.cs @@ -0,0 +1,14 @@ +using ReactiveUI; + +namespace LittleBigMouse.DisplayLayout.Dimensions; + +public class DisplayBorders : ReactiveObject +{ + public double Left { get; set => this.RaiseAndSetIfChanged(ref field, value); } + + public double Top { get; set => this.RaiseAndSetIfChanged(ref field, value); } + + public double Right { get; set => this.RaiseAndSetIfChanged(ref field, value); } + + public double Bottom { get; set => this.RaiseAndSetIfChanged(ref field, value); } +} \ No newline at end of file diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayLocate.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayLocate.cs index ec4bdb02..7b042538 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayLocate.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayLocate.cs @@ -22,7 +22,7 @@ You should have received a copy of the GNU General Public License */ using System.Diagnostics; -using Avalonia; +using HLab.Geo; namespace LittleBigMouse.DisplayLayout.Dimensions; @@ -33,30 +33,18 @@ public DisplayLocate(IDisplaySize source, Point? point = null) : base(source) Location = point ?? new Point(); } - public override double X - { - get => _x; - set - { - Debug.Assert(!double.IsInfinity(value)); - this.SetUnsavedValue(ref _x, value); - } + public override double X { get; set { + Debug.Assert(!double.IsInfinity(value)); + SetUnsavedValue(ref field, value); + } } - double _x; - - public override double Y - { - get => _y; - set - { - Debug.Assert(!double.IsInfinity(value)); - this.SetUnsavedValue(ref _y, value); - } + public override double Y { get; set { + Debug.Assert(!double.IsInfinity(value)); + SetUnsavedValue(ref field, value); + } } - double _y; - public override string TransformToString => $"To:{X},{Y}"; } diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRatio.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRatio.cs index 69345e33..abafdc71 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRatio.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRatio.cs @@ -23,56 +23,13 @@ You should have received a copy of the GNU General Public License using System; using System.Runtime.Serialization; -using HLab.Base; using HLab.Base.ReactiveUI; -using LittleBigMouse.Zoning; namespace LittleBigMouse.DisplayLayout.Dimensions; - -public class BorderResistance : SavableReactiveModel, IBorderResistance -{ - public double Left - { - get => _left; - set => SetUnsavedValue(ref _left,value); - } - double _left; - - public double Top - { - get => _top; - set => SetUnsavedValue(ref _top,value); - } - double _top; - - public double Right - { - get => _right; - set => SetUnsavedValue(ref _right, value); - } - double _right; - - public double Bottom - { - get => _bottom; - set => SetUnsavedValue(ref _bottom, value); - } - double _bottom; -} - - -public interface IDisplayRatio : ISavable -{ - double X { get; set; } - double Y { get; set; } - bool IsUnary { get; } -} - [DataContract] public abstract class DisplayRatio : SavableReactiveModel, IDisplayRatio, IEquatable { - protected DisplayRatio() { } [DataMember] public abstract double X { get; set; } [DataMember] diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRatioExt.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRatioExt.cs index 8d1d7563..60454f0e 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRatioExt.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRatioExt.cs @@ -1,4 +1,4 @@ -using Avalonia; +using HLab.Geo; using LittleBigMouse.DisplayLayout.Monitors; namespace LittleBigMouse.DisplayLayout.Dimensions; diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRatioValue.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRatioValue.cs index e1735870..12b25866 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRatioValue.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRatioValue.cs @@ -1,15 +1,10 @@ -using Avalonia; +using HLab.Geo; namespace LittleBigMouse.DisplayLayout.Dimensions; -public class DisplayRatioValue : DisplayRatio +public class DisplayRatioValue(double x, double y) : DisplayRatio { - public DisplayRatioValue(double x, double y) - { - _x = x; - _y = y; - } - public DisplayRatioValue(double r):this(r,r) {} + public DisplayRatioValue(double r):this(r,r) {} public DisplayRatioValue(Vector v):this(v.X, v.Y) {} public DisplayRatioValue Set(double x, double y) @@ -29,14 +24,14 @@ public DisplayRatioValue Set(Vector v) public override double X { get => _x; - set => this.SetUnsavedValue(ref _x, value); + set => SetUnsavedValue(ref _x, value); } - double _x; + double _x = x; public override double Y { get => _y; - set => this.SetUnsavedValue(ref _y, value); + set => SetUnsavedValue(ref _y, value); } - double _y; + double _y = y; } diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRect.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRect.cs new file mode 100644 index 00000000..4d549119 --- /dev/null +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRect.cs @@ -0,0 +1,14 @@ +using ReactiveUI; + +namespace LittleBigMouse.DisplayLayout.Dimensions; + +public class DisplayRect : ReactiveObject +{ + public double X { get; set => this.RaiseAndSetIfChanged(ref field, value); } + + public double Y { get; set => this.RaiseAndSetIfChanged(ref field, value); } + + public double Width { get; set => this.RaiseAndSetIfChanged(ref field, value); } + + public double Height { get; set => this.RaiseAndSetIfChanged(ref field, value); } +} \ No newline at end of file diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRotate.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRotate.cs index 4c062898..5875c62a 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRotate.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayRotate.cs @@ -21,9 +21,9 @@ You should have received a copy of the GNU General Public License http://www.mgth.fr */ -using Avalonia; using ReactiveUI; using System.Reactive.Concurrency; +using HLab.Geo; namespace LittleBigMouse.DisplayLayout.Dimensions; @@ -112,15 +112,10 @@ public DisplayRotate(IDisplaySize source, int rotation = 0) : base(source) ) .ToProperty(this, e => e.LeftBorder, scheduler: Scheduler.Immediate); - base.Init(); + Init(); } - public Vector Translation - { - get => _translation; - set => this.RaiseAndSetIfChanged(ref _translation, value); - } - Vector _translation; + public Vector Translation { get; set => this.RaiseAndSetIfChanged(ref field, value); } public override double Width { @@ -157,23 +152,12 @@ public override double Height } } } + readonly ObservableAsPropertyHelper _height; - ObservableAsPropertyHelper _height; - - public override double X - { - get => _x.Value; - set => Source.X = value; - } - + public override double X { get => _x.Value; set => Source.X = value; } readonly ObservableAsPropertyHelper _x; - public override double Y - { - get => _y.Value; - set => Source.Y = value; - } - + public override double Y { get => _y.Value; set => Source.Y = value; } readonly ObservableAsPropertyHelper _y; static double GetBorder(int border, int rotation, double left, double top, double right, double bottom) @@ -210,38 +194,16 @@ void SetBorder(int border, double value) } } - - - public override double TopBorder - { - get => _topBorder.Value; - set => SetBorder(0, value); - } - + public override double TopBorder{ get => _topBorder.Value; set => SetBorder(0, value); } readonly ObservableAsPropertyHelper _topBorder; - public override double RightBorder - { - get => _rightBorder.Value; - set => SetBorder(1, value); - } - + public override double RightBorder { get => _rightBorder.Value; set => SetBorder(1, value); } readonly ObservableAsPropertyHelper _rightBorder; - public override double BottomBorder - { - get => _bottomBorder.Value; - set => SetBorder(2, value); - } - + public override double BottomBorder { get => _bottomBorder.Value; set => SetBorder(2, value); } readonly ObservableAsPropertyHelper _bottomBorder; - public override double LeftBorder - { - get => _leftBorder.Value; - set => SetBorder(3, value); - } - + public override double LeftBorder { get => _leftBorder.Value; set => SetBorder(3, value); } readonly ObservableAsPropertyHelper _leftBorder; public override string TransformToString => $"Rotate:{Rotation}"; diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySize.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySize.cs index 01e514c0..9cf16fe5 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySize.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySize.cs @@ -26,8 +26,8 @@ You should have received a copy of the GNU General Public License using System.Runtime.Serialization; using System.Text; using System.Text.Json.Serialization; -using Avalonia; using HLab.Base.ReactiveUI; +using HLab.Geo; using ReactiveUI; namespace LittleBigMouse.DisplayLayout.Dimensions; @@ -99,7 +99,8 @@ protected void Init() e => e.OutsideY, e => e.OutsideWidth, e => e.OutsideHeight, - (x,y,width,height) => new Rect(new Point(x, y), new Size(width, height))) + (x,y,width,height) => new Rect(x, y, width, height)) +// (x,y,width,height) => new Rect(new Point(x,y), new Size(width, height))) .Log(this).ToProperty(this, e => e.OutsideBounds, scheduler: Scheduler.Immediate); } diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeExtensions.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeExtensions.cs index e6ba75c7..0045a52a 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeExtensions.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeExtensions.cs @@ -1,5 +1,5 @@  -using Avalonia; +using HLab.Geo; namespace LittleBigMouse.DisplayLayout.Dimensions; @@ -12,7 +12,7 @@ public static Point GetPoint(this IDisplaySize sz, IDisplaySize source, Point po var x = (point.X - source.X) / source.Width; var y = (point.Y - source.Y) / source.Height; - return new Point(sz.X + x * sz.Width, sz.Y + y * sz.Height); + return new(sz.X + x * sz.Width, sz.Y + y * sz.Height); } public static Point Inside(this IDisplaySize sz, Point p) @@ -20,7 +20,7 @@ public static Point Inside(this IDisplaySize sz, Point p) var x = p.X < sz.X ? sz.X : p.X > sz.Bounds.Right - 1 ? sz.Bounds.Right - 1 : p.X; var y = p.Y < sz.Y ? sz.Y : p.Y > sz.Bounds.Bottom - 1 ? sz.Bounds.Bottom - 1 : p.Y; - return new Point(x, y); + return new(x, y); } public static T Set(this T @this, Size size) where T : IDisplaySize diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeInMm.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeInMm.cs index fd8cbcc1..0e41ff43 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeInMm.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeInMm.cs @@ -26,172 +26,64 @@ You should have received a copy of the GNU General Public License namespace LittleBigMouse.DisplayLayout.Dimensions; -public class DisplayRect : ReactiveObject +/// +/// Actual real monitor size +/// +public class DisplaySizeInMm : DisplaySize { - public double X - { - get => _x; - set => this.RaiseAndSetIfChanged(ref _x, value); - } - double _x; + public DisplaySizeInMm() : base(null) => Init(); - public double Y - { - get => _y; - set => this.RaiseAndSetIfChanged(ref _y, value); - } - double _y; - public double Width - { - get => _with; - set => this.RaiseAndSetIfChanged(ref _with, value); - } - double _with; + public bool FixedAspectRatio { get; set => this.RaiseAndSetIfChanged(ref field, value); } - public double Height - { - get => _height; - set => this.RaiseAndSetIfChanged(ref _height, value); - } - double _height; -} -public class DisplayBorders : ReactiveObject -{ - public double Left - { - get => _left; - set => this.RaiseAndSetIfChanged(ref _left, value); - } - double _left; + public override double Width { get; set { + using (DelayChangeNotifications()) + { + var newValue = Math.Max(value, 0); + var oldValue = field; - public double Top - { - get => _top; - set => this.RaiseAndSetIfChanged(ref _top, value); - } - double _top; - public double Right - { - get => _right; - set => this.RaiseAndSetIfChanged(ref _right, value); - } - double _right; + if (FixedAspectRatio) + { + var ratio = newValue / oldValue; + FixedAspectRatio = false; + Height *= ratio; + FixedAspectRatio = true; + } - public double Bottom - { - get => _bottom; - set => this.RaiseAndSetIfChanged(ref _bottom, value); + SetUnsavedValue(ref field, value); + } + } } - double _bottom; -} -/// -/// Actual real monitor size -/// -public class DisplaySizeInMm : DisplaySize -{ - public DisplaySizeInMm() : base(null) - { - Init(); - } + public override double Height { get; set { + using (DelayChangeNotifications()) + { + var newValue = Math.Max(value, 0); + var oldValue = field; - public bool FixedAspectRatio - { - get => _fixedAspectRatio; - set => this.RaiseAndSetIfChanged(ref _fixedAspectRatio, value); - } - bool _fixedAspectRatio;//PropertyBuilder.DefaultValue(true); - - public override double Width - { - get => _width; - - set - { - using (DelayChangeNotifications()) - { - var newValue = Math.Max(value, 0); - var oldValue = _width; - - if (FixedAspectRatio) - { - var ratio = newValue / oldValue; - FixedAspectRatio = false; - Height *= ratio; - FixedAspectRatio = true; - } - - this.SetUnsavedValue(ref _width, value); - } - } - } - double _width; - - public override double Height - { - get => _height; - set - { - using (DelayChangeNotifications()) - { - var newValue = Math.Max(value, 0); - var oldValue = _height; - - if (FixedAspectRatio) - { - var ratio = newValue / oldValue; - FixedAspectRatio = false; - Width *= ratio; - FixedAspectRatio = true; - } - - this.SetUnsavedValue(ref _height, value); - } - } - } - double _height; + if (FixedAspectRatio) + { + var ratio = newValue / oldValue; + FixedAspectRatio = false; + Width *= ratio; + FixedAspectRatio = true; + } - public override double X - { - get => _x; - set => this.RaiseAndSetIfChanged(ref _x, value); + SetUnsavedValue(ref field, value); + } + } } - double _x; - public override double Y - { - get => _y; - set => this.RaiseAndSetIfChanged(ref _y, value); - } - double _y; + public override double X { get; set => this.RaiseAndSetIfChanged(ref field, value); } - public override double TopBorder - { - get => _topBorder; - set => this.SetUnsavedValue(ref _topBorder, Math.Max(value, 0.0)); - } - double _topBorder = 20.0; + public override double Y { get; set => this.RaiseAndSetIfChanged(ref field, value); } - public override double RightBorder - { - get => _rightBorder; - set => this.SetUnsavedValue(ref _rightBorder, Math.Max(value, 0.0)); - } - double _rightBorder = 20.0; + public override double TopBorder { get; set => SetUnsavedValue(ref field, Math.Max(value, 0.0));} = 20.0; - public override double BottomBorder - { - get => _bottomBorder; - set => this.SetUnsavedValue(ref _bottomBorder, Math.Max(value, 0.0)); - } - double _bottomBorder = 20.0; + public override double RightBorder { get; set => SetUnsavedValue(ref field, Math.Max(value, 0.0)); } = 20.0; - public override double LeftBorder - { - get => _leftBorder; - set => this.SetUnsavedValue(ref _leftBorder, Math.Max(value, 0.0)); - } - double _leftBorder = 20.0; + public override double BottomBorder { get; set => this.SetUnsavedValue(ref field, Math.Max(value, 0.0)); } = 20.0; + + public override double LeftBorder { get; set => this.SetUnsavedValue(ref field, Math.Max(value, 0.0)); } = 20.0; public override string TransformToString => $"InMm"; diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeInPixel.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeInPixel.cs index 4ff3e253..f863ff70 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeInPixel.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeInPixel.cs @@ -22,67 +22,25 @@ You should have received a copy of the GNU General Public License */ using System; -using Avalonia; +using HLab.Geo; namespace LittleBigMouse.DisplayLayout.Dimensions; public class DisplaySizeInPixels : DisplaySize { - public DisplaySizeInPixels(Rect rect) : base(null) { Init(); this.Set(rect); } - public override double Width - { - get => _width; - set => this.SetUnsavedValue(ref _width, value); - } - double _width; - - - public override double Height - { - get => _height; - set => this.SetUnsavedValue(ref _height, value); - } - double _height; - - public override double X - { - get => _x; - set => this.SetUnsavedValue(ref _x, value); - } - double _x; - - public override double Y - { - get => _y; - set => this.SetUnsavedValue(ref _y, value); - } - double _y; - - public override double TopBorder - { - get => 0; - set => throw new NotImplementedException(); - } - public override double BottomBorder - { - get => 0; - set => throw new NotImplementedException(); - } - public override double LeftBorder - { - get => 0; - set => throw new NotImplementedException(); - } - public override double RightBorder - { - get => 0; - set => throw new NotImplementedException(); - } + public override double Width { get; set => SetUnsavedValue(ref field, value); } + public override double Height { get; set => SetUnsavedValue(ref field, value); } + public override double X { get; set => SetUnsavedValue(ref field, value); } + public override double Y { get; set => SetUnsavedValue(ref field, value); } + public override double TopBorder { get => 0; set => throw new NotImplementedException(); } + public override double BottomBorder { get => 0; set => throw new NotImplementedException(); } + public override double LeftBorder { get => 0; set => throw new NotImplementedException(); } + public override double RightBorder { get => 0; set => throw new NotImplementedException(); } } diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeWpf.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeWpf.cs index b167e8f4..b65ae0cc 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeWpf.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplaySizeWpf.cs @@ -36,10 +36,9 @@ public DisplaySizeWpf(IDisplaySize source) : base(source) public IDisplayRatio Ratio { - get => _ratio; - set => _ratio = value; + get; + set => field = value; } - IDisplayRatio _ratio; public override double Width { diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayTranslate.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayTranslate.cs index 5f1fd10c..1ba41949 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayTranslate.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/DisplayTranslate.cs @@ -21,9 +21,9 @@ You should have received a copy of the GNU General Public License http://www.mgth.fr */ -using Avalonia; using ReactiveUI; using System.Reactive.Concurrency; +using HLab.Geo; namespace LittleBigMouse.DisplayLayout.Dimensions; @@ -36,7 +36,7 @@ public class DisplayTranslate : DisplayMove { public DisplayTranslate(IDisplaySize source, Vector? translation = null) : base(source) { - _translation = translation ?? new Vector(); + Translation = translation ?? new Vector(); _x = this.WhenAnyValue(e => e.Source.X,e =>e.Translation, (x,t)=>x + t.X) .ToProperty(this, e => e.X, scheduler: Scheduler.Immediate); @@ -45,12 +45,7 @@ public DisplayTranslate(IDisplaySize source, Vector? translation = null) : base( .ToProperty(this, e => e.Y, scheduler: Scheduler.Immediate); } - public Vector Translation - { - get => _translation; - set => this.RaiseAndSetIfChanged(ref _translation, value); - } - Vector _translation; + public Vector Translation { get; set => this.RaiseAndSetIfChanged(ref field, value); } public override double X { @@ -67,5 +62,4 @@ public override double Y readonly ObservableAsPropertyHelper _y; public override string TransformToString => $"Translate:{Translation}"; - } diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/IDisplayRatio.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/IDisplayRatio.cs new file mode 100644 index 00000000..4ec69d37 --- /dev/null +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/IDisplayRatio.cs @@ -0,0 +1,10 @@ +using HLab.Base; + +namespace LittleBigMouse.DisplayLayout.Dimensions; + +public interface IDisplayRatio : ISavable +{ + double X { get; set; } + double Y { get; set; } + bool IsUnary { get; } +} \ No newline at end of file diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/IDisplaySize.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/IDisplaySize.cs index a7d06988..e44954e0 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/IDisplaySize.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Dimensions/IDisplaySize.cs @@ -1,7 +1,7 @@  using System; -using Avalonia; using HLab.Base; +using HLab.Geo; namespace LittleBigMouse.DisplayLayout.Dimensions; diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/LittleBigMouse.DisplayLayout.csproj b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/LittleBigMouse.DisplayLayout.csproj index 41fbfe3d..f1d92556 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/LittleBigMouse.DisplayLayout.csproj +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/LittleBigMouse.DisplayLayout.csproj @@ -1,24 +1,25 @@  - net8.0 - x64;x86;AnyCpu + net10.0 + preview + x64 Library Debug;Release;ReleaseDebug - 5.2.4.0 + 5.3.0.0 - - - - - + + + + - + + diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/DisplaySource.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/DisplaySource.cs index 307317c0..9f1e15db 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/DisplaySource.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/DisplaySource.cs @@ -1,8 +1,9 @@ -using LittleBigMouse.DisplayLayout.Dimensions; +using System.Drawing; +using LittleBigMouse.DisplayLayout.Dimensions; using System.Runtime.Serialization; -using Avalonia; -using Avalonia.Media; using HLab.Base.ReactiveUI; +using HLab.ColorTools; +using HLab.Geo; using ReactiveUI; namespace LittleBigMouse.DisplayLayout.Monitors; @@ -53,132 +54,73 @@ public DisplaySource(string id) /// Source is the primary display /// [DataMember] - public bool Primary - { - get => _primary; - set => this.RaiseAndSetIfChanged(ref _primary, value) ; - } - bool _primary; + public bool Primary { get; set => this.RaiseAndSetIfChanged(ref field, value); } /// /// Source Device Name /// [DataMember] - public string DeviceName - { - get => _deviceName; - set => this.RaiseAndSetIfChanged(ref _deviceName, value) ; - } - string _deviceName; + public string DeviceName { get; set => this.RaiseAndSetIfChanged(ref field, value); } /// /// Source Name /// [DataMember] - public string SourceName - { - get => _sourceName; - set => this.RaiseAndSetIfChanged(ref _sourceName, value) ; - } - string _sourceName; + public string SourceName { get; set => this.RaiseAndSetIfChanged(ref field, value); } /// /// Display Device Name /// [DataMember] - public string DisplayName - { - get => _displayName; - set => this.RaiseAndSetIfChanged(ref _displayName, value) ; - } - string _displayName; + public string DisplayName { get; set => this.RaiseAndSetIfChanged(ref field, value); } /// /// Source number in windows system /// [DataMember] - public string SourceNumber - { - get => _sourceNumber; - set => this.RaiseAndSetIfChanged(ref _sourceNumber, value) ; - } - string _sourceNumber; + public string SourceNumber { get; set => this.RaiseAndSetIfChanged(ref field, value); } /// /// Current monitor frequency /// [DataMember] - public int DisplayFrequency - { - get => _displayFrequency; - set => this.RaiseAndSetIfChanged(ref _displayFrequency, value) ; - } - int _displayFrequency; + public int DisplayFrequency { get; set => this.RaiseAndSetIfChanged(ref field, value); } /// /// Display size in pixel /// [DataMember] - public DisplaySizeInPixels InPixel { get; } = new(new Rect()); + public DisplaySizeInPixels InPixel { get; } = new(new ()); /// /// Monitor orientation (0=0°, 1=90°, 2=180°, 3=270°) /// [DataMember] - public int Orientation - { - get => _orientation; - set => this.SetUnsavedValue(ref _orientation, value); - } - int _orientation; + public int Orientation { get; set => SetUnsavedValue(ref field, value); } [DataMember] - public string WallpaperPath { - get => _wallpaperPath; - set => this.RaiseAndSetIfChanged(ref _wallpaperPath, value); + public string WallpaperPath + { + get; + set => this.RaiseAndSetIfChanged(ref field, value); } - string _wallpaperPath; [DataMember] - public WallpaperStyle WallpaperStyle - { - get => _wallpaperStyle; - set => this.RaiseAndSetIfChanged(ref _wallpaperStyle, value); - } - WallpaperStyle _wallpaperStyle; + public WallpaperStyle WallpaperStyle { get; set => this.RaiseAndSetIfChanged(ref field, value); } [DataMember] - public Color BackgroundColor { - get => _backgroundColor; - set => this.RaiseAndSetIfChanged(ref _backgroundColor, value); - } - Color _backgroundColor; + public ColorRGB BackgroundColor { get; set => this.RaiseAndSetIfChanged(ref field, value); } [DataMember] - public string InterfaceName - { - get => _interfaceName; - set => this.RaiseAndSetIfChanged(ref _interfaceName, value); - } - string _interfaceName; + public string InterfaceName { get; set => this.RaiseAndSetIfChanged(ref field, value); } [DataMember] - public string InterfaceLogo - { - get => _interfaceLogo; - set => this.RaiseAndSetIfChanged(ref _interfaceLogo, value); - } - string _interfaceLogo; + public string InterfaceLogo { get; set => this.RaiseAndSetIfChanged(ref field, value); } [DataMember] - public bool AttachedToDesktop - { - get => _attachedToDesktop; - set => this.RaiseAndSetIfChanged(ref _attachedToDesktop, value); - } - bool _attachedToDesktop; + public bool AttachedToDesktop { get; set => this.RaiseAndSetIfChanged(ref field, value); } [DataMember] public double WinDpiX => _winDpiX.Value; diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/Extensions/ZonesLayoutFactory.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/Extensions/ZonesLayoutFactory.cs index f9472721..d8cf5a91 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/Extensions/ZonesLayoutFactory.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/Extensions/ZonesLayoutFactory.cs @@ -1,5 +1,5 @@ -using LittleBigMouse.Zoning; -using Avalonia; +using HLab.Geo; +using LittleBigMouse.Zoning; namespace LittleBigMouse.DisplayLayout.Monitors.Extensions; diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/IMonitorsLayout.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/IMonitorsLayout.cs index d5650096..dcd9fbe9 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/IMonitorsLayout.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/IMonitorsLayout.cs @@ -1,7 +1,7 @@ -using Avalonia; -using HLab.Sys.Windows.API; +using HLab.Sys.Windows.API; using System; using System.Collections.ObjectModel; +using HLab.Geo; namespace LittleBigMouse.DisplayLayout.Monitors; diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/MonitorExtentions.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/MonitorExtentions.cs index b5bab347..2a4e1c3b 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/MonitorExtentions.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/MonitorExtentions.cs @@ -1,7 +1,7 @@ -using Avalonia; -using System; +using System; using System.Collections.Generic; using System.Linq; +using HLab.Geo; namespace LittleBigMouse.DisplayLayout.Monitors; diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/MonitorsLayout.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/MonitorsLayout.cs index a5de4642..d3ee2fda 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/MonitorsLayout.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/MonitorsLayout.cs @@ -9,11 +9,11 @@ using System.Runtime.Serialization; using System.Text.Json.Serialization; using System.Text.RegularExpressions; -using Avalonia; -using Avalonia.Controls; +using System.Threading; using DynamicData; using DynamicData.Binding; using HLab.Base.ReactiveUI; +using HLab.Geo; using HLab.Sys.Windows.API; using LittleBigMouse.DisplayLayout.Monitors.Extensions; using Microsoft.Win32.TaskScheduler; @@ -27,427 +27,378 @@ namespace LittleBigMouse.DisplayLayout.Monitors; [DataContract] public class MonitorsLayout : SavableReactiveModel, IMonitorsLayout { - public MonitorsLayout(ILayoutOptions options) - { - Options = options; - - DpiAwareness = WinUser.GetAwarenessFromDpiAwarenessContext(WinUser.GetThreadDpiAwarenessContext()); - - _physicalMonitorsCache.Connect() - .StartWithEmpty() - .Bind(out _physicalMonitors) - .Subscribe().DisposeWith(this); - - _physicalSourcesCache.Connect() - .Sort(SortExpressionComparer.Ascending(t => t.DeviceId)) - .Bind(out _physicalSources) - .Subscribe().DisposeWith(this); - - _physicalMonitorsCache.Connect() - //.AutoRefresh(e => e.DepthProjection.Bounds) - .ToCollection() - .Do(ParsePhysicalMonitors) - .Subscribe().DisposeWith(this); - - _physicalSourcesCache.Connect() - .AutoRefresh(e => e.Source.EffectiveDpi.Y) - .AutoRefresh(e => e.Source.EffectiveDpi.Y) - .AutoRefresh(e => e.PixelToDipRatio) - .ToCollection() - .Do(ParseDisplaySources) - .Subscribe().DisposeWith(this); - - _x0 = this - .WhenAnyValue(e => e.PhysicalBounds.Left, left => -left) - .Log(this, "X0").ToProperty(this, e => e.X0) - .DisposeWith(this); - - _y0 = this - .WhenAnyValue(e => e.PhysicalBounds.Top, top => -top) - .Log(this, "Y0") - .ToProperty(this, e => e.Y0) - .DisposeWith(this); - - //if any physical monitor unsaved set layout not saved - _physicalMonitorsCache.Connect() - .AutoRefresh(e => e.Saved) - .ToCollection() - .Do(e => - { - if(e.All(m => m.Saved)) return; - Saved = false; - }) - .Subscribe().DisposeWith(this); - - //if any physical source unsaved set layout not saved - _physicalSourcesCache.Connect() - .AutoRefresh(e => e.Saved) - .ToCollection() - .Do(e => - { - if(e.All(m => m.Saved)) return; - Saved = false; - }) - .Subscribe().DisposeWith(this); - - this.WhenAnyValue(e => e.Options.Saved).Where(e => !e).Do(e => Saved = false).Subscribe().DisposeWith(this); - } - - public ILayoutOptions Options { get; } - - Rect GetOutsideBounds() - { - using var enumerator = PhysicalMonitors.GetEnumerator(); - - if (!enumerator.MoveNext()) return default; - - var r = enumerator.Current!.DepthProjection.OutsideBounds; - while (enumerator.MoveNext()) - { - r = r.Union(enumerator.Current.DepthProjection.OutsideBounds); - } - return r; - } - - public WinDef.DpiAwareness DpiAwareness { get; } - - [DataMember] - public string Id - { - get => _id; - set => this.RaiseAndSetIfChanged(ref _id, value); - } - string _id = ""; - - /// - /// a list of string representing each known config in registry - /// - //public static IEnumerable LayoutsList - //{ - // get - // { - // using var rootKey = MonitorsLayoutExtensions.OpenRootRegKey(); - // using var key = rootKey?.OpenSubKey("Layouts"); - // if (key == null) return new List(); - // return key?.GetSubKeyNames(); - // } - //} - - [JsonIgnore] - readonly SourceCache _physicalMonitorModelsCache = new(m => m.PnpCode); - public PhysicalMonitorModel GetOrAddPhysicalMonitorModel(string id, Func value) - { - PhysicalMonitorModel? result = null; - _physicalMonitorModelsCache.Lookup(id); - _physicalMonitorModelsCache.Edit(u => - { - var lookup = u.Lookup(id); - if (lookup.HasValue) - { - result = lookup.Value; - } - result = value(id); - u.AddOrUpdate(result); - }); - if (result==null) throw new Exception("GetOrAddPhysicalMonitorModel failed"); - return result; - } - - public ReadOnlyObservableCollection PhysicalMonitors => _physicalMonitors; - readonly ReadOnlyObservableCollection _physicalMonitors; - readonly SourceCache _physicalMonitorsCache = new(m => m.Id); - public void AddOrUpdatePhysicalMonitor(PhysicalMonitor monitor) - { - _physicalMonitorsCache.AddOrUpdate(monitor); - } - - [JsonIgnore] - public ReadOnlyObservableCollection PhysicalSources => _physicalSources; - readonly ReadOnlyObservableCollection _physicalSources; - readonly SourceCache _physicalSourcesCache = new(s => s.Source.Id); - public void AddOrUpdatePhysicalSource(PhysicalSource source) - { - _physicalSourcesCache.AddOrUpdate(source); - } - - /// - /// Selected physical monitor - /// - public PhysicalMonitor? Selected - { - get => _selected; - set => this.RaiseAndSetIfChanged(ref _selected, value); - } - PhysicalMonitor? _selected; - - - - public string LayoutPath(bool create) => Options.GetConfigPath(Id, create); - - public void EnumWmi() - { - const string namespacePath = "\\\\.\\ROOT\\WMI\\ms_409"; - const string className = "WmiMonitorID"; - - //Create ManagementClass - var oClass = new ManagementClass(namespacePath + ":" + className); - - //Get all instances of the class and enumerate them - foreach (var o in oClass.GetInstances().OfType()) - { - //access a property of the Management object - Console.WriteLine("ManufacturerName : {0}", o["ManufacturerName"]); - } - } - - /// - /// PhysicalMonitor on witch primary source get displayed. - /// - [JsonIgnore] - public PhysicalMonitor? PrimaryMonitor - { - get => _primaryMonitor; - private set => this.RaiseAndSetIfChanged(ref _primaryMonitor, value); - } - PhysicalMonitor? _primaryMonitor; - - /// - /// Source for primary display (always located at 0,0). - /// - [DataMember] - public DisplaySource? PrimarySource - { - get => _primarySource; - private set => this.RaiseAndSetIfChanged(ref _primarySource, value); - } - DisplaySource? _primarySource; - - /// - /// Mm Bounds of overall screens without borders - /// - [DataMember] - public Rect PhysicalBounds - { - get => _physicalBounds; - set => this.RaiseAndSetIfChanged(ref _physicalBounds, value); - } - Rect _physicalBounds; - - public void UpdatePhysicalMonitors() => ParsePhysicalMonitors(PhysicalMonitors); - - void ParsePhysicalMonitors(IEnumerable monitors) - { - Rect? physicalBounds = null; - foreach (var m in monitors) - { - if (m.DepthProjection != null) - { - physicalBounds = physicalBounds?.Union(m.DepthProjection.OutsideBounds) ?? m.DepthProjection.OutsideBounds; - } - } - - Options.MinimalMaxTravelDistance = Math.Ceiling(this.GetMinimalMaxTravelDistance()); - - using (DelayChangeNotifications()) - { - PhysicalBounds = physicalBounds ?? new Rect(); - } - } - - public double X0 => _x0.Value; - - readonly ObservableAsPropertyHelper _x0; - - /// - /// - /// - public double Y0 => _y0.Value; - readonly ObservableAsPropertyHelper _y0; - - - - /// - /// Store window location betwin sessions - /// - [DataMember] - public Rect ConfigLocation - { - get => _configLocation; - set => SetUnsavedValue(ref _configLocation, value); - } - Rect _configLocation; - - - readonly object _compactLock = new object(); - - public void Compact() - { - if(Options.AllowDiscontinuity) return; - lock (_compactLock) - { - ForceCompact(); - } - } - - /// - /// Remove all gaps between screens - /// - public void ForceCompact() - { - // we cannot compact until primary monitor is placed - if (PrimaryMonitor == null) return; - - // Primary monitor is always at 0,0 - List done = [PrimaryMonitor]; - - // Enqueue all other monitors to be placed - var todo = this - .PhysicalMonitors.Except(done) - .OrderBy(monitor => monitor - .DepthProjection.OutsideBounds.DistanceToTouch(PrimaryMonitor.DepthProjection.OutsideBounds) - .DistanceHV() - ).ToList(); - - while (todo.Any()) - { - var monitor = todo.First(); - - monitor.PlaceAuto(done,Options.AllowDiscontinuity,Options.AllowOverlaps); - done.Add(monitor); - - todo = [.. todo.Except([monitor]).OrderBy(s => s + public MonitorsLayout(ILayoutOptions options) + { + Options = options; + + DpiAwareness = WinUser.GetAwarenessFromDpiAwarenessContext(WinUser.GetThreadDpiAwarenessContext()); + + _physicalMonitorsCache.Connect() + .StartWithEmpty() + .Bind(out _physicalMonitors) + .Subscribe().DisposeWith(this); + + _physicalSourcesCache.Connect() + .Sort(SortExpressionComparer.Ascending(t => t.DeviceId)) + .Bind(out _physicalSources) + .Subscribe().DisposeWith(this); + + _physicalMonitorsCache.Connect() + .AutoRefresh(e => e.DepthProjection.OutsideBounds) + .ToCollection() + .Do(ParsePhysicalMonitors) + .Subscribe().DisposeWith(this); + + _physicalSourcesCache.Connect() + .AutoRefresh(e => e.Source.EffectiveDpi.X) + .AutoRefresh(e => e.Source.EffectiveDpi.Y) + .AutoRefresh(e => e.PixelToDipRatio) + .ToCollection() + .Do(ParseDisplaySources) + .Subscribe().DisposeWith(this); + + _x0 = this + .WhenAnyValue(e => e.PhysicalBounds.Left, left => -left) + .Log(this, "X0").ToProperty(this, e => e.X0) + .DisposeWith(this); + + _y0 = this + .WhenAnyValue(e => e.PhysicalBounds.Top, top => -top) + .Log(this, "Y0") + .ToProperty(this, e => e.Y0) + .DisposeWith(this); + + //if any physical monitor unsaved set layout not saved + _physicalMonitorsCache.Connect() + .AutoRefresh(e => e.Saved) + .ToCollection() + .Do(e => + { + if (e.All(m => m.Saved)) return; + Saved = false; + }) + .Subscribe().DisposeWith(this); + + //if any physical source unsaved set layout not saved + _physicalSourcesCache.Connect() + .AutoRefresh(e => e.Saved) + .ToCollection() + .Do(e => + { + if (e.All(m => m.Saved)) return; + Saved = false; + }) + .Subscribe().DisposeWith(this); + + this.WhenAnyValue(e => e.Options.Saved).Where(e => !e).Do(e => Saved = false).Subscribe().DisposeWith(this); + } + + public ILayoutOptions Options { get; } + + + public WinDef.DpiAwareness DpiAwareness { get; } + + [DataMember] + public string Id + { + get; + set => this.RaiseAndSetIfChanged(ref field, value); + } = ""; + + /// + /// a list of string representing each known config in registry + /// + //public static IEnumerable LayoutsList + //{ + // get + // { + // using var rootKey = MonitorsLayoutExtensions.OpenRootRegKey(); + // using var key = rootKey?.OpenSubKey("Layouts"); + // if (key == null) return new List(); + // return key?.GetSubKeyNames(); + // } + //} + + [JsonIgnore] + readonly SourceCache _physicalMonitorModelsCache = new(m => m.PnpCode); + public PhysicalMonitorModel GetOrAddPhysicalMonitorModel(string id, Func value) + { + PhysicalMonitorModel? result = null; + _physicalMonitorModelsCache.Lookup(id); + _physicalMonitorModelsCache.Edit(u => + { + var lookup = u.Lookup(id); + if (lookup.HasValue) + { + result = lookup.Value; + } + result = value(id); + u.AddOrUpdate(result); + }); + if (result == null) throw new Exception("GetOrAddPhysicalMonitorModel failed"); + return result; + } + + public ReadOnlyObservableCollection PhysicalMonitors => _physicalMonitors; + readonly ReadOnlyObservableCollection _physicalMonitors; + readonly SourceCache _physicalMonitorsCache = new(m => m.Id); + public void AddOrUpdatePhysicalMonitor(PhysicalMonitor monitor) + { + _physicalMonitorsCache.AddOrUpdate(monitor); + } + + [JsonIgnore] + public ReadOnlyObservableCollection PhysicalSources => _physicalSources; + readonly ReadOnlyObservableCollection _physicalSources; + readonly SourceCache _physicalSourcesCache = new(s => s.Source.Id); + public void AddOrUpdatePhysicalSource(PhysicalSource source) + { + _physicalSourcesCache.AddOrUpdate(source); + } + + /// + /// Selected physical monitor + /// + public PhysicalMonitor? Selected + { + get; + set => this.RaiseAndSetIfChanged(ref field, value); + } + + + public string LayoutPath(bool create) => Options.GetConfigPath(Id, create); + + public void EnumWmi() + { + const string namespacePath = "\\\\.\\ROOT\\WMI\\ms_409"; + const string className = "WmiMonitorID"; + + //Create ManagementClass + var oClass = new ManagementClass(namespacePath + ":" + className); + + //Get all instances of the class and enumerate them + foreach (var o in oClass.GetInstances().OfType()) + { + //access a property of the Management object + Console.WriteLine("ManufacturerName : {0}", o["ManufacturerName"]); + } + } + + /// + /// PhysicalMonitor on witch primary source get displayed. + /// + [JsonIgnore] + public PhysicalMonitor? PrimaryMonitor + { + get; + private set => this.RaiseAndSetIfChanged(ref field, value); + } + + /// + /// Source for primary display (always located at 0,0). + /// + [DataMember] + public DisplaySource? PrimarySource { get; private set => this.RaiseAndSetIfChanged(ref field, value); } + + /// + /// Mm Bounds of overall screens without borders + /// + [DataMember] + public Rect PhysicalBounds { get; set => this.RaiseAndSetIfChanged(ref field, value); } + + public void UpdatePhysicalMonitors() => ParsePhysicalMonitors(PhysicalMonitors); + + void ParsePhysicalMonitors(IEnumerable monitors) + { + Options.MinimalMaxTravelDistance = Math.Ceiling(this.GetMinimalMaxTravelDistance()); + + using var it = monitors.GetEnumerator(); + if(!it.MoveNext()) return; + var physicalBounds = it.Current.DepthProjection.OutsideBounds; + while (it.MoveNext()) + { + physicalBounds = physicalBounds.Union(it.Current.DepthProjection.OutsideBounds); + } + + PhysicalBounds = physicalBounds; + } + + public double X0 => _x0.Value; + readonly ObservableAsPropertyHelper _x0; + + /// + /// + /// + public double Y0 => _y0.Value; + readonly ObservableAsPropertyHelper _y0; + + + /// + /// Store window location betwin sessions + /// + [DataMember] + public Rect ConfigLocation { get; set => SetUnsavedValue(ref field, value); } + + readonly Lock _compactLock = new(); + + public void Compact() + { + if (Options.AllowDiscontinuity) return; + lock (_compactLock) + { + ForceCompact(); + } + } + + /// + /// Remove all gaps between screens + /// + public void ForceCompact() + { + // we cannot compact until primary monitor is placed + if (PrimaryMonitor == null) return; + + // Primary monitor is always at 0,0 + List done = [PrimaryMonitor]; + + // Enqueue all other monitors to be placed + var todo = this + .PhysicalMonitors.Except(done) + .OrderBy(monitor => monitor + .DepthProjection.OutsideBounds.DistanceToTouch(PrimaryMonitor.DepthProjection.OutsideBounds) + .DistanceHV() + ).ToList(); + + while (todo.Any()) + { + var monitor = todo.First(); + + monitor.PlaceAuto(done, Options.AllowDiscontinuity, Options.AllowOverlaps); + done.Add(monitor); + + todo = [.. todo.Except([monitor]).OrderBy(s => s .DepthProjection.OutsideBounds.DistanceToTouch(done.Select(m => m.DepthProjection.OutsideBounds) ) .DistanceHV() )]; - } - } - - /// - /// Maximum effective Horizontal DPI of all screens - /// - [DataMember] - public double MaxEffectiveDpiX - { - get => _maxEffectiveDpiX; - private set => this.RaiseAndSetIfChanged(ref _maxEffectiveDpiX, value); - } - double _maxEffectiveDpiX; - - /// - /// Maximum effective Vertical DPI of all screens - /// - [DataMember] - public double MaxEffectiveDpiY - { - get => _maxEffectiveDpiY; - private set => this.RaiseAndSetIfChanged(ref _maxEffectiveDpiY, value); - } - double _maxEffectiveDpiY; - - void ParseDisplaySources(IEnumerable sources) - { - double maxEffectiveDpiX = 0; - double maxEffectiveDpiY = 0; - var isUnaryRatio = true; - PhysicalSource? primarySource = null; - - using (SuppressChangeNotifications()) - { - foreach (var source in sources) + } + } + + /// + /// Maximum effective Horizontal DPI of all screens + /// + [DataMember] + public double MaxEffectiveDpiX { get; private set => this.RaiseAndSetIfChanged(ref field, value); } + + /// + /// Maximum effective Vertical DPI of all screens + /// + [DataMember] + public double MaxEffectiveDpiY { get; private set => this.RaiseAndSetIfChanged(ref field, value); } + + void ParseDisplaySources(IEnumerable sources) + { + double maxEffectiveDpiX = 0; + double maxEffectiveDpiY = 0; + var isUnaryRatio = true; + PhysicalSource? primarySource = null; + + using (SuppressChangeNotifications()) + { + foreach (var source in sources) + { + if (source.Source.Primary) { primarySource = source; } + if (source.Source.EffectiveDpi is not null) { - if (source.Source.Primary) { primarySource = source; } - if (source.Source.EffectiveDpi is not null) - { - maxEffectiveDpiX = Math.Max(maxEffectiveDpiX, source.Source.EffectiveDpi.X); - maxEffectiveDpiY = Math.Max(maxEffectiveDpiY, source.Source.EffectiveDpi.Y); - } - if (isUnaryRatio && source.PixelToDipRatio is { IsUnary: false }) isUnaryRatio = false; - if (!source.Saved) Saved = false; + maxEffectiveDpiX = Math.Max(maxEffectiveDpiX, source.Source.EffectiveDpi.X); + maxEffectiveDpiY = Math.Max(maxEffectiveDpiY, source.Source.EffectiveDpi.Y); } - - PrimaryMonitor = primarySource?.Monitor; - PrimarySource = primarySource?.Source; - MaxEffectiveDpiX = maxEffectiveDpiX; - MaxEffectiveDpiY = maxEffectiveDpiY; - Options.IsUnaryRatio = isUnaryRatio; - } - } - - string ServiceName { get; } = "LittleBigMouse_" + System.Security.Principal.WindowsIdentity.GetCurrent().Name.Replace('\\', '_'); - - string ApplicationExe { get; } = AppDomain.CurrentDomain.BaseDirectory + AppDomain.CurrentDomain.FriendlyName + ".exe"; - - public static MonitorsLayout MonitorsLayoutDesign - { - get - { - if(!Design.IsDesignMode) throw new InvalidOperationException("Only for design mode"); - return new MonitorsLayout(null); - } - } - - public bool IsScheduled() - { - using var ts = new TaskService(); - return ts.RootFolder.GetTasks(new Regex(ServiceName)).Any(); - } - - public bool Schedule(bool elevated) - { - Unschedule(); - - using var ts = new TaskService(); - - //ts.RootFolder.DeleteTask(ServiceName, false); - - var td = ts.NewTask(); - td.RegistrationInfo.Description = "Multi-dpi aware monitors mouse crossover"; - td.Triggers.Add( - //new BootTrigger()); - new LogonTrigger { UserId = System.Security.Principal.WindowsIdentity.GetCurrent().Name }); - - td.Actions.Add( - new ExecAction(ApplicationExe, "", AppDomain.CurrentDomain.BaseDirectory) - ); - - td.Principal.RunLevel = TaskRunLevel.Highest; - td.Settings.DisallowStartIfOnBatteries = false; - td.Settings.DisallowStartOnRemoteAppSession = true; - td.Settings.StopIfGoingOnBatteries = false; - td.Settings.ExecutionTimeLimit = TimeSpan.Zero; - try - { - ts.RootFolder.RegisterTaskDefinition(ServiceName, td); - return true; - } - catch (UnauthorizedAccessException e) - { - } - - td.Principal.RunLevel = elevated ? TaskRunLevel.Highest : TaskRunLevel.LUA; - try - { - ts.RootFolder.RegisterTaskDefinition(ServiceName, td); - return true; - } - catch (UnauthorizedAccessException e) - { - return false; - } - } - - public void Unschedule() - { - using var ts = new TaskService(); - try - { - ts.RootFolder.DeleteTask(ServiceName, false); - } - catch(UnauthorizedAccessException) - { - - } - } + if (isUnaryRatio && source.PixelToDipRatio is { IsUnary: false }) isUnaryRatio = false; + if (!source.Saved) Saved = false; + } + + PrimaryMonitor = primarySource?.Monitor; + PrimarySource = primarySource?.Source; + MaxEffectiveDpiX = maxEffectiveDpiX; + MaxEffectiveDpiY = maxEffectiveDpiY; + Options.IsUnaryRatio = isUnaryRatio; + } + } + + string ServiceName { get; } = "LittleBigMouse_" + System.Security.Principal.WindowsIdentity.GetCurrent().Name.Replace('\\', '_'); + + string ApplicationExe { get; } = AppDomain.CurrentDomain.BaseDirectory + AppDomain.CurrentDomain.FriendlyName + ".exe"; + + public static MonitorsLayout MonitorsLayoutDesign + { + get + { + // if(!Design.IsDesignMode) throw new InvalidOperationException("Only for design mode"); + return new MonitorsLayout(null); + } + } + + public bool IsScheduled() + { + using var ts = new TaskService(); + return ts.RootFolder.GetTasks(new Regex(ServiceName)).Any(); + } + + public bool Schedule(bool elevated) + { + Unschedule(); + + using var ts = new TaskService(); + + //ts.RootFolder.DeleteTask(ServiceName, false); + + var td = ts.NewTask(); + td.RegistrationInfo.Description = "Multi-dpi aware monitors mouse crossover"; + td.Triggers.Add( + //new BootTrigger()); + new LogonTrigger { UserId = System.Security.Principal.WindowsIdentity.GetCurrent().Name }); + + td.Actions.Add( + new ExecAction(ApplicationExe, "", AppDomain.CurrentDomain.BaseDirectory) + ); + + td.Principal.RunLevel = TaskRunLevel.Highest; + td.Settings.DisallowStartIfOnBatteries = false; + td.Settings.DisallowStartOnRemoteAppSession = true; + td.Settings.StopIfGoingOnBatteries = false; + td.Settings.ExecutionTimeLimit = TimeSpan.Zero; + try + { + ts.RootFolder.RegisterTaskDefinition(ServiceName, td); + return true; + } + catch (UnauthorizedAccessException e) + { + } + + td.Principal.RunLevel = elevated ? TaskRunLevel.Highest : TaskRunLevel.LUA; + try + { + ts.RootFolder.RegisterTaskDefinition(ServiceName, td); + return true; + } + catch (UnauthorizedAccessException e) + { + return false; + } + } + + public void Unschedule() + { + using var ts = new TaskService(); + try + { + ts.RootFolder.DeleteTask(ServiceName, false); + } + catch (UnauthorizedAccessException) + { + + } + } diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/PhysicalMonitor.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/PhysicalMonitor.cs index 9ef8dc35..c282cb30 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/PhysicalMonitor.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/PhysicalMonitor.cs @@ -45,7 +45,7 @@ public class Design : PhysicalMonitor { public Design() : base("PNP0000", MonitorsLayout.MonitorsLayoutDesign, PhysicalMonitorModel.Design) { - if(!Avalonia.Controls.Design.IsDesignMode) throw new InvalidOperationException("Only for design mode"); + //if(!Avalonia.Controls.Design.IsDesignMode) throw new InvalidOperationException("Only for design mode"); } } @@ -63,18 +63,16 @@ public Design() : base("PNP0000", MonitorsLayout.MonitorsLayoutDesign, PhysicalM /// public PhysicalSource ActiveSource { - get => _activeSource; - set => SetUnsavedValue(ref _activeSource, value); + get; + set => SetUnsavedValue(ref field, value); } - PhysicalSource _activeSource; - [DataMember] - public string DeviceId + [DataMember] + public string DeviceId { - get => _deviceId; - set => SetUnsavedValue(ref _deviceId, value); + get; + set => SetUnsavedValue(ref field, value); } - string _deviceId; public PhysicalMonitor(string id, IMonitorsLayout layout, PhysicalMonitorModel model) { @@ -151,10 +149,9 @@ void ParseDisplaySources(IReadOnlyCollection obj) [DataMember] public bool SplitSources { - get => _splitSources; - set => this.SetUnsavedValue(ref _splitSources, value); + get; + set => this.SetUnsavedValue(ref field, value); } - bool _splitSources; /// /// Serial number from EDID @@ -162,20 +159,18 @@ public bool SplitSources [DataMember] public string SerialNumber { - get => _serialNumber; - set => this.SetUnsavedValue(ref _serialNumber, value); + get; + set => this.SetUnsavedValue(ref field, value); } - string _serialNumber; /// /// True when placement has been set by user or by automatic placement /// public bool Placed { - get => _placed; - set => this.RaiseAndSetIfChanged(ref _placed, value); + get; + set => this.RaiseAndSetIfChanged(ref field, value); } - bool _placed; /// /// Monitor model diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/PhysicalMonitorModel.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/PhysicalMonitorModel.cs index ee60d49c..f5a173e5 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/PhysicalMonitorModel.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/PhysicalMonitorModel.cs @@ -16,7 +16,7 @@ public static PhysicalMonitorModel Design { get { - if(!Avalonia.Controls.Design.IsDesignMode) throw new InvalidOperationException("Only for design mode"); + //if(!Avalonia.Controls.Design.IsDesignMode) throw new InvalidOperationException("Only for design mode"); return new PhysicalMonitorModel("PNP0000") { }; @@ -39,25 +39,13 @@ public PhysicalMonitorModel(string pnpCode) }); } - [DataMember] - public string PnpDeviceName - { - get => _pnpDeviceName; - set => SetUnsavedValue(ref _pnpDeviceName, value); - } - string _pnpDeviceName; + public string PnpDeviceName { get; set => SetUnsavedValue(ref field, value); } /// /// Icon path for brand logo /// - public string Logo - { - get => _logo; - set => this.RaiseAndSetIfChanged(ref _logo, value); - } - string _logo; - + public string Logo { get; set => this.RaiseAndSetIfChanged(ref field, value); } [DataMember] public DisplaySizeInMm PhysicalSize { get; } diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/PhysicalSource.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/PhysicalSource.cs index e284d712..8b9dd0d5 100644 --- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/PhysicalSource.cs +++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/PhysicalSource.cs @@ -40,35 +40,16 @@ public static IDisplayRatio UpdateDipToPixelRatio( double srcDpiX, double srcDpiY, double dpiEffectiveX, double dpiEffectiveY) { - switch (aware) - { - case WinDef.DpiAwareness.Unaware: - return new DisplayRatioValue( - Math.Round(dpiRealX / dpiAngX * 10) / 10, - Math.Round(dpiRealY / dpiAngY * 10) / 10); - //return Math.Round((RealDpiY / DpiAwareAngularDpiY) * 20) / 20; - - case WinDef.DpiAwareness.SystemAware: - return new DisplayRatioValue( - srcDpiX / 96, - srcDpiY / 96 - ); - - case WinDef.DpiAwareness.PerMonitorAware: - return new DisplayRatioValue( - dpiEffectiveX / 96, - dpiEffectiveY / 96 - ); - - case WinDef.DpiAwareness.Invalid: - return new DisplayRatioValue( - dpiEffectiveX / 96, - dpiEffectiveY / 96 - ); - - default: - throw new ArgumentOutOfRangeException(); - } + return aware switch + { + WinDef.DpiAwareness.Unaware => new DisplayRatioValue(Math.Round(dpiRealX / dpiAngX * 10) / 10, + Math.Round(dpiRealY / dpiAngY * 10) / 10), + //return Math.Round((RealDpiY / DpiAwareAngularDpiY) * 20) / 20; + WinDef.DpiAwareness.SystemAware => new(srcDpiX / 96, srcDpiY / 96), + WinDef.DpiAwareness.PerMonitorAware or WinDef.DpiAwareness.Invalid => new ( + dpiEffectiveX / 96, dpiEffectiveY / 96), + _ => throw new ArgumentOutOfRangeException() + }; } public PhysicalSource(string deviceId, PhysicalMonitor monitor, DisplaySource source) @@ -150,11 +131,11 @@ public PhysicalSource(string deviceId, PhysicalMonitor monitor, DisplaySource so /// /// Device ID /// - public string DeviceId { - get => _deviceId; - set => this.RaiseAndSetIfChanged(ref _deviceId, value); + public string DeviceId + { + get; + set => this.RaiseAndSetIfChanged(ref field, value); } - string _deviceId; /// diff --git a/LittleBigMouse.Core/LittleBigMouse.Zones/IXmlSerializable.cs b/LittleBigMouse.Core/LittleBigMouse.Zones/IXmlSerializable.cs index 31411949..c3d89cfa 100644 --- a/LittleBigMouse.Core/LittleBigMouse.Zones/IXmlSerializable.cs +++ b/LittleBigMouse.Core/LittleBigMouse.Zones/IXmlSerializable.cs @@ -1,7 +1,7 @@ using System.Collections; using System.Globalization; using System.Linq.Expressions; -using Avalonia; +using HLab.Geo; namespace LittleBigMouse.Zoning; diff --git a/LittleBigMouse.Core/LittleBigMouse.Zones/LittleBigMouse.Zoning.csproj b/LittleBigMouse.Core/LittleBigMouse.Zones/LittleBigMouse.Zoning.csproj index af2cfa9d..cba6d4cb 100644 --- a/LittleBigMouse.Core/LittleBigMouse.Zones/LittleBigMouse.Zoning.csproj +++ b/LittleBigMouse.Core/LittleBigMouse.Zones/LittleBigMouse.Zoning.csproj @@ -1,17 +1,19 @@  - net8.0 + net10.0 enable enable - AnyCPU;x64;x86 - 5.2.4.0 + x64 + 5.3.0.0 - - + + + + diff --git a/LittleBigMouse.Core/LittleBigMouse.Zones/RectExtentions.cs b/LittleBigMouse.Core/LittleBigMouse.Zones/RectExtentions.cs index 7f7c5aed..0a7006af 100644 --- a/LittleBigMouse.Core/LittleBigMouse.Zones/RectExtentions.cs +++ b/LittleBigMouse.Core/LittleBigMouse.Zones/RectExtentions.cs @@ -1,41 +1,93 @@ -using Avalonia; +using HLab.Geo; namespace LittleBigMouse.Zoning; public static class RectExtensions { - /// - /// - /// - /// - /// - /// - /// - public static Rect[] TravelPixels(this Rect source, Rect target, Rect[] allowed) + + public static Rect[] TravelPathDepth(this Rect start, Rect target, Rect[] allowed) { - var list = source.Reachable(target); + var list = start.DetermineContactZones(target); if (list.Length>1) return list; - if (!allowed.Any()) return Array.Empty(); + if (!allowed.Any()) return []; foreach(var next in allowed) { var newAllowed = allowed.Where(r => !r.Equals(next)).ToArray(); - var tail = next.TravelPixels(target,newAllowed); - if (!tail.Any()) continue; + var tail = next.TravelPathDepth(target,newAllowed); + if (tail.Length == 0) continue; - //todo : should retain smallest travel - var travel = source.TravelPixels(next,newAllowed); - - if(travel.Any()) return travel.Concat(tail).ToArray(); + var head = start.TravelPathDepth(next,newAllowed); + if(head.Length != 0) return head.Concat(tail).ToArray(); } - return Array.Empty(); + return []; } - public static Rect[] Reachable(this Rect source, Rect target) + + + /// + /// Calculates the travel path between a source rectangle and a target rectangle, + /// potentially navigating through allowed intermediary rectangles. + /// + /// The source rectangle where the travel begins. + /// The destination rectangle to reach. + /// An array of intermediate rectangles that can be used during the travel. + /// + /// An array of rectangles representing the travel path from the source to the target, + /// passing through allowed rectangles if necessary. + /// + public static Rect[] TravelPath(this Rect source, Rect target, Rect[] allowed) + { + var directPath = source.DetermineContactZones(target); + + // If the source and target rectangles are already connected, return the list directly + if (directPath.Length > 1) return directPath; + if (allowed.Length == 0) return []; + + var queue = new Queue<(Rect current, Rect[] allowed)>(); + queue.Enqueue((source, [source])); + + do + { + var (current, currentPath) = queue.Dequeue(); + + foreach(var next in allowed) + { + directPath = current.DetermineContactZones(next); + + // If the source and target rectangles are already connected, return the list directly + if (directPath.Length > 1) return directPath; + + var newAllowed = allowed.Where(r => !r.Equals(next)).ToArray(); + + queue.Enqueue((next, newAllowed)); + var tail = next.TravelPath(target,newAllowed); + if (tail.Length == 0) continue; + + var travel = source.TravelPath(next,newAllowed); + + if(travel.Length != 0) return travel.Concat(tail).ToArray(); + } + } while (queue.Count > 0); + + + return []; + } + + /// + /// Determines the parts of source and target rectangles that allow to horizontally or vertically reach from the source to the target rectangle. + /// + /// The source rectangle from which the path starts. + /// The target rectangle to determine the path to. + /// + /// An array of rectangles representing the path between the source and target rectangles. + /// + + public static Rect[] DetermineContactZones (this Rect source, Rect target) { var left = Math.Max(target.Left, source.Left); var right = Math.Min(target.Right, source.Right); @@ -46,23 +98,54 @@ public static Rect[] Reachable(this Rect source, Rect target) { if(top >= bottom) { - return new[] { source }; + // No direct path, return the source rectangle + // +---+ +---+ + // | S | | 0 | + // +---+ => +---+ + // +---+ .... + // | T | . . + // +---+ .... + + return [source]; } + + // Horizontal path + // +---+ ..... + // | S | +---+ ==> +---+ +---+ + // | | | | | 0 | | 1 | + // +---+ | T | +---+ +---+ + // +---+ ..... var start = new Rect(source.Left, top, source.Width, bottom - top); var dest = new Rect(target.Left, top, target.Width, bottom - top); - return new[] { start, dest }; + return [start, dest]; } if(top >= bottom) { + // Vertical path + // +---+ ..+-+ + // | S | . |0| + // +---+ ==> ..+-+ + // +---+ +-+.. + // | T | |1| . + // +---+ +-+.. + var start = new Rect(left, source.Top, right-left, source.Height); var dest = new Rect(left, target.Top, right-left, target.Height); - return new[] { start, dest }; + return [start, dest]; } - + + + // Overlaping path + // +------+ ....... + // | S +------+ . +--+... + // | | T | . |01| . + // +---| | ==> ...+--+ . + // +------+ ....... + var rect = new Rect(left, top, right-left, bottom - top); - return new[] { rect, rect }; + return [rect, rect]; } } \ No newline at end of file diff --git a/LittleBigMouse.Core/LittleBigMouse.Zones/Zone.cs b/LittleBigMouse.Core/LittleBigMouse.Zones/Zone.cs index 9885c05a..dc160bb9 100644 --- a/LittleBigMouse.Core/LittleBigMouse.Zones/Zone.cs +++ b/LittleBigMouse.Core/LittleBigMouse.Zones/Zone.cs @@ -1,7 +1,6 @@ - -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Text.Json.Serialization; -using Avalonia; +using HLab.Geo; namespace LittleBigMouse.Zoning; @@ -55,14 +54,14 @@ public void Init(int id) _pixelsToPhysicalMatrix = Matrix .CreateTranslation(PixelsBounds.X, -PixelsBounds.Y) - .Append(Matrix.CreateScale(1 / PixelsBounds.Width, 1 / PixelsBounds.Height)) - .Append(Matrix.CreateScale(PhysicalBounds.Width, PhysicalBounds.Height)) - .Append(Matrix.CreateTranslation(PhysicalBounds.X, PhysicalBounds.Y)); + * Matrix.CreateScale(1 / PixelsBounds.Width, 1 / PixelsBounds.Height) + * Matrix.CreateScale(PhysicalBounds.Width, PhysicalBounds.Height) + * Matrix.CreateTranslation(PhysicalBounds.X, PhysicalBounds.Y); _physicalToPixelsMatrix = Matrix.CreateTranslation(-PhysicalBounds.X, -PhysicalBounds.Y) - .Append(Matrix.CreateScale(1 / PhysicalBounds.Width, 1 / PhysicalBounds.Height)) - .Append(Matrix.CreateScale(PixelsBounds.Width, PixelsBounds.Height)) - .Append(Matrix.CreateTranslation(PixelsBounds.X, PixelsBounds.Y)); + * Matrix.CreateScale(1 / PhysicalBounds.Width, 1 / PhysicalBounds.Height) + * Matrix.CreateScale(PixelsBounds.Width, PixelsBounds.Height) + * Matrix.CreateTranslation(PixelsBounds.X, PixelsBounds.Y); var dpiX = PixelsBounds.Width / (PhysicalBounds.Width / 25.4); var dpiY = PixelsBounds.Height / (PhysicalBounds.Height / 25.4); @@ -290,7 +289,17 @@ public Point InsidePhysicalBounds(Point mm) public IEnumerable TravelPixels(IEnumerable zones, Zone target) { - return _travels.GetOrAdd(target.Main, z => PixelsBounds.TravelPixels(z.PixelsBounds, zones.Where(z => ReferenceEquals(z, z.Main)).Select(z => z.PixelsBounds).ToArray())); + return _travels.GetOrAdd( + target.Main, + + z => PixelsBounds.TravelPath( + z.PixelsBounds, + zones + .Where(z => ReferenceEquals(z, z.Main)) + .Select(z => z.PixelsBounds) + .ToArray() + ) + ); } public string Serialize() diff --git a/LittleBigMouse.Core/LittleBigMouse.Zones/ZonesLayout.cs b/LittleBigMouse.Core/LittleBigMouse.Zones/ZonesLayout.cs index 1d44b08d..b76ac89d 100644 --- a/LittleBigMouse.Core/LittleBigMouse.Zones/ZonesLayout.cs +++ b/LittleBigMouse.Core/LittleBigMouse.Zones/ZonesLayout.cs @@ -1,5 +1,5 @@ -using System.Text.Json.Serialization; -using Avalonia; +using HLab.Geo; +using System.Text.Json.Serialization; namespace LittleBigMouse.Zoning { diff --git a/LittleBigMouse.Hook/Daemon/LittleBigMouseDaemon.cpp b/LittleBigMouse.Hook/Daemon/LittleBigMouseDaemon.cpp index 19759e5b..eff732f1 100644 --- a/LittleBigMouse.Hook/Daemon/LittleBigMouseDaemon.cpp +++ b/LittleBigMouse.Hook/Daemon/LittleBigMouseDaemon.cpp @@ -5,15 +5,15 @@ #include #pragma comment(lib,"shlwapi.lib") -#include "SignalSlot.h" - -#include "Engine/MouseEngine.h" -#include "Hook/Hooker.h" -#include "Remote/RemoteServer.h" -#include "Remote/RemoteClient.h" -#include "Xml/tinyxml2.h" -#include "Xml/XmlHelper.h" -#include "Strings/str.h" +#include "../SignalSlot.h" + +#include "../Engine/MouseEngine.h" +#include "../Hook/Hooker.h" +#include "../Remote/RemoteServer.h" +#include "../Remote/RemoteClient.h" +#include "../Xml/tinyxml2.h" +#include "../Xml/XmlHelper.h" +#include "../Strings/str.h" void LittleBigMouseDaemon::Unhooked() const { diff --git a/LittleBigMouse.Hook/Daemon/LittleBigMouseDaemon.h b/LittleBigMouse.Hook/Daemon/LittleBigMouseDaemon.h index 6bf3c4df..84213348 100644 --- a/LittleBigMouse.Hook/Daemon/LittleBigMouseDaemon.h +++ b/LittleBigMouse.Hook/Daemon/LittleBigMouseDaemon.h @@ -1,5 +1,5 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" #include #include diff --git a/LittleBigMouse.Hook/Engine/HookMouseEventArg.h b/LittleBigMouse.Hook/Engine/HookMouseEventArg.h index 2780245a..ab132f6a 100644 --- a/LittleBigMouse.Hook/Engine/HookMouseEventArg.h +++ b/LittleBigMouse.Hook/Engine/HookMouseEventArg.h @@ -1,8 +1,8 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" #include -#include "Geometry/Point.h" +#include "../Geometry/Point.h" class MouseEventArg { diff --git a/LittleBigMouse.Hook/Engine/MouseEngine.cpp b/LittleBigMouse.Hook/Engine/MouseEngine.cpp index 345d54c7..c48f4e9c 100644 --- a/LittleBigMouse.Hook/Engine/MouseEngine.cpp +++ b/LittleBigMouse.Hook/Engine/MouseEngine.cpp @@ -1,6 +1,6 @@ #include "MouseEngine.h" -#include "Geometry/Geometry.h" +#include "../Geometry/Geometry.h" #include "MouseHelper.h" #include "ZoneLink.h" diff --git a/LittleBigMouse.Hook/Engine/MouseEngine.h b/LittleBigMouse.Hook/Engine/MouseEngine.h index ea4cca65..d5cc67ae 100644 --- a/LittleBigMouse.Hook/Engine/MouseEngine.h +++ b/LittleBigMouse.Hook/Engine/MouseEngine.h @@ -1,13 +1,13 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" #include -#include "SignalSlot.h" +#include "../SignalSlot.h" #include "HookMouseEventArg.h" #include "ZonesLayout.h" -#include "Geometry/Rect.h" -#include "Geometry/Segment.h" +#include "../Geometry/Rect.h" +#include "../Geometry/Segment.h" class ZoneLink; diff --git a/LittleBigMouse.Hook/Engine/MouseHelper.h b/LittleBigMouse.Hook/Engine/MouseHelper.h index 4fe6ecf9..c163ff52 100644 --- a/LittleBigMouse.Hook/Engine/MouseHelper.h +++ b/LittleBigMouse.Hook/Engine/MouseHelper.h @@ -1,8 +1,8 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" -#include "Geometry/Point.h" -#include "Geometry/Rect.h" +#include "../Geometry/Point.h" +#include "../Geometry/Rect.h" void SetMouseLocation(const geo::Point& location); geo::Point GetMouseLocation(); diff --git a/LittleBigMouse.Hook/Engine/Zone.cpp b/LittleBigMouse.Hook/Engine/Zone.cpp index 3efdb30c..2e6462b4 100644 --- a/LittleBigMouse.Hook/Engine/Zone.cpp +++ b/LittleBigMouse.Hook/Engine/Zone.cpp @@ -3,7 +3,7 @@ #include #include -#include "Xml/tinyxml2.h" +#include "../Xml/tinyxml2.h" #include "ZoneLink.h" #include "ZonesLayout.h" diff --git a/LittleBigMouse.Hook/Engine/Zone.h b/LittleBigMouse.Hook/Engine/Zone.h index 0d36c0a9..58fa79ca 100644 --- a/LittleBigMouse.Hook/Engine/Zone.h +++ b/LittleBigMouse.Hook/Engine/Zone.h @@ -1,13 +1,13 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" #include #include -#include "Xml/tinyxml2.h" +#include "../Xml/tinyxml2.h" -#include "Geometry/Point.h" -#include "Geometry/Rect.h" +#include "../Geometry/Point.h" +#include "../Geometry/Rect.h" class ZoneLink; class ZonesLayout; diff --git a/LittleBigMouse.Hook/Engine/ZoneLink.h b/LittleBigMouse.Hook/Engine/ZoneLink.h index 6bc12429..7735d8d0 100644 --- a/LittleBigMouse.Hook/Engine/ZoneLink.h +++ b/LittleBigMouse.Hook/Engine/ZoneLink.h @@ -1,5 +1,5 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" class Zone; diff --git a/LittleBigMouse.Hook/Engine/ZonesLayout.cpp b/LittleBigMouse.Hook/Engine/ZonesLayout.cpp index 816b9099..2e48470c 100644 --- a/LittleBigMouse.Hook/Engine/ZonesLayout.cpp +++ b/LittleBigMouse.Hook/Engine/ZonesLayout.cpp @@ -1,6 +1,6 @@ #include "ZonesLayout.h" -#include "Xml/XmlHelper.h" +#include "../Xml/XmlHelper.h" #include "ZoneLink.h" #include "Zone.h" diff --git a/LittleBigMouse.Hook/Engine/ZonesLayout.h b/LittleBigMouse.Hook/Engine/ZonesLayout.h index 4c4bfb9d..7aed0e88 100644 --- a/LittleBigMouse.Hook/Engine/ZonesLayout.h +++ b/LittleBigMouse.Hook/Engine/ZonesLayout.h @@ -1,10 +1,10 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" #include -#include "Geometry/Point.h" -#include "Xml/tinyxml2.h" +#include "../Geometry/Point.h" +#include "../Xml/tinyxml2.h" #include "Priority.h" class Zone; diff --git a/LittleBigMouse.Hook/Geometry/Line.h b/LittleBigMouse.Hook/Geometry/Line.h index 8272b2a3..20e412bf 100644 --- a/LittleBigMouse.Hook/Geometry/Line.h +++ b/LittleBigMouse.Hook/Geometry/Line.h @@ -1,5 +1,5 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" #include "Point.h" diff --git a/LittleBigMouse.Hook/Geometry/Point.h b/LittleBigMouse.Hook/Geometry/Point.h index 8f01a580..2c8ea940 100644 --- a/LittleBigMouse.Hook/Geometry/Point.h +++ b/LittleBigMouse.Hook/Geometry/Point.h @@ -1,5 +1,5 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" #include #include diff --git a/LittleBigMouse.Hook/Geometry/Segment.h b/LittleBigMouse.Hook/Geometry/Segment.h index fa07e00d..2da1f4cd 100644 --- a/LittleBigMouse.Hook/Geometry/Segment.h +++ b/LittleBigMouse.Hook/Geometry/Segment.h @@ -1,5 +1,5 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" #include diff --git a/LittleBigMouse.Hook/Hook/Hooker.cpp b/LittleBigMouse.Hook/Hook/Hooker.cpp index 46345ec2..fc13ba20 100644 --- a/LittleBigMouse.Hook/Hook/Hooker.cpp +++ b/LittleBigMouse.Hook/Hook/Hooker.cpp @@ -1,7 +1,7 @@ #include "Hooker.h" -#include "Logger/Logger.h" -#include "Remote/RemoteServer.h" +#include "../Logger/Logger.h" +#include "../Remote/RemoteServer.h" std::atomic Hooker::_instance = nullptr; diff --git a/LittleBigMouse.Hook/Hook/Hooker.h b/LittleBigMouse.Hook/Hook/Hooker.h index 90aab337..4461648b 100644 --- a/LittleBigMouse.Hook/Hook/Hooker.h +++ b/LittleBigMouse.Hook/Hook/Hooker.h @@ -1,10 +1,10 @@ #pragma once -#include "framework.h" +#include "../framework.h" #include -#include "SignalSlot.h" -#include "Engine/Priority.h" -#include "Thread/ThreadHost.h" +#include "../SignalSlot.h" +#include "../Engine/Priority.h" +#include "../Thread/ThreadHost.h" class MouseEventArg; class MouseEngine; diff --git a/LittleBigMouse.Hook/Hook/HookerDisplayChanged.cpp b/LittleBigMouse.Hook/Hook/HookerDisplayChanged.cpp index c9e1aa5b..a92eb29a 100644 --- a/LittleBigMouse.Hook/Hook/HookerDisplayChanged.cpp +++ b/LittleBigMouse.Hook/Hook/HookerDisplayChanged.cpp @@ -1,5 +1,5 @@ #include "Hooker.h" -#include "Strings/str.h" +#include "../Strings/str.h" #define MAX_LOADSTRING 100 diff --git a/LittleBigMouse.Hook/Hook/HookerMouse.cpp b/LittleBigMouse.Hook/Hook/HookerMouse.cpp index a6be0bfc..fa17ef6f 100644 --- a/LittleBigMouse.Hook/Hook/HookerMouse.cpp +++ b/LittleBigMouse.Hook/Hook/HookerMouse.cpp @@ -1,6 +1,6 @@ #include "Hooker.h" -#include "Engine/MouseEngine.h" +#include "../Engine/MouseEngine.h" void Hooker::HookMouse() { diff --git a/LittleBigMouse.Hook/Hook/HookerWinEvents.cpp b/LittleBigMouse.Hook/Hook/HookerWinEvents.cpp index 50d8538d..e4ba845d 100644 --- a/LittleBigMouse.Hook/Hook/HookerWinEvents.cpp +++ b/LittleBigMouse.Hook/Hook/HookerWinEvents.cpp @@ -1,6 +1,6 @@ #include "Hooker.h" -#include "Strings/str.h" +#include "../Strings/str.h" DWORD GetProcessIdFromWindow(HWND hWnd) { DWORD processId; diff --git a/LittleBigMouse.Hook/Logger/Logger.cpp b/LittleBigMouse.Hook/Logger/Logger.cpp index 2e2bbaad..4d6577a3 100644 --- a/LittleBigMouse.Hook/Logger/Logger.cpp +++ b/LittleBigMouse.Hook/Logger/Logger.cpp @@ -1,10 +1,24 @@ #include "Logger.h" #if _DEBUG && DEBUG_LOG +#include +#include std::mutex Logger::Lock; #ifdef LOGTOFILE -std::ofstream Logger::Out = std::ofstream("L:\\log.txt", std::ios::app); +static std::string LogFilePath() +{ + char base[MAX_PATH] = { 0 }; + const DWORD n = GetEnvironmentVariableA("ProgramData", base, MAX_PATH); + if (n == 0 || n >= MAX_PATH) + return "lbm-hook.log"; + + const std::string dir = std::string(base) + "\\Mgth\\LittleBigMouse"; + CreateDirectoryA((std::string(base) + "\\Mgth").c_str(), nullptr); + CreateDirectoryA(dir.c_str(), nullptr); + return dir + "\\hook.log"; +} +std::ofstream Logger::Out = std::ofstream(LogFilePath(), std::ios::app); #else std::ostream Logger::Out = std::cout; #endif // LOGTOFILE diff --git a/LittleBigMouse.Hook/Logger/Logger.h b/LittleBigMouse.Hook/Logger/Logger.h index 7f6f8081..29aa3c0a 100644 --- a/LittleBigMouse.Hook/Logger/Logger.h +++ b/LittleBigMouse.Hook/Logger/Logger.h @@ -1,5 +1,5 @@ #pragma once -#include "Config.h" +#include "../Config.h" #if _DEBUG && DEBUG_LOG diff --git a/LittleBigMouse.Hook/Remote/ClientMessage.h b/LittleBigMouse.Hook/Remote/ClientMessage.h index f196ea9d..dd99e2c5 100644 --- a/LittleBigMouse.Hook/Remote/ClientMessage.h +++ b/LittleBigMouse.Hook/Remote/ClientMessage.h @@ -1,5 +1,5 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" #include class RemoteClient; diff --git a/LittleBigMouse.Hook/Remote/RemoteClient.cpp b/LittleBigMouse.Hook/Remote/RemoteClient.cpp index 458cf71b..629202f7 100644 --- a/LittleBigMouse.Hook/Remote/RemoteClient.cpp +++ b/LittleBigMouse.Hook/Remote/RemoteClient.cpp @@ -1,4 +1,4 @@ -#include "Framework.h" +#include "../Framework.h" #include "RemoteClient.h" #include "RemoteServerSocket.h" diff --git a/LittleBigMouse.Hook/Remote/RemoteClient.h b/LittleBigMouse.Hook/Remote/RemoteClient.h index 34dc9cdd..689c3da5 100644 --- a/LittleBigMouse.Hook/Remote/RemoteClient.h +++ b/LittleBigMouse.Hook/Remote/RemoteClient.h @@ -1,9 +1,9 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" #include -#include "Thread/ThreadHost.h" +#include "../Thread/ThreadHost.h" class RemoteServerSocket; diff --git a/LittleBigMouse.Hook/Remote/RemoteServer.h b/LittleBigMouse.Hook/Remote/RemoteServer.h index b533e260..9df9d0ef 100644 --- a/LittleBigMouse.Hook/Remote/RemoteServer.h +++ b/LittleBigMouse.Hook/Remote/RemoteServer.h @@ -1,12 +1,12 @@ #pragma once -#include "framework.h" +#include "../framework.h" #include #include -#include "SignalSlot.h" +#include "../SignalSlot.h" #include "RemoteClient.h" -#include "Thread/ThreadHost.h" +#include "../Thread/ThreadHost.h" class RemoteClient; class ClientMessage; diff --git a/LittleBigMouse.Hook/Remote/RemoteServerPipe.cpp b/LittleBigMouse.Hook/Remote/RemoteServerPipe.cpp index 34a1273c..2c5bc0e3 100644 --- a/LittleBigMouse.Hook/Remote/RemoteServerPipe.cpp +++ b/LittleBigMouse.Hook/Remote/RemoteServerPipe.cpp @@ -2,7 +2,7 @@ #include "RemoteServer.h" -#include "Strings/str.h" +#include "../Strings/str.h" bool RemoteServerPipe::StartListener() { diff --git a/LittleBigMouse.Hook/Remote/RemoteServerPipe.h b/LittleBigMouse.Hook/Remote/RemoteServerPipe.h index 3e1afedc..4b2c6da2 100644 --- a/LittleBigMouse.Hook/Remote/RemoteServerPipe.h +++ b/LittleBigMouse.Hook/Remote/RemoteServerPipe.h @@ -1,9 +1,9 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" #include -#include "Engine/HookMouseEventArg.h" +#include "../Engine/HookMouseEventArg.h" #include "RemoteServer.h" constexpr int BUFFERSIZE = 1024*16; diff --git a/LittleBigMouse.Hook/Remote/RemoteServerSocket.h b/LittleBigMouse.Hook/Remote/RemoteServerSocket.h index a3dc8e61..aa7430de 100644 --- a/LittleBigMouse.Hook/Remote/RemoteServerSocket.h +++ b/LittleBigMouse.Hook/Remote/RemoteServerSocket.h @@ -1,5 +1,5 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" #include #include diff --git a/LittleBigMouse.Hook/Thread/ThreadHost.cpp b/LittleBigMouse.Hook/Thread/ThreadHost.cpp index 9820b4ea..c369e3ea 100644 --- a/LittleBigMouse.Hook/Thread/ThreadHost.cpp +++ b/LittleBigMouse.Hook/Thread/ThreadHost.cpp @@ -1,6 +1,6 @@ #include "ThreadHost.h" -#include "Daemon/LittleBigMouseDaemon.h" +#include "../Daemon/LittleBigMouseDaemon.h" ThreadHost::~ThreadHost() { diff --git a/LittleBigMouse.Hook/Thread/ThreadHost.h b/LittleBigMouse.Hook/Thread/ThreadHost.h index 07921538..4d6219bc 100644 --- a/LittleBigMouse.Hook/Thread/ThreadHost.h +++ b/LittleBigMouse.Hook/Thread/ThreadHost.h @@ -1,5 +1,5 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" #include #include diff --git a/LittleBigMouse.Hook/Xml/XmlHelper.h b/LittleBigMouse.Hook/Xml/XmlHelper.h index acc88a4c..e26e591e 100644 --- a/LittleBigMouse.Hook/Xml/XmlHelper.h +++ b/LittleBigMouse.Hook/Xml/XmlHelper.h @@ -1,10 +1,10 @@ #pragma once -#include "Framework.h" +#include "../Framework.h" #include -#include "Geometry/Rect.h" -#include "Xml/tinyxml2.h" +#include "../Geometry/Rect.h" +#include "../Xml/tinyxml2.h" class XmlHelper { diff --git a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/BorderResistancePlugin/BorderResistancePlugin.cs b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/BorderResistancePlugin/BorderResistancePlugin.cs index fbf4dbc6..227e5249 100644 --- a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/BorderResistancePlugin/BorderResistancePlugin.cs +++ b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/BorderResistancePlugin/BorderResistancePlugin.cs @@ -29,9 +29,9 @@ You should have received a copy of the GNU General Public License namespace LittleBigMouse.Plugin.Layout.Avalonia.BorderResistancePlugin; public class BorderResistanceViewMode : ViewMode { } -public class BorderResistancePlugin(IMainService mainService) : IBootloader +public class BorderResistancePlugin(IMainService mainService) : Bootloader { - public Task LoadAsync(IBootContext bootstrapper) + public override Task LoadAsync() { mainService.AddControlPlugin(c => c.AddViewModeButton( @@ -40,6 +40,6 @@ public Task LoadAsync(IBootContext bootstrapper) "Border resistance" ) ); - return Task.CompletedTask; + return Task.FromResult(BootState.Completed); } } diff --git a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LittleBigMouse.Plugin.Layout.Avalonia.csproj b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LittleBigMouse.Plugin.Layout.Avalonia.csproj index 76a4b690..8c7c63d1 100644 --- a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LittleBigMouse.Plugin.Layout.Avalonia.csproj +++ b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LittleBigMouse.Plugin.Layout.Avalonia.csproj @@ -1,13 +1,13 @@  - net8.0 + net10.0 enable enable - x64;x86;AnyCpu + x64 true preview - 5.2.4.0 + 5.3.0.0 @@ -20,11 +20,6 @@ - - - - - diff --git a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LocationPlugin/MonitorLocationPlugin.cs b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LocationPlugin/MonitorLocationPlugin.cs index 1ba7cbd5..37d84d48 100644 --- a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LocationPlugin/MonitorLocationPlugin.cs +++ b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LocationPlugin/MonitorLocationPlugin.cs @@ -4,9 +4,9 @@ namespace LittleBigMouse.Plugin.Layout.Avalonia.LocationPlugin; -public class MonitorLocationPlugin(IMainService mainService) : IBootloader +public class MonitorLocationPlugin(IMainService mainService) : Bootloader { - public Task LoadAsync(IBootContext bootstrapper) + public override Task LoadAsync() { mainService.AddControlPlugin(c => c.AddViewModeButton( @@ -15,7 +15,7 @@ public Task LoadAsync(IBootContext bootstrapper) "Location" )); - return Task.CompletedTask; + return Task.FromResult(BootState.Completed); } } \ No newline at end of file diff --git a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LocationPlugin/MonitorLocationView.axaml b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LocationPlugin/MonitorLocationView.axaml index a61487d3..997a5a33 100644 --- a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LocationPlugin/MonitorLocationView.axaml +++ b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LocationPlugin/MonitorLocationView.axaml @@ -38,7 +38,7 @@ - + diff --git a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/Rulers/RulerPanelView.axaml b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/Rulers/RulerPanelView.axaml index 1ba5881b..25db4710 100644 --- a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/Rulers/RulerPanelView.axaml +++ b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/Rulers/RulerPanelView.axaml @@ -12,7 +12,7 @@ ShowActivated="False" Topmost="True" Margin="0" - SystemDecorations="None" + WindowDecorations="None" TransparencyLevelHint="Transparent" Background="Transparent" diff --git a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/Rulers/RulerViewTop.cs b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/Rulers/RulerViewTop.cs index 04c9844a..f69e65dc 100644 --- a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/Rulers/RulerViewTop.cs +++ b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/Rulers/RulerViewTop.cs @@ -69,7 +69,7 @@ public Brush GetBackground(Color color) protected static Brush GetBrush(double x1, double y1, double x2, double y2, Color c0) { var c1 = c0.ToColor(); - var c2 = new ColorRGB(0, c1.Red / 3, c1.Green / 3, c1.Blue / 3).ToAvaloniaColor(); + var c2 = HLabColors.RGB(0, c1.Red / 3, c1.Green / 3, c1.Blue / 3).ToAvaloniaColor(); return new LinearGradientBrush { @@ -282,7 +282,7 @@ public bool Selected readonly Pen _penIn = new(Brushes.WhiteSmoke, 1); - readonly Pen _penOut = new(new SolidColorBrush(new ColorRGB(0.7, 0.7, 0.7, 0.7).ToAvaloniaColor()), 1); + readonly Pen _penOut = new(new SolidColorBrush(HLabColors.RGB(0.7, 0.7, 0.7, 0.7).ToAvaloniaColor()), 1); protected void Render() { diff --git a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/SizePlugin/ScreenSizePlugin.cs b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/SizePlugin/ScreenSizePlugin.cs index 59350462..49544391 100644 --- a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/SizePlugin/ScreenSizePlugin.cs +++ b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/SizePlugin/ScreenSizePlugin.cs @@ -29,9 +29,9 @@ You should have received a copy of the GNU General Public License namespace LittleBigMouse.Plugin.Layout.Avalonia.SizePlugin; public class ScreenSizeViewMode : ViewMode { } -public class ScreenSizePlugin(IMainService mainService) : IBootloader +public class ScreenSizePlugin(IMainService mainService) : Bootloader { - public Task LoadAsync(IBootContext bootstrapper) + public override Task LoadAsync() { mainService.AddControlPlugin(c => c.AddViewModeButton( @@ -40,6 +40,6 @@ public Task LoadAsync(IBootContext bootstrapper) "Size" ) ); - return Task.CompletedTask; + return Task.FromResult(BootState.Completed); } } diff --git a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/LittleBigMouse.Plugin.Vcp.Avalonia.csproj b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/LittleBigMouse.Plugin.Vcp.Avalonia.csproj index def3d1ae..ac6fa130 100644 --- a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/LittleBigMouse.Plugin.Vcp.Avalonia.csproj +++ b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/LittleBigMouse.Plugin.Vcp.Avalonia.csproj @@ -1,13 +1,13 @@  - net8.0 + net10.0 enable enable - AnyCPU;x64;x86 + x64 preview true - 5.2.4.0 + 5.3.0.0 @@ -21,9 +21,7 @@ - - - + diff --git a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/VcpPlugin.cs b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/VcpPlugin.cs index 39be0aa0..12281728 100644 --- a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/VcpPlugin.cs +++ b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/VcpPlugin.cs @@ -21,6 +21,7 @@ You should have received a copy of the GNU General Public License http://www.mgth.fr */ +using Avalonia; using HLab.Core.Annotations; using HLab.Mvvm.Annotations; using LittleBigMouse.Plugins; @@ -30,9 +31,9 @@ namespace LittleBigMouse.Plugin.Vcp.Avalonia; internal class MonitorVcpViewMode : ViewMode { } -public class VcpPlugin(IMainService mainService) : IBootloader +public class VcpPlugin(IMainService mainService) : Bootloader { - public Task LoadAsync(IBootContext bootstrapper) + public override Task LoadAsync() { #if DEBUG mainService.AddControlPlugin(c => @@ -42,7 +43,7 @@ public Task LoadAsync(IBootContext bootstrapper) "Vcp control") ); #endif - return Task.CompletedTask; + return Task.FromResult(BootState.Completed); } } diff --git a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/VcpScreenView.axaml b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/VcpScreenView.axaml index 1070c1c6..caee43a0 100644 --- a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/VcpScreenView.axaml +++ b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/VcpScreenView.axaml @@ -5,7 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:vcp.Avalonia="clr-namespace:LittleBigMouse.Plugin.Vcp.Avalonia" xmlns:mvvm.Avalonia="clr-namespace:HLab.Mvvm.Avalonia;assembly=HLab.Mvvm.Avalonia" - xmlns:avalonia="clr-namespace:ScottPlot.Avalonia;assembly=ScottPlot.Avalonia" + xmlns:avalonia="clr-namespace:LiveChartsCore.SkiaSharpView.Avalonia;assembly=LiveChartsCore.SkiaSharpView.Avalonia" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="615.613" x:DataType="vcp.Avalonia:VcpScreenViewModel" @@ -15,7 +15,7 @@ - + @@ -61,8 +61,6 @@ - - @@ -72,7 +70,26 @@ - + + + + + +