fix Nvidia crash, remove UWP dependencies

This commit is contained in:
Vincent Maas committed 2025-01-26 10:38:56 +01:00
1 parent d31d2f321f
commit 6e206a6728
40 files changed
+8544 -8449

No files matched your search

+4 -3
View File
@@ -1,14 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net9.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<OutputType>Library</OutputType>
<OutputType>Library</OutputType>
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NLog" Version="5.2.8" />
<PackageReference Include="NLog" Version="5.3.4" />
</ItemGroup>
<ItemGroup>
@@ -251,6 +251,17 @@
</div>
</div>
}
else
{
<div class="row">
<div class="col">
<div class="mb-2">
<label class="form-label" for="shadowDetailBoost">Shadow detail boost (%)</label>
<input class="form-control" id="shadowDetailBoost" type="number" min="0" max="100" @bind="ColorProfile.ShadowDetailBoost" disabled="@(ColorProfile.SDRTransferFunction == SDRTransferFunction.Piecewise)" />
</div>
</div>
</div>
}
</div>
</div>
</div>
@@ -33,12 +33,12 @@ else
{
<span>No displays found</span>
}
@foreach (var display in Displays)
else
{
<div class="mb-2">
<label class="form-label" for="device">Selected display</label>
<select class="form-select" id="device" @bind="SelectedDisplayId" @bind:after="SelectedDisplayChanged">
@foreach (var device in Displays)
@foreach (var display in Displays)
{
<option value="@display.DisplayId">@display.DisplayName @@ @display.AdapterName</option>
}
@@ -7,57 +7,133 @@
@if (Label != null)
{
<div class="mb-2">
<label class="form-label" for="name">@Label</label>
<input class="form-control" type="text" readonly value="@Shortcut"
@onchange="(ChangeEventArgs e) => ShortcutOnChange(e)"
@onkeydown="ShortcutOnKeyDown"
@onkeyup="(KeyboardEventArgs e) => ShortcutOnKeyUp(e)"
@onfocus="ShortcutOnFocus"
@onblur="ShortcutOnBlur"/>
</div>
<div class="mb-2">
<label class="form-label" for="name">@Label</label>
<div class="input-group">
<input class="form-control" type="text" readonly value="@Shortcut"
@onchange="(ChangeEventArgs e) => ShortcutOnChange(e)"
@onkeydown="ShortcutOnKeyDown"
@onkeyup="(KeyboardEventArgs e) => ShortcutOnKeyUp(e)"
@onfocus="ShortcutOnFocus"
@onblur="ShortcutOnBlur"/>
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
</button>
<ul class="dropdown-menu">
@foreach (var modifier in Modifiers) {
<li>
<a class="dropdown-item" @onclick="() => ModifierOnClick(modifier.Key)">
<input class="form-check-input me-2" type="checkbox" id="flexCheckChecked" checked="@modifier.Value" @onchange="(e) => ModifierKeyChanged(e, modifier.Key)">@modifier.Key
</a>
</li>
}
</ul>
</div>
</div>
}
@code {
[Parameter]
public string? Label { get; set; }
[Parameter]
public string? Label { get; set; }
[Parameter]
public string? Shortcut { get; set; }
[Parameter]
public string? Shortcut { get; set; }
[Parameter]
public EventCallback<string?> ShortcutChanged { get; set; }
[Parameter]
public EventCallback<string?> ShortcutChanged { get; set; }
private async Task ShortcutOnChange(ChangeEventArgs e)
{
Shortcut = e.Value?.ToString();
await ShortcutChanged.InvokeAsync(Shortcut);
}
private Dictionary<string, bool> Modifiers = new() {
{ "Shift", false },
{ "Control", false },
{ "Alt", false },
{ "Win", false }
};
private void ShortcutOnKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Tab")
{
return;
}
protected override void OnParametersSet()
{
LoadModifiers();
}
var text = KeyboardShortcutDispatcher.FormatKeyboardShortcut(e.ShiftKey, e.CtrlKey, e.AltKey, e.Key, e.Code);
Shortcut = text;
}
private async Task ShortcutOnChange(ChangeEventArgs e)
{
Shortcut = e.Value?.ToString();
LoadModifiers();
await ShortcutChanged.InvokeAsync(Shortcut);
}
private async Task ShortcutOnKeyUp(KeyboardEventArgs e)
{
//KeyboardShortcutDispatcher.HandleKeyboardShortcutUp()
await ShortcutChanged.InvokeAsync(Shortcut);
}
private void ShortcutOnKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Tab")
{
return;
}
private void ShortcutOnFocus(FocusEventArgs e)
{
KeyboardShortcutDispatcher.IsActive = false;
}
var text = KeyboardShortcutDispatcher.FormatKeyboardShortcut(e.ShiftKey, e.CtrlKey, e.AltKey, e.Key, e.Code);
Shortcut = text;
}
private void ShortcutOnBlur(FocusEventArgs e)
{
KeyboardShortcutDispatcher.IsActive = true;
}
private async Task ShortcutOnKeyUp(KeyboardEventArgs e)
{
//KeyboardShortcutDispatcher.HandleKeyboardShortcutUp()
await ShortcutChanged.InvokeAsync(Shortcut);
}
private void ShortcutOnFocus(FocusEventArgs e)
{
KeyboardShortcutDispatcher.IsActive = false;
}
private void ShortcutOnBlur(FocusEventArgs e)
{
KeyboardShortcutDispatcher.IsActive = true;
}
private void LoadModifiers()
{
foreach (var modifier in Modifiers.Keys)
{
Modifiers[modifier] = Shortcut?.Contains(modifier) == true;
}
}
private async Task ModifierKeyChanged(ChangeEventArgs e, string modifier)
{
var value = e.Value is bool boolValue && boolValue;
Modifiers[modifier] = value;
await SetModifiers();
}
private async Task SetModifiers()
{
var shortcut = Shortcut ?? "";
foreach (var modifier in Modifiers.Keys)
{
shortcut = shortcut.Replace(modifier, "").Trim().TrimStart(',');
}
shortcut = shortcut.Trim();
foreach (var modifier in Modifiers.Where(kv => kv.Value).Select(kv => kv.Key).Reverse())
{
if (shortcut.StartsWith("+"))
{
shortcut = $"{modifier} {shortcut}";
}
else
{
shortcut = $"{modifier}, {shortcut}";
}
}
Shortcut = shortcut;
await ShortcutChanged.InvokeAsync(Shortcut);
}
private async Task ModifierOnClick(string modifier)
{
Modifiers[modifier] = !Modifiers[modifier];
await SetModifiers();
}
}
@@ -89,8 +89,8 @@
</div>
<div class="modal-footer">
<span class="me-auto">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" @onclick="SetDitherRegistryKeyOnClick">Set dither registry key</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" @onclick="RestartDriverOnClick">Restart driver</button>
<button type="button" class="btn btn-secondary" @onclick="SetDitherRegistryKeyOnClick">Set dither registry key</button>
<button type="button" class="btn btn-secondary" @onclick="RestartDriverOnClick">Restart driver</button>
</span>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
@@ -11,6 +11,7 @@
@inject RpcUiClientService _rpcClientService
@inject AppState AppState
@inject NavigationManager _navigationManager;
@inject JSHelper jsHelper;
<div class="modal" id="presetModal" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false" @onfocus="ModalOnFocus">
<div class="modal-dialog modal-dialog-scrollable modal-dialog-centered">
@@ -70,10 +71,10 @@
<div class="mb-2">
<label class="form-label" for="mode">Display</label>
<select class="form-select" id="mode" @bind="Preset.DisplayId" disabled="@(Preset.primaryDisplay)">
@foreach (var display in displayPresets)
{
<option value="@display.DisplayId">@display.displayName</option>
}
@foreach (var display in displayPresets)
{
<option value="@display.DisplayId">@display.displayName</option>
}
</select>
</div>
<div class="mb-2">
@@ -356,7 +357,7 @@
</div>
<div class="mb-2">
<label class="form-label" for="bits">Bit depth</label>
<select class="form-select" id="bits" @bind="Preset.NvDitherBits">
<select class="form-select" id="bits" @bind="Preset.NvDitherBits">
@foreach (var bits in Enum.GetValues<NvDitherBits>())
{
<option value="@bits.ToString()">@bits.GetDescription()</option>
@@ -544,7 +545,7 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" @onclick="() => IsVisible = false">Close</button>
<button type="submit" class="btn btn-primary" data-bs-dismiss="@(IsValid() ? "modal" : "")" @onclick="ApplyClick">@(Preset?.IsDisplayPreset == true ? "Apply" : "Save")</button>
<button type="submit" class="btn btn-primary" disabled="@(!IsValid())" @onclick="ApplyClick">@(Preset?.IsDisplayPreset == true ? "Apply" : "Save")</button>
</div>
</div>
</div>
@@ -667,12 +668,20 @@
else
{
var result = await _rpcClientService.CallAsync<bool>("NvService", "UpdatePreset", Preset);
if (!result)
{
return;
}
}
if (AfterApply != null)
{
await AfterApply.Invoke(Preset);
}
await jsHelper.CloseModal("presetModal");
IsVisible = false;
}
private async Task ApplyDisplayPreset()
@@ -90,6 +90,26 @@ else
<br />
<small class="text-body">Color profile: @preset.ColorProfileSettings.ProfileName</small>
}
@if (preset.driverSettings?.Any() == true)
{
<br />
<div class="dropdown">
<span role="button" class="text-decoration-underline dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false" data-bs-auto-close="outside" @onclick="() => DriverSettingsOnClick(preset)">
<small>@preset.driverSettings.Count() driver settings changed</small>
</span>
<form class="dropdown-menu">
@if (DriverSettings != null)
{
<ul class="list-group p-0">
@foreach (var setting in DriverSettings)
{
<li class="list-group-item py-0 px-1"><small>@setting.FriendlyName</small></li>
}
</ul>
}
</form>
</div>
}
</div>
</div>
</div>
@@ -258,6 +278,7 @@ else
private NvPreset? CurrentGpuSettingsPreset;
private NvGpuInfoDto? CurrentGpuInfo;
private bool DitheringVisible;
private List<NvSettingItemDto>? DriverSettings;
private PresetOrder PresetOrder;
@@ -371,4 +392,14 @@ else
Presets = Presets?.OrderPresetsBy(PresetOrder);
}
private async Task DriverSettingsOnClick(NvPreset preset)
{
var driverSettings = await _rpcClientService.CallAsync<List<NvSettingItemDto>>("NvService", "GetDriverSettings", Type.Missing, true);
if (driverSettings != null)
{
DriverSettings = driverSettings.Where(s => s.Value != s.DefaultValue && s.State == 2).ToList();
}
}
}
@@ -301,7 +301,7 @@ else
private async Task ElevationMethodInput(ChangeEventArgs e)
{
var value = e.Value != null ? (ElevationMethod)int.Parse((string)e.Value) : ElevationMethod.None;
var value = e.Value != null ? Enum.Parse<ElevationMethod>((string)e.Value) : ElevationMethod.None;
await _rpcClientService.CallAsync<bool>("OptionsService", "SetElevationMethod", value);
}
+13 -15
View File
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net9.0-windows</TargetFramework>
<OutputType>WinExe</OutputType>
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
@@ -18,8 +18,8 @@
<PublisherName>Maassoft</PublisherName>
<Company>Maassoft</Company>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>10.1.0.0</ApplicationVersion>
<Version>10.1.0.0</Version>
<ApplicationVersion>10.2.0.0</ApplicationVersion>
<Version>10.2.0.0</Version>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
<BootstrapperEnabled>false</BootstrapperEnabled>
@@ -28,8 +28,7 @@
<UseWPF>false</UseWPF>
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
<ApplicationIcon>Resources\pngbarn.ico</ApplicationIcon>
<SupportedOSPlatformVersion>10.0.20348.0</SupportedOSPlatformVersion>
<Copyright>2020-2024 Maassoft</Copyright>
<Copyright>2020-2025 Maassoft</Copyright>
<Authors>Maassoft</Authors>
<ManifestCertificateThumbprint>CF0BC153EA664CD97AC6F234B91F45D34630958F</ManifestCertificateThumbprint>
<ManifestKeyFile>ColorControl_1_TemporaryKey.pfx</ManifestKeyFile>
@@ -39,6 +38,7 @@
<SignManifests>true</SignManifests>
<AssemblyOriginatorKeyFile>ColorControl_TemporaryKey.pfx</AssemblyOriginatorKeyFile>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<OutputPath>bin\x64\Debug\</OutputPath>
@@ -106,17 +106,15 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2277.86" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.0" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2903.40" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.2.8" />
<PackageReference Include="NStandard" Version="0.59.0" />
<PackageReference Include="NWin32" Version="1.2.6" />
<PackageReference Include="System.Management" Version="8.0.0" />
<PackageReference Include="TaskScheduler" Version="2.10.1" />
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.4.17" />
<PackageReference Include="RawInput.Sharp" Version="0.1.3" />
<PackageReference Include="NLog" Version="5.3.4" />
<PackageReference Include="NStandard" Version="0.83.1" />
<PackageReference Include="NWin32" Version="1.2.8" />
<PackageReference Include="System.Management" Version="9.0.0" />
<PackageReference Include="TaskScheduler" Version="2.11.0" />
</ItemGroup>
<ItemGroup>
<Page Include="XForms\ColorProfileWindow.xaml">
+297
View File
@@ -0,0 +1,297 @@
using ColorControl.Shared.Common;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Concurrent;
using System.Net.Security;
using System.Net.WebSockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace LgTv
{
public class SendMessageExceptionCws : Exception
{
public SendMessageExceptionCws(string message, Exception e) : base(message, e)
{
}
}
public delegate void IsConnectedDelegateCws(bool status);
public class LgTvApiCoreCws : IAsyncDisposable
{
public bool ConnectionClosed { get; private set; }
private ClientWebSocket _clientWebSocket;
private int _commandCount;
private Uri _uri;
public event IsConnectedDelegateCws IsConnected;
private readonly ConcurrentDictionary<string, TaskCompletionSource<dynamic>> _tokens = new ConcurrentDictionary<string, TaskCompletionSource<dynamic>>();
private readonly ConcurrentDictionary<string, Func<dynamic, bool>> _callbacks = new ConcurrentDictionary<string, Func<dynamic, bool>>();
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public async Task<bool> Connect(Uri uri, bool ignoreReceiver = false)
{
_uri = uri;
try
{
ConnectionClosed = false;
_commandCount = 0;
CreateWebSocket();
try
{
await _clientWebSocket.ConnectAsync(uri, CancellationToken.None).WaitAsync(TimeSpan.FromMilliseconds(5000));
ConnectionClosed = false;
var _ = Receive(false);
IsConnected?.Invoke(true);
return true;
}
catch (TimeoutException te)
{
Logger.Error($"Timeout while connecting to {uri}: {te.Message}");
return false;
}
}
catch (Exception e)
{
Logger.Error($"Connect to {uri}: {e.Message}");
return false;
}
}
private void CreateWebSocket()
{
_clientWebSocket = new ClientWebSocket();
_clientWebSocket.Options.RemoteCertificateValidationCallback += CertificationValidationCallback;
}
private bool CertificationValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors policyErrors) => true;
public async Task SendMessageAsync(string message, bool reconnect = true)
{
try
{
if (_clientWebSocket?.State != WebSocketState.Open)
{
throw new InvalidOperationException("Socket not open");
}
var bytes = UTF8Encoding.UTF8.GetBytes(message);
var data = bytes.AsMemory();
await _clientWebSocket.SendAsync(data, WebSocketMessageType.Text, true, CancellationToken.None);
}
catch (WebSocketException)
{
if (reconnect && await Connect(_uri))
{
await SendMessageAsync(message, false);
}
}
catch (Exception e)
{
Logger.Error("SendMessageAsync: " + e.Message);
ConnectionClosed = true;
}
}
public async Task<dynamic> SendCommandAsync(string message)
{
var obj = JsonConvert.DeserializeObject<dynamic>(message);
return await SendCommandAsync((string)obj.id, message);
}
private async Task<dynamic> SendCommandAsync(string id, string message)
{
try
{
var taskSource = new TaskCompletionSource<dynamic>();
_tokens.TryAdd(id, taskSource);
await SendMessageAsync(message);
if (ConnectionClosed)
{
throw new Exception("Connection closed");
}
return await taskSource.Task;
}
catch (Exception e)
{
throw new SendMessageExceptionCws("Can't send message", e);
}
}
public async Task<dynamic> SendCommandAsync(RequestMessage message)
{
var rawMessage = new RawRequestMessage(message, ++_commandCount);
var serialized = JsonConvert.SerializeObject(rawMessage, new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
return await SendCommandAsync(rawMessage.Id, serialized);
}
public async Task<dynamic> SubscribeAsync(RequestMessage message, Func<dynamic, bool> callback)
{
var rawMessage = new RawRequestMessage(message, ++_commandCount);
var serialized = JsonConvert.SerializeObject(rawMessage, new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
_callbacks.TryAdd(rawMessage.Id, callback);
return await SendCommandAsync(rawMessage.Id, serialized);
}
private async Task Receive(bool singleResponse)
{
var dataPerPacket = 8 * 1024; //8192
var strBuilder = new StringBuilder();
var buffer = new ArraySegment<byte>(new byte[dataPerPacket]);
try
{
while (_clientWebSocket?.State == WebSocketState.Open)
{
var receiveResult = await _clientWebSocket.ReceiveAsync(buffer, CancellationToken.None);
strBuilder.Append(Encoding.UTF8.GetString(buffer.Array, buffer.Offset, receiveResult.Count));
//keep doing until end of message
while (!receiveResult.EndOfMessage)
{
receiveResult = await _clientWebSocket.ReceiveAsync(buffer, CancellationToken.None);
strBuilder.Append(Encoding.UTF8.GetString(buffer.Array, buffer.Offset, receiveResult.Count));
}
var message = strBuilder.ToString();
strBuilder.Clear();
HandleMessage(message);
if (singleResponse)
{
return;
}
}
}
catch (Exception)
{
ConnectionClosed = true;
Logger.Debug("Connection closed");
IsConnected?.Invoke(false);
}
}
public void HandleMessage(string message)
{
try
{
var obj = JsonConvert.DeserializeObject<dynamic>(message);
var id = (string)obj.id;
var type = (string)obj.type;
TaskCompletionSource<dynamic> taskCompletion;
if (type == "registered")
{
if (_tokens.TryRemove(id, out taskCompletion))
{
var key = (string)JObject.Parse(message)["payload"]["client-key"];
taskCompletion.TrySetResult(new { clientKey = key });
}
}
else if (_tokens.TryGetValue(id, out taskCompletion))
{
if (id == "register_0")
{
//taskCompletion.TrySetResult(obj.payload);
return;
}
if (obj.type == "error")
{
taskCompletion.SetException(new Exception(obj.error?.ToString()));
}
//else if (args.Cancelled)
//{
// taskSource.SetCanceled();
//}
taskCompletion.TrySetResult(obj.payload);
if (_callbacks.TryGetValue(id, out Func<dynamic, bool> callback))
{
try
{
callback(obj.payload);
}
catch (Exception callbackException)
{
Logger.Error($"Connection_MessageReceived: the callback threw an exception: {callbackException.ToLogString()}");
}
}
}
}
catch (Exception ex)
{
Logger.Error($"HandleMessage: status: {_clientWebSocket.State}, exception: {ex.ToLogString()}");
SetExceptionOnAllTokens(ex);
ConnectionClosed = true;
}
}
public async ValueTask DisposeAsync()
{
if (_clientWebSocket != null)
{
if (_clientWebSocket.State == WebSocketState.Open)
{
try
{
await _clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None);
}
catch { }
}
_clientWebSocket?.Dispose();
}
GC.SuppressFinalize(this);
}
private void SetExceptionOnAllTokens(Exception ex)
{
//Logger.Debug($"Tokens: {_tokens.Count}");
foreach (var taskCompletion in _tokens.Values)
{
try
{
if (taskCompletion.Task.Status != TaskStatus.RanToCompletion)
{
Logger.Debug("taskCompletion.Task.Status: " + taskCompletion.Task.Status);
taskCompletion.SetException(new Exception(ex.Message));
}
}
catch (Exception ex2)
{
Logger.Error("SetExceptionOnAllTokens: " + ex2.Message);
}
}
_tokens.Clear();
}
}
}
File diff suppressed because it is too large. Load diff
+27 -6
View File
@@ -38,6 +38,7 @@ namespace ColorControl.Services.Common
protected int _quickAccessShortcutId;
protected GlobalContext _globalContext;
private KeyboardShortcutDispatcher _keyboardShortcutDispatcher;
private List<JsonConverter> _jsonConverters;
@@ -147,28 +148,33 @@ namespace ColorControl.Services.Common
return await ApplyPresetUi(preset);
}
private void LoadServices()
{
_keyboardShortcutDispatcher ??= _globalContext.ServiceProvider.GetService<KeyboardShortcutDispatcher>();
}
protected void SetShortcuts(int quickAccessShortcutId = 0, string shortcut = null)
{
_quickAccessShortcutId = quickAccessShortcutId;
var keyboardShortcutDispatcher = _globalContext.ServiceProvider.GetService<KeyboardShortcutDispatcher>();
LoadServices();
if (keyboardShortcutDispatcher == null)
if (_keyboardShortcutDispatcher == null)
{
return;
}
if (quickAccessShortcutId != 0)
{
keyboardShortcutDispatcher.RegisterShortcut(quickAccessShortcutId, shortcut);
_keyboardShortcutDispatcher.RegisterShortcut(quickAccessShortcutId, shortcut);
}
foreach (var preset in _presets)
{
keyboardShortcutDispatcher.RegisterShortcut(preset.id, preset.shortcut);
_keyboardShortcutDispatcher.RegisterShortcut(preset.id, preset.shortcut);
}
keyboardShortcutDispatcher.RegisterAsyncEventHandler(KeyboardShortcutDispatcher.Event_HotKey, HotKeyPressed);
_keyboardShortcutDispatcher.RegisterAsyncEventHandler(KeyboardShortcutDispatcher.Event_HotKey, HotKeyPressed);
}
public virtual void InstallEventHandlers()
@@ -288,8 +294,23 @@ namespace ColorControl.Services.Common
}
protected void SavePresets()
protected void ValidatePreset(PresetBase preset)
{
if (!KeyboardShortcutDispatcher.ValidateShortcut(preset.shortcut, false))
{
throw new InvalidOperationException("Invalid shortcut");
}
}
protected void SavePresets(PresetBase updatedPreset = null)
{
if (updatedPreset != null)
{
LoadServices();
_keyboardShortcutDispatcher?.RegisterShortcut(updatedPreset.id, updatedPreset.shortcut);
}
Utils.WriteObject(_presetsFilename, _presets);
}
+368 -366
View File
@@ -15,370 +15,372 @@ using System.Threading.Tasks;
namespace ColorControl.Services.GameLauncher
{
class GameService : ServiceBase<GamePreset>
{
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public override string ServiceName => "Game";
protected override string PresetsBaseFilename => "GamePresets.json";
private ProcessEventDispatcher _processEventDispatcher;
private readonly WinApiAdminService _winApiAdminService;
private readonly WinApiService _winApiService;
private ServiceManager _serviceManager;
private int _lastStartedProcessId;
private System.DateTime _lastStartedPresetDateTime = System.DateTime.MinValue;
private string _lastStartedProcessPath;
private string _configFilename;
public GameServiceConfig Config { get; private set; }
public static readonly int SHORTCUTID_GAMEQA = -203;
public GameService(GlobalContext globalContext, ServiceManager serviceManager, ProcessEventDispatcher processEventDispatcher, WinApiAdminService winApiAdminService, WinApiService winApiService) : base(globalContext)
{
LoadConfig();
LoadPresets();
_serviceManager = serviceManager;
_processEventDispatcher = processEventDispatcher;
_winApiAdminService = winApiAdminService;
_winApiService = winApiService;
_processEventDispatcher.RegisterAsyncEventHandler(ProcessEventDispatcher.Event_ProcessChanged, ProcessChanged);
}
public override void InstallEventHandlers()
{
base.InstallEventHandlers();
SetShortcuts(SHORTCUTID_GAMEQA, Config.QuickAccessShortcut);
}
public override List<string> GetInfo()
{
return [$"{_presets.Count} presets"];
}
private async Task ProcessChanged(object sender, ProcessChangedEventArgs e, CancellationToken token)
{
if (e.StartedProcesses?.Any() != true || !Config.ApplyExternallyLaunched)
{
return;
}
if (_lastStartedPresetDateTime > System.DateTime.Now.AddSeconds(-5))
{
return;
}
_lastStartedProcessId = 0;
var startedProcesses = e.StartedProcesses;
foreach (var startedProcess in startedProcesses)
{
try
{
if (await HandleStartedProcess(startedProcess))
{
return;
}
}
catch (System.Exception) { }
}
}
private Task<bool> HandleStartedProcess(Process process)
{
GamePreset preset;
if (_winApiService.IsAdministrator())
{
var mainModule = process.MainModule;
if (mainModule == null)
{
return Task.FromResult(false);
}
var fileName = mainModule.FileName;
preset = _presets.FirstOrDefault(p => fileName.Contains(Path.GetDirectoryName(p.Path), System.StringComparison.OrdinalIgnoreCase));
}
else
{
var name = process.ProcessName.Replace("-Win64-Shipping", "");
preset = _presets.FirstOrDefault(p => Path.GetFileName(p.Path).Contains(name, System.StringComparison.OrdinalIgnoreCase));
}
if (preset == null || !preset.AutoSettings.AllowAutoApply)
{
return Task.FromResult(false);
}
if (_lastStartedProcessId != process.Id)
{
Logger.Debug($"Auto-starting preset {preset.name} for process {process.ProcessName}");
var mainThreadId = 0;
var suspended = false;
if (preset.AutoSettings.ProcessAutoAction == ProcessAutoAction.Suspend)
{
mainThreadId = _winApiAdminService.SuspendMainThread(process.Id);
suspended = true;
}
else if (preset.AutoSettings.ProcessAutoAction == ProcessAutoAction.Restart)
{
_winApiAdminService.StopProcess(process.Id);
process = null;
}
var _ = ExecutePreset(preset, process, suspended ? mainThreadId : 0);
return Task.FromResult(true);
}
return Task.FromResult(false);
}
protected override List<GamePreset> GetDefaultPresets()
{
return new List<GamePreset>();
}
public void GlobalSave()
{
SavePresets();
SaveConfig();
}
public override async Task<bool> ApplyPreset(GamePreset preset)
{
var result = await ExecutePreset(preset);
_lastAppliedPreset = preset;
PresetApplied();
return result;
}
private async Task<bool> ExecutePreset(GamePreset preset, Process process = null, int resumeThreadId = default)
{
var result = true;
await ExecuteSteps(preset.PreLaunchSteps);
if (process == null && !string.IsNullOrEmpty(preset.Path))
{
process = _winApiAdminService.StartProcess(preset.Path, preset.Parameters, setWorkingDir: true, elevate: preset.RunAsAdministrator, affinityMask: preset.ProcessAffinityMask, priorityClass: preset.ProcessPriorityClass);
_lastStartedPresetDateTime = System.DateTime.Now;
_lastStartedProcessId = process.Id;
_lastStartedProcessPath = Path.GetDirectoryName(preset.Path);
}
else if (resumeThreadId != default)
{
_winApiAdminService.ResumeThread((uint)resumeThreadId);
}
await ExecuteSteps(preset.PostLaunchSteps);
if (process != null && preset.FinalizeSteps?.Any() == true)
{
await ExecuteFinalizationStepsAsync(process, preset.FinalizeSteps);
}
return result;
}
private async Task ExecuteFinalizationStepsAsync(Process process, List<string> finalizeSteps)
{
await Task.Delay(1000);
try
{
if (process.HasExited)
{
return;
}
await process.WaitForExitAsync();
}
catch (Exception ex)
{
Logger.Error(ex);
return;
}
await ExecuteSteps(finalizeSteps);
}
private async Task ExecuteSteps(List<string> steps)
{
if (steps?.Any() != true)
{
return;
}
foreach (var step in steps)
{
var keySpec = step.Split(':');
var delay = 0;
var key = step;
if (keySpec.Length == 2)
{
delay = Utils.ParseInt(keySpec[1]);
if (delay > 0)
{
key = keySpec[0];
}
}
var index = key.IndexOf("(");
string[] parameters = null;
if (index > -1)
{
var keyValue = key.Split('(');
key = keyValue[0];
parameters = keyValue[1].Substring(0, keyValue[1].Length - 1).Trim().Split(';');
}
var handled = false;
if (parameters != null)
{
handled = await _serviceManager.HandleExternalServiceAsync(key, parameters);
}
if (!handled)
{
}
if (delay > 0)
{
await Task.Delay(delay);
}
}
}
private void LoadConfig()
{
_configFilename = Path.Combine(_dataPath, "GameConfig.json");
try
{
if (File.Exists(_configFilename))
{
Config = JsonConvert.DeserializeObject<GameServiceConfig>(File.ReadAllText(_configFilename));
}
}
catch (System.Exception ex)
{
Logger.Error($"LoadConfig: {ex.Message}");
}
Config ??= new GameServiceConfig();
}
private void SaveConfig()
{
Utils.WriteObject(_configFilename, Config);
}
public GameServiceConfig GetConfig()
{
return Config;
}
public bool UpdateConfig(GameServiceConfig config)
{
Config.Update(config);
SetShortcuts(SHORTCUTID_GAMEQA, Config.QuickAccessShortcut);
SaveConfig();
return true;
}
public bool UpdatePreset(GamePreset presetSpec)
{
var preset = _presets.FirstOrDefault(x => x.id == presetSpec.id);
if (preset != null)
{
preset.Update(presetSpec);
}
else
{
preset = new GamePreset(presetSpec);
_presets.Add(preset);
}
SavePresets();
return true;
}
public string SelectPath()
{
var fileInfo = Utils.SelectFile();
if (fileInfo == null)
{
return null;
}
return fileInfo.FullName;
}
public List<GameApp> GetMruApps(bool skipExistingPresets = false)
{
var key = Registry.ClassesRoot.OpenSubKey(@"Local Settings\Software\Microsoft\Windows\Shell\MuiCache");
if (key == null)
{
return new List<GameApp>();
}
var names = key.GetValueNames();
var apps = new List<GameApp>();
var winFolder = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
foreach (var name in names)
{
var parts = name.Split('.');
if (parts.Last() != "FriendlyAppName")
{
continue;
}
var path = name.Replace("." + parts.Last(), "");
if (skipExistingPresets && _presets.Any(p => p.Path.Equals(path, StringComparison.OrdinalIgnoreCase)))
{
continue;
}
if (!path.StartsWith(winFolder) && Path.Exists(path))
{
var friendlyName = key.GetValue(name)?.ToString();
var app = new GameApp
{
Path = path,
Filename = Path.GetFileName(path),
FriendlyName = friendlyName
};
apps.Add(app);
}
}
apps = apps.DistinctBy(a => a.Path).OrderBy(a => a.FriendlyName).ToList();
return apps;
}
}
class GameService : ServiceBase<GamePreset>
{
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public override string ServiceName => "Game";
protected override string PresetsBaseFilename => "GamePresets.json";
private ProcessEventDispatcher _processEventDispatcher;
private readonly WinApiAdminService _winApiAdminService;
private readonly WinApiService _winApiService;
private ServiceManager _serviceManager;
private int _lastStartedProcessId;
private System.DateTime _lastStartedPresetDateTime = System.DateTime.MinValue;
private string _lastStartedProcessPath;
private string _configFilename;
public GameServiceConfig Config { get; private set; }
public static readonly int SHORTCUTID_GAMEQA = -203;
public GameService(GlobalContext globalContext, ServiceManager serviceManager, ProcessEventDispatcher processEventDispatcher, WinApiAdminService winApiAdminService, WinApiService winApiService) : base(globalContext)
{
LoadConfig();
LoadPresets();
_serviceManager = serviceManager;
_processEventDispatcher = processEventDispatcher;
_winApiAdminService = winApiAdminService;
_winApiService = winApiService;
_processEventDispatcher.RegisterAsyncEventHandler(ProcessEventDispatcher.Event_ProcessChanged, ProcessChanged);
}
public override void InstallEventHandlers()
{
base.InstallEventHandlers();
SetShortcuts(SHORTCUTID_GAMEQA, Config.QuickAccessShortcut);
}
public override List<string> GetInfo()
{
return [$"{_presets.Count} presets"];
}
private async Task ProcessChanged(object sender, ProcessChangedEventArgs e, CancellationToken token)
{
if (e.StartedProcesses?.Any() != true || !Config.ApplyExternallyLaunched)
{
return;
}
if (_lastStartedPresetDateTime > System.DateTime.Now.AddSeconds(-5))
{
return;
}
_lastStartedProcessId = 0;
var startedProcesses = e.StartedProcesses;
foreach (var startedProcess in startedProcesses)
{
try
{
if (await HandleStartedProcess(startedProcess))
{
return;
}
}
catch (System.Exception) { }
}
}
private Task<bool> HandleStartedProcess(Process process)
{
GamePreset preset;
if (_winApiService.IsAdministrator())
{
var mainModule = process.MainModule;
if (mainModule == null)
{
return Task.FromResult(false);
}
var fileName = mainModule.FileName;
preset = _presets.FirstOrDefault(p => fileName.Contains(Path.GetDirectoryName(p.Path), System.StringComparison.OrdinalIgnoreCase));
}
else
{
var name = process.ProcessName.Replace("-Win64-Shipping", "");
preset = _presets.FirstOrDefault(p => Path.GetFileName(p.Path).Contains(name, System.StringComparison.OrdinalIgnoreCase));
}
if (preset == null || !preset.AutoSettings.AllowAutoApply)
{
return Task.FromResult(false);
}
if (_lastStartedProcessId != process.Id)
{
Logger.Debug($"Auto-starting preset {preset.name} for process {process.ProcessName}");
var mainThreadId = 0;
var suspended = false;
if (preset.AutoSettings.ProcessAutoAction == ProcessAutoAction.Suspend)
{
mainThreadId = _winApiAdminService.SuspendMainThread(process.Id);
suspended = true;
}
else if (preset.AutoSettings.ProcessAutoAction == ProcessAutoAction.Restart)
{
_winApiAdminService.StopProcess(process.Id);
process = null;
}
var _ = ExecutePreset(preset, process, suspended ? mainThreadId : 0);
return Task.FromResult(true);
}
return Task.FromResult(false);
}
protected override List<GamePreset> GetDefaultPresets()
{
return new List<GamePreset>();
}
public void GlobalSave()
{
SavePresets();
SaveConfig();
}
public override async Task<bool> ApplyPreset(GamePreset preset)
{
var result = await ExecutePreset(preset);
_lastAppliedPreset = preset;
PresetApplied();
return result;
}
private async Task<bool> ExecutePreset(GamePreset preset, Process process = null, int resumeThreadId = default)
{
var result = true;
await ExecuteSteps(preset.PreLaunchSteps);
if (process == null && !string.IsNullOrEmpty(preset.Path))
{
process = _winApiAdminService.StartProcess(preset.Path, preset.Parameters, setWorkingDir: true, elevate: preset.RunAsAdministrator, affinityMask: preset.ProcessAffinityMask, priorityClass: preset.ProcessPriorityClass);
_lastStartedPresetDateTime = System.DateTime.Now;
_lastStartedProcessId = process.Id;
_lastStartedProcessPath = Path.GetDirectoryName(preset.Path);
}
else if (resumeThreadId != default)
{
_winApiAdminService.ResumeThread((uint)resumeThreadId);
}
await ExecuteSteps(preset.PostLaunchSteps);
if (process != null && preset.FinalizeSteps?.Any() == true)
{
await ExecuteFinalizationStepsAsync(process, preset.FinalizeSteps);
}
return result;
}
private async Task ExecuteFinalizationStepsAsync(Process process, List<string> finalizeSteps)
{
await Task.Delay(1000);
try
{
if (process.HasExited)
{
return;
}
await process.WaitForExitAsync();
}
catch (Exception ex)
{
Logger.Error(ex);
return;
}
await ExecuteSteps(finalizeSteps);
}
private async Task ExecuteSteps(List<string> steps)
{
if (steps?.Any() != true)
{
return;
}
foreach (var step in steps)
{
var keySpec = step.Split(':');
var delay = 0;
var key = step;
if (keySpec.Length == 2)
{
delay = Utils.ParseInt(keySpec[1]);
if (delay > 0)
{
key = keySpec[0];
}
}
var index = key.IndexOf("(");
string[] parameters = null;
if (index > -1)
{
var keyValue = key.Split('(');
key = keyValue[0];
parameters = keyValue[1].Substring(0, keyValue[1].Length - 1).Trim().Split(';');
}
var handled = false;
if (parameters != null)
{
handled = await _serviceManager.HandleExternalServiceAsync(key, parameters);
}
if (!handled)
{
}
if (delay > 0)
{
await Task.Delay(delay);
}
}
}
private void LoadConfig()
{
_configFilename = Path.Combine(_dataPath, "GameConfig.json");
try
{
if (File.Exists(_configFilename))
{
Config = JsonConvert.DeserializeObject<GameServiceConfig>(File.ReadAllText(_configFilename));
}
}
catch (System.Exception ex)
{
Logger.Error($"LoadConfig: {ex.Message}");
}
Config ??= new GameServiceConfig();
}
private void SaveConfig()
{
Utils.WriteObject(_configFilename, Config);
}
public GameServiceConfig GetConfig()
{
return Config;
}
public bool UpdateConfig(GameServiceConfig config)
{
Config.Update(config);
SetShortcuts(SHORTCUTID_GAMEQA, Config.QuickAccessShortcut);
SaveConfig();
return true;
}
public bool UpdatePreset(GamePreset specPreset)
{
ValidatePreset(specPreset);
var preset = _presets.FirstOrDefault(x => x.id == specPreset.id);
if (preset != null)
{
preset.Update(specPreset);
}
else
{
preset = new GamePreset(specPreset);
_presets.Add(preset);
}
SavePresets(preset);
return true;
}
public string SelectPath()
{
var fileInfo = Utils.SelectFile();
if (fileInfo == null)
{
return null;
}
return fileInfo.FullName;
}
public List<GameApp> GetMruApps(bool skipExistingPresets = false)
{
var key = Registry.ClassesRoot.OpenSubKey(@"Local Settings\Software\Microsoft\Windows\Shell\MuiCache");
if (key == null)
{
return new List<GameApp>();
}
var names = key.GetValueNames();
var apps = new List<GameApp>();
var winFolder = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
foreach (var name in names)
{
var parts = name.Split('.');
if (parts.Last() != "FriendlyAppName")
{
continue;
}
var path = name.Replace("." + parts.Last(), "");
if (skipExistingPresets && _presets.Any(p => p.Path.Equals(path, StringComparison.OrdinalIgnoreCase)))
{
continue;
}
if (!path.StartsWith(winFolder) && Path.Exists(path))
{
var friendlyName = key.GetValue(name)?.ToString();
var app = new GameApp
{
Path = path,
Filename = Path.GetFileName(path),
FriendlyName = friendlyName
};
apps.Add(app);
}
}
apps = apps.DistinctBy(a => a.Path).OrderBy(a => a.FriendlyName).ToList();
return apps;
}
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+15 -11
View File
@@ -300,6 +300,8 @@ namespace ColorControl.Services.NVIDIA
public bool UpdatePreset(NvPreset specPreset)
{
ValidatePreset(specPreset);
var currentPreset = _presets.FirstOrDefault(p => p.id == specPreset.id);
if (currentPreset != null)
@@ -308,7 +310,7 @@ namespace ColorControl.Services.NVIDIA
currentPreset.shortcut = specPreset.shortcut;
currentPreset.Update(specPreset);
SavePresets();
SavePresets(currentPreset);
return true;
}
@@ -319,7 +321,7 @@ namespace ColorControl.Services.NVIDIA
_presets.Add(newPreset);
SavePresets();
SavePresets(newPreset);
return true;
}
@@ -858,13 +860,7 @@ namespace ColorControl.Services.NVIDIA
var gpuHandle = displayDevice.PhysicalGPU.Handle;
var displayId = displayDevice.DisplayId;
if (state == NvDitherState.Auto)
{
// These seem to be ignored in Auto-state
bits = 0;
mode = 0;
}
else if (preset != null)
if (preset != null)
{
bits = preset.ditheringBits;
mode = preset.ditheringMode;
@@ -873,6 +869,13 @@ namespace ColorControl.Services.NVIDIA
restartDriver |= preset.RestartDriver;
}
if (state == NvDitherState.Auto)
{
// These seem to be ignored in Auto-state
bits = 0;
mode = 0;
}
if (setRegistryKey)
{
var info = CCD.GetDisplayInfo(display.Name);
@@ -1566,7 +1569,7 @@ namespace ColorControl.Services.NVIDIA
return _meta.GetSettingMeta(settingId);
}
public List<NvSettingItemDto> GetDriverSettings(string profileName = null)
public List<NvSettingItemDto> GetDriverSettings(string profileName = null, bool addFriendlyName = false)
{
if (profileName == null)
{
@@ -1599,7 +1602,8 @@ namespace ColorControl.Services.NVIDIA
Value = intValue.intValue,
DefaultValue = intValue.defaultValue,
SettingType = type,
Values = values?.ToList()
Values = values?.ToList(),
FriendlyName = addFriendlyName ? $"{settingMeta.SettingName}: {settingMeta.ToFriendlyName(intValue: intValue.intValue, displayDefault: true)}" : null
};
}).ToList();
}
+102 -213
View File
@@ -1,13 +1,11 @@
using ColorControl.Shared.Common;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Net.Security;
using System.Net.WebSockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.Networking.Sockets;
using Windows.Security.Cryptography.Certificates;
using Windows.Storage.Streams;
namespace ColorControl.Services.Samsung
{
@@ -21,72 +19,53 @@ namespace ColorControl.Services.Samsung
public delegate void ConnectedDelegate(string token, bool disconnect);
public class SamTvConnection : IDisposable
public class SamTvConnection : IAsyncDisposable
{
public static SynchronizationContext SyncContext { get; set; }
public bool? ConnectionClosed { get; private set; }
public bool ClosedByDispose { get; private set; }
private MessageWebSocket _connection;
private DataWriter _messageWriter;
private ClientWebSocket _clientWebSocket;
private int _commandCount;
private int _readTimeout;
private Uri _uri;
public event ConnectedDelegate Connected;
private readonly ConcurrentDictionary<string, TaskCompletionSource<dynamic>> _tokens = new ConcurrentDictionary<string, TaskCompletionSource<dynamic>>();
private readonly ConcurrentDictionary<string, Func<dynamic, bool>> _callbacks = new ConcurrentDictionary<string, Func<dynamic, bool>>();
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public async Task<bool> Connect(Uri uri, int readTimeout = 5000)
public async Task<bool> Connect(Uri uri, int connectTimeout = 5000)
{
_readTimeout = readTimeout;
_uri = uri;
try
{
_connection?.Dispose();
_clientWebSocket?.Dispose();
_commandCount = 0;
// Not creating the web socket from main thread can cause a stackoverflow in combase32.dll
if (Environment.CurrentManagedThreadId != 1)
{
SyncContext.Send((_) => CreateWebSocket(), null);
}
else
{
CreateWebSocket();
}
CreateWebSocket();
try
{
await _connection.ConnectAsync(uri).AsTask().WaitAsync(TimeSpan.FromSeconds(5));
Logger.Debug($"Connecting to {uri}");
await _clientWebSocket.ConnectAsync(uri, CancellationToken.None).WaitAsync(TimeSpan.FromMilliseconds(connectTimeout));
Logger.Debug($"Connected to {uri}");
ConnectionClosed = false;
_messageWriter = new DataWriter(_connection.OutputStream);
await Receive(true);
Logger.Debug("Received");
return true;
}
catch (TimeoutException te)
{
Logger.Error($"Connect to {uri}: {te.Message}");
Logger.Error($"Timeout while connecting to {uri}: {te.Message}");
return false;
}
}
catch (Exception e)
{
switch (SocketError.GetStatus(e.HResult))
{
case SocketErrorStatus.HostNotFound:
// Handle HostNotFound Error
break;
default:
// Handle Unknown Error
break;
}
Logger.Error($"Connect to {uri}: {e.Message}");
return false;
}
@@ -94,63 +73,50 @@ namespace ColorControl.Services.Samsung
private void CreateWebSocket()
{
_connection = new MessageWebSocket();
_connection.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
_connection.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
_connection.Control.MessageType = SocketMessageType.Utf8;
_connection.MessageReceived += Connection_MessageReceived;
_connection.Closed += Connection_Closed;
_clientWebSocket = new ClientWebSocket();
_clientWebSocket.Options.RemoteCertificateValidationCallback += CertificationValidationCallback;
}
public async Task SendMessageAsync(string message)
private bool CertificationValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors policyErrors) => true;
public async Task SendMessageAsync(string message, bool reconnect = true)
{
try
{
if (_messageWriter == null)
if (_clientWebSocket?.State != WebSocketState.Open)
{
throw new Exception("SendMessageAsync: no writer");
throw new InvalidOperationException("Socket not open");
}
var bytes = UTF8Encoding.UTF8.GetBytes(message);
var data = bytes.AsMemory();
_messageWriter.WriteString(message);
await _messageWriter.StoreAsync().AsTask().WaitAsync(TimeSpan.FromSeconds(5));
await _clientWebSocket.SendAsync(data, WebSocketMessageType.Text, true, CancellationToken.None);
}
catch (WebSocketException)
{
if (reconnect && await Connect(_uri))
{
await SendMessageAsync(message, false);
}
}
catch (Exception e)
{
Logger.Error("SendMessageAsync: " + e.Message);
ConnectionClosed = true;
_messageWriter?.Dispose();
}
}
private async Task<dynamic> SendCommandAsync(string id, string message, bool waitForAnswer = true)
private async Task<dynamic> SendCommandAsync(string message)
{
try
{
if (waitForAnswer)
await SendMessageAsync(message);
if (ConnectionClosed == true)
{
var taskSource = new TaskCompletionSource<dynamic>();
_tokens.TryAdd(id, taskSource);
await SendMessageAsync(message);
if (ConnectionClosed == true)
{
throw new Exception("Connection closed");
}
return await taskSource.Task;
}
else
{
await SendMessageAsync(message);
if (ConnectionClosed == true)
{
throw new Exception("Connection closed");
}
return null;
throw new Exception("Connection closed");
}
return null;
}
catch (Exception e)
{
@@ -158,7 +124,7 @@ namespace ColorControl.Services.Samsung
}
}
public async Task<dynamic> SendCommandAsync(RequestMessage message, bool waitForAnswer = true)
public async Task<dynamic> SendCommandAsync(RequestMessage message)
{
var rawMessage = new RawRequestMessage(message, ++_commandCount);
var serialized = JsonConvert.SerializeObject(rawMessage, new JsonSerializerSettings()
@@ -166,32 +132,7 @@ namespace ColorControl.Services.Samsung
NullValueHandling = NullValueHandling.Ignore,
//ContractResolver = new CamelCasePropertyNamesContractResolver()
});
return await SendCommandAsync(rawMessage.Id, serialized, waitForAnswer);
}
public async Task<dynamic> SubscribeAsync(RequestMessage message, Func<dynamic, bool> callback)
{
var rawMessage = new RawRequestMessage(message, ++_commandCount);
var serialized = JsonConvert.SerializeObject(rawMessage, new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
_callbacks.TryAdd(rawMessage.Id, callback);
return await SendCommandAsync(rawMessage.Id, serialized);
}
private void Connection_Closed(IWebSocket sender, WebSocketClosedEventArgs args)
{
var webSocket = Interlocked.Exchange(ref _connection, null);
webSocket?.Dispose();
ConnectionClosed = true;
Logger.Debug("Connection closed");
Connected?.Invoke(null, true);
return await SendCommandAsync(serialized);
}
private const string MS_CHANNEL_CONNECT_EVENT = "ms.channel.connect";
@@ -201,128 +142,76 @@ namespace ColorControl.Services.Samsung
private const string MS_CHANNEL_UNAUTHORIZED = "ms.channel.unauthorized";
private const string MS_ERROR_EVENT = "ms.error";
private async void Connection_MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
private async Task Receive(bool singleResponse)
{
try
{
var task = new Task<DataReader>(args.GetDataReader);
task.Start();
var dataReader = await task.WaitAsync(TimeSpan.FromMilliseconds(_readTimeout));
var dataPerPacket = 8 * 1024; //8192
var strBuilder = new StringBuilder();
var buffer = new ArraySegment<byte>(new byte[dataPerPacket]);
using (dataReader)
while (_clientWebSocket?.State == WebSocketState.Open)
{
var receiveResult = await _clientWebSocket.ReceiveAsync(buffer, CancellationToken.None);
strBuilder.Append(Encoding.UTF8.GetString(buffer.Array, buffer.Offset, receiveResult.Count));
//keep doing until end of message
while (!receiveResult.EndOfMessage)
{
dataReader.UnicodeEncoding = UnicodeEncoding.Utf8;
var message = dataReader.ReadString(dataReader.UnconsumedBufferLength);
var obj = JsonConvert.DeserializeObject<dynamic>(message);
var id = (string)obj.id;
var type = (string)obj.@event;
Logger.Debug($"Received message: {message}");
// Response:
// {"data":{"clients":[{"attributes":{"name":"c2Ftc3VuZ2N0bA=="},"connectTime":1685302606520,"deviceName":"c2Ftc3VuZ2N0bA==","id":"92e0cbc1-6f86-4013-9b9b-65a47afb2236","isHost":false}],"id":"92e0cbc1-6f86-4013-9b9b-65a47afb2236","token":"16224598"},"event":"ms.channel.connect"}
// Second response:
// {"data":{"clients":[{"attributes":{"name":"c2Ftc3VuZ2N0bA==","token":"16224598"},"connectTime":1685303321571,"deviceName":"c2Ftc3VuZ2N0bA==","id":"58589451-2ecf-44f0-9267-31983a5466","isHost":false}],"id":"58589451-2ecf-44f0-9267-31983a5466"},"event":"ms.channel.connect"}
//TaskCompletionSource<dynamic> taskCompletion;
if (type == MS_CHANNEL_CONNECT_EVENT)
{
var token = (string)obj.data?.token;
if (token == null)
{
token = (string)obj.data?.clients[0]?.attributes?.token;
}
if (token != null)
{
Connected?.Invoke(token, false);
}
//if (_tokens.TryRemove(id, out taskCompletion))
//{
// var key = (string)JObject.Parse(message)["payload"]["client-key"];
// taskCompletion.TrySetResult(new { clientKey = key });
//}
}
else
{
}
//else if (_tokens.TryGetValue(id, out taskCompletion))
//{
// if (id == "register_0") return;
// if (obj.type == "error")
// {
// taskCompletion.SetException(new Exception(obj.error?.ToString()));
// }
// //else if (args.Cancelled)
// //{
// // taskSource.SetCanceled();
// //}
// taskCompletion.TrySetResult(obj.payload);
// if (_callbacks.TryGetValue(id, out Func<dynamic, bool> callback))
// {
// try
// {
// callback(obj.payload);
// }
// catch (Exception callbackException)
// {
// Logger.Error($"Connection_MessageReceived: the callback threw an exception: {callbackException.ToLogString()}");
// }
// }
//}
receiveResult = await _clientWebSocket.ReceiveAsync(buffer, CancellationToken.None);
strBuilder.Append(Encoding.UTF8.GetString(buffer.Array, buffer.Offset, receiveResult.Count));
}
}
catch (Exception ex)
{
var status = WebSocketError.GetStatus(ex.GetBaseException().HResult);
Logger.Error($"Connection_MessageReceived: status: {status}, exception: {ex.ToLogString()}");
SetExceptionOnAllTokens(ex);
var message = strBuilder.ToString();
strBuilder.Clear();
ConnectionClosed = true;
var obj = JsonConvert.DeserializeObject<dynamic>(message);
var id = (string)obj.id;
var type = (string)obj.@event;
_messageWriter?.Dispose();
// Response:
// {"data":{"clients":[{"attributes":{"name":"c2Ftc3VuZ2N0bA=="},"connectTime":1685302606520,"deviceName":"c2Ftc3VuZ2N0bA==","id":"92e0cbc1-6f86-4013-9b9b-65a47afb2236","isHost":false}],"id":"92e0cbc1-6f86-4013-9b9b-65a47afb2236","token":"16224598"},"event":"ms.channel.connect"}
// Second response:
// {"data":{"clients":[{"attributes":{"name":"c2Ftc3VuZ2N0bA==","token":"16224598"},"connectTime":1685303321571,"deviceName":"c2Ftc3VuZ2N0bA==","id":"58589451-2ecf-44f0-9267-31983a5466","isHost":false}],"id":"58589451-2ecf-44f0-9267-31983a5466"},"event":"ms.channel.connect"}
if (type == MS_CHANNEL_CONNECT_EVENT)
{
var token = (string)obj.data?.token;
if (token == null)
{
token = (string)obj.data?.clients[0]?.attributes?.token;
}
if (token != null)
{
Connected?.Invoke(token, false);
}
}
if (singleResponse)
{
return;
}
}
}
private void SetExceptionOnAllTokens(Exception ex)
{
//Logger.Debug($"Tokens: {_tokens.Count}");
foreach (var taskCompletion in _tokens.Values)
{
try
{
if (taskCompletion.Task.Status != TaskStatus.RanToCompletion)
{
Logger.Debug("taskCompletion.Task.Status: " + taskCompletion.Task.Status);
taskCompletion.SetException(new Exception(ex.Message));
}
}
catch (Exception ex2)
{
Logger.Error("SetExceptionOnAllTokens: " + ex2.Message);
}
}
_tokens.Clear();
}
public void Close()
{
_connection?.Close(1000, "");
}
public void Dispose()
public async ValueTask DisposeAsync()
{
ClosedByDispose = true;
Close();
_connection?.Dispose();
if (_clientWebSocket != null)
{
if (_clientWebSocket.State == WebSocketState.Open)
{
try
{
await _clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None);
}
catch { }
}
_clientWebSocket?.Dispose();
}
GC.SuppressFinalize(this);
}
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
-281
View File
@@ -1,281 +0,0 @@
using ColorControl.Shared.Common;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using Windows.Networking.Sockets;
using Windows.Security.Cryptography.Certificates;
using Windows.Storage.Streams;
namespace LgTv
{
public class SendMessageException : Exception
{
public SendMessageException(string message, Exception e) : base(message, e)
{
}
}
public delegate void IsConnectedDelegate(bool status);
public class LgTvApiCore : IDisposable
{
public static SynchronizationContext SyncContext { get; set; }
public bool ConnectionClosed { get; private set; }
private MessageWebSocket _connection;
private DataWriter _messageWriter;
private int _commandCount;
public event IsConnectedDelegate IsConnected;
private readonly ConcurrentDictionary<string, TaskCompletionSource<dynamic>> _tokens = new ConcurrentDictionary<string, TaskCompletionSource<dynamic>>();
private readonly ConcurrentDictionary<string, Func<dynamic, bool>> _callbacks = new ConcurrentDictionary<string, Func<dynamic, bool>>();
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public async Task<bool> Connect(Uri uri, bool ignoreReceiver = false)
{
try
{
//Logger.Debug($"Connecting from thread: {Environment.CurrentManagedThreadId}");
_connection?.Dispose();
ConnectionClosed = false;
_commandCount = 0;
// Not creating the web socket from main thread can cause a stackoverflow in combase32.dll
if (Environment.CurrentManagedThreadId != 1)
{
SyncContext.Send((_) => CreateWebSocket(), null);
}
else
{
CreateWebSocket();
}
try
{
await _connection.ConnectAsync(uri).AsTask().WaitAsync(TimeSpan.FromSeconds(5));
_messageWriter = new DataWriter(_connection.OutputStream);
IsConnected?.Invoke(true);
return true;
}
catch (TimeoutException te)
{
Logger.Error($"Connect to {uri}: {te.Message}");
return false;
}
}
catch (Exception e)
{
switch (SocketError.GetStatus(e.HResult))
{
case SocketErrorStatus.HostNotFound:
// Handle HostNotFound Error
break;
default:
// Handle Unknown Error
break;
}
Logger.Error($"Connect to {uri}: {e.Message}");
return false;
}
}
private void CreateWebSocket()
{
_connection = new MessageWebSocket();
_connection.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
_connection.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
_connection.Control.MessageType = SocketMessageType.Utf8;
_connection.MessageReceived += Connection_MessageReceived;
_connection.Closed += Connection_Closed;
}
public async Task SendMessageAsync(string message)
{
try
{
if (_messageWriter == null)
{
throw new Exception("SendMessageAsync: no writer");
}
_messageWriter.WriteString(message);
await _messageWriter.StoreAsync().AsTask().WaitAsync(TimeSpan.FromSeconds(5));
}
catch (Exception e)
{
Logger.Error("SendMessageAsync: " + e.Message);
ConnectionClosed = true;
_messageWriter?.Dispose();
}
}
public async Task<dynamic> SendCommandAsync(string message)
{
var obj = JsonConvert.DeserializeObject<dynamic>(message);
return await SendCommandAsync((string)obj.id, message);
}
private async Task<dynamic> SendCommandAsync(string id, string message)
{
try
{
var taskSource = new TaskCompletionSource<dynamic>();
_tokens.TryAdd(id, taskSource);
await SendMessageAsync(message);
if (ConnectionClosed)
{
throw new Exception("Connection closed");
}
return await taskSource.Task;
}
catch (Exception e)
{
throw new SendMessageException("Can't send message", e);
}
}
public async Task<dynamic> SendCommandAsync(RequestMessage message)
{
var rawMessage = new RawRequestMessage(message, ++_commandCount);
var serialized = JsonConvert.SerializeObject(rawMessage, new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
return await SendCommandAsync(rawMessage.Id, serialized);
}
public async Task<dynamic> SubscribeAsync(RequestMessage message, Func<dynamic, bool> callback)
{
var rawMessage = new RawRequestMessage(message, ++_commandCount);
var serialized = JsonConvert.SerializeObject(rawMessage, new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
_callbacks.TryAdd(rawMessage.Id, callback);
return await SendCommandAsync(rawMessage.Id, serialized);
}
private void Connection_Closed(IWebSocket sender, WebSocketClosedEventArgs args)
{
MessageWebSocket webSocket = Interlocked.Exchange(ref _connection, null);
webSocket?.Dispose();
ConnectionClosed = true;
}
private async void Connection_MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
{
try
{
var task = new Task<DataReader>(args.GetDataReader);
task.Start();
var dataReader = await task.WaitAsync(TimeSpan.FromSeconds(5));
using (dataReader)
{
dataReader.UnicodeEncoding = UnicodeEncoding.Utf8;
var message = dataReader.ReadString(dataReader.UnconsumedBufferLength);
var obj = JsonConvert.DeserializeObject<dynamic>(message);
var id = (string)obj.id;
var type = (string)obj.type;
TaskCompletionSource<dynamic> taskCompletion;
if (type == "registered")
{
if (_tokens.TryRemove(id, out taskCompletion))
{
var key = (string)JObject.Parse(message)["payload"]["client-key"];
taskCompletion.TrySetResult(new { clientKey = key });
}
}
else if (_tokens.TryGetValue(id, out taskCompletion))
{
if (id == "register_0") return;
if (obj.type == "error")
{
taskCompletion.SetException(new Exception(obj.error?.ToString()));
}
//else if (args.Cancelled)
//{
// taskSource.SetCanceled();
//}
taskCompletion.TrySetResult(obj.payload);
if (_callbacks.TryGetValue(id, out Func<dynamic, bool> callback))
{
try
{
callback(obj.payload);
}
catch (Exception callbackException)
{
Logger.Error($"Connection_MessageReceived: the callback threw an exception: {callbackException.ToLogString()}");
}
}
}
}
}
catch (Exception ex)
{
var status = WebSocketError.GetStatus(ex.GetBaseException().HResult);
Logger.Error($"Connection_MessageReceived: status: {status}, exception: {ex.ToLogString()}");
SetExceptionOnAllTokens(ex);
ConnectionClosed = true;
_messageWriter?.Dispose();
}
}
private void SetExceptionOnAllTokens(Exception ex)
{
//Logger.Debug($"Tokens: {_tokens.Count}");
foreach (var taskCompletion in _tokens.Values)
{
try
{
if (taskCompletion.Task.Status != TaskStatus.RanToCompletion)
{
Logger.Debug("taskCompletion.Task.Status: " + taskCompletion.Task.Status);
taskCompletion.SetException(new Exception(ex.Message));
}
}
catch (Exception ex2)
{
Logger.Error("SetExceptionOnAllTokens: " + ex2.Message);
}
}
_tokens.Clear();
}
public void Close()
{
_connection?.Close(1, "");
}
public void Dispose()
{
_connection?.Dispose();
}
}
}
+43 -38
View File
@@ -4,49 +4,54 @@ using System.Threading.Tasks;
namespace LgTv
{
public class LgWebOsMouseService : IDisposable
{
private readonly LgTvApiCore _connection;
public class LgWebOsMouseService : IAsyncDisposable
{
private readonly LgTvApiCoreCws _connection;
public LgWebOsMouseService(LgTvApiCore connection)
{
_connection = connection;
}
public LgWebOsMouseService(LgTvApiCoreCws connection)
{
_connection = connection;
}
public async Task<bool> Connect(string uri)
{
var ctx = _connection.Connect(new Uri(uri), ignoreReceiver: true);
return (await ctx);
}
public async Task<bool> Connect(string uri)
{
var ctx = _connection.Connect(new Uri(uri), ignoreReceiver: true);
return (await ctx);
}
public async Task SendButton(ButtonType bt)
{
var text = bt.ToString();
if (text[0] == '_')
{
text = text.Substring(1);
}
await _connection.SendMessageAsync($"type:button\nname:{text}\n\n");
}
public async Task SendButton(ButtonType bt)
{
var text = bt.ToString();
if (text[0] == '_')
{
text = text.Substring(1);
}
await _connection.SendMessageAsync($"type:button\nname:{text}\n\n");
}
public void Move(double dx, double dy, bool drag = false)
{
_connection.SendMessageAsync($"type:move\ndx:{dx}\ndy:{dy}\ndown:{(drag ? 1 : 0)}\n\n").ConfigureAwait(false);
}
public void Move(double dx, double dy, bool drag = false)
{
_connection.SendMessageAsync($"type:move\ndx:{dx}\ndy:{dy}\ndown:{(drag ? 1 : 0)}\n\n").ConfigureAwait(false);
}
public void Scroll(double dx, double dy)
{
_connection.SendMessageAsync($"type:scroll\ndx:{dx}\ndy:{dy}\n\n").ConfigureAwait(false);
}
public void Scroll(double dx, double dy)
{
_connection.SendMessageAsync($"type:scroll\ndx:{dx}\ndy:{dy}\n\n").ConfigureAwait(false);
}
public void Click()
{
_connection.SendMessageAsync("type:click\n\n").ConfigureAwait(false);
}
public void Click()
{
_connection.SendMessageAsync("type:click\n\n").ConfigureAwait(false);
}
public void Dispose()
{
_connection?.Dispose();
}
}
public async ValueTask DisposeAsync()
{
if (_connection != null)
{
await _connection.DisposeAsync();
}
GC.SuppressFinalize(this);
}
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
+1203 -1183
View File
File diff suppressed because it is too large. Load diff
+2 -7
View File
@@ -1,21 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Platforms>x64</Platforms>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
</ItemGroup>
<PropertyGroup Condition="$([MSBuild]::VersionGreaterThanOrEquals('$(NETCoreSdkVersion)', '8.0'))">
<TargetFramework>net8.0</TargetFramework>
<UseNativeAot Condition="$(PublishDir) != ''">true</UseNativeAot>
</PropertyGroup>
<!-- Optimize for size -->
<PropertyGroup Condition="'$(UseNativeAot)' == 'true'">
<PublishAot>true</PublishAot>
+3 -3
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net9.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<RootNamespace>DJ</RootNamespace>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
@@ -18,8 +18,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="NLog" Version="5.2.8" />
<PackageReference Include="System.Reactive" Version="6.0.0" />
<PackageReference Include="NLog" Version="5.3.4" />
<PackageReference Include="System.Reactive" Version="6.0.1" />
</ItemGroup>
<ItemGroup>
@@ -27,8 +27,11 @@ namespace nspector.Common.Meta
return settingIds;
}
private SettingMeta GetDriverSettingMetaInternal(uint settingId)
private SettingMeta? GetDriverSettingMetaInternal(uint settingId)
{
if ((settingId & 0xFFFFF000) == 0x10c7d000)
return null;
var values = new NVDRS_SETTING_VALUES();
values.version = nvw.NVDRS_SETTING_VALUES_VER;
uint valueCount = 255;
+2 -2
View File
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net9.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<UseWindowsForms>true</UseWindowsForms>
<Nullable>enable</Nullable>
@@ -14,7 +14,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Resources.Extensions" Version="8.0.0" />
<PackageReference Include="System.Resources.Extensions" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
+21
View File
@@ -7913,6 +7913,27 @@
</CustomSettingValue>
</SettingValues>
</CustomSetting>
<CustomSetting>
<UserfriendlyName>DLSS 3.1.11+ - Forced DLSS3.1 preset letter (base profile only)</UserfriendlyName>
<HexSettingID>0x10E41DF3</HexSettingID>
<GroupName>8 - Extra</GroupName>
<MinRequiredDriverVersion>0</MinRequiredDriverVersion>
<SettingValues>
<CustomSettingValue>
<UserfriendlyName>Preset E</UserfriendlyName>
<HexValue>0x00000005</HexValue>
</CustomSettingValue>
<CustomSettingValue>
<UserfriendlyName>Preset F</UserfriendlyName>
<HexValue>0x00000006</HexValue>
</CustomSettingValue>
<CustomSettingValue>
<UserfriendlyName>Preset J</UserfriendlyName>
<HexValue>0x0000000A</HexValue>
</CustomSettingValue>
</SettingValues>
<SettingMasks />
</CustomSetting>
</Settings>
</CustomSettingNames>
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net9.0-windows</TargetFramework>
<Version>0.8.1.106</Version>
<Company>falahati.net</Company>
<Description>NvAPIWrapper is a .Net wrapper for NVIDIA public API</Description>
+2 -2
View File
@@ -28,7 +28,7 @@ namespace ColorControl.Shared.Common
var len = BitConverter.ToInt32(lenBytes);
var inBuffer = new byte[len];
ioStream.Read(inBuffer, 0, len);
ioStream.ReadExactly(inBuffer, 0, len);
return streamEncoding.GetString(inBuffer);
}
@@ -47,7 +47,7 @@ namespace ColorControl.Shared.Common
var len = BitConverter.ToInt32(lenBytes);
var inBuffer = new byte[len];
ioStream.Read(inBuffer, 0, len);
ioStream.ReadExactly(inBuffer, 0, len);
return streamEncoding.GetString(inBuffer);
}
+727 -734
View File
File diff suppressed because it is too large. Load diff
+36 -35
View File
@@ -4,64 +4,65 @@ namespace ColorControl.Shared.Contracts.NVIDIA;
public enum NvSettingType
{
DwordType,
BinaryType
DwordType,
BinaryType
}
public class NvSettingItemDto
{
public uint SettingId { get; set; }
public uint SettingId { get; set; }
public string SettingText { get; set; }
public string SettingText { get; set; }
public string ValueText { get; set; }
public string ValueText { get; set; }
public string ValueRaw { get; set; }
public string ValueRaw { get; set; }
[JsonIgnore]
public bool ValueChanged { get; set; }
[JsonIgnore]
public bool ValueChanged { get; set; }
private uint _value;
private uint _value;
public uint Value
{
get
{
return _value;
}
public uint Value
{
get
{
return _value;
}
set
{
_value = value;
ValueChanged = true;
}
}
set
{
_value = value;
ValueChanged = true;
}
}
public string GroupName { get; set; }
public string GroupName { get; set; }
public int State { get; set; }
public int State { get; set; }
public bool IsStringValue { get; set; }
public bool IsStringValue { get; set; }
public bool IsApiExposed { get; set; }
public bool IsApiExposed { get; set; }
public bool IsSettingHidden { get; set; }
public bool IsSettingHidden { get; set; }
public NvSettingType SettingType { get; set; }
public NvSettingType SettingType { get; set; }
public uint DefaultValue { get; set; }
public uint DefaultValue { get; set; }
public List<NvSettingItemValue> Values { get; set; }
public List<NvSettingItemValue> Values { get; set; }
public string FriendlyName { get; set; }
public override string ToString()
{
return string.Format("{0}; 0x{1:X8}; {2}; {3}; {4};", State, SettingId, SettingText, ValueText, ValueRaw);
}
public override string ToString()
{
return string.Format("{0}; 0x{1:X8}; {2}; {3}; {4};", State, SettingId, SettingText, ValueText, ValueRaw);
}
}
public class NvSettingItemValue
{
public uint Value { get; set; }
public string ValueName { get; set; }
public uint Value { get; set; }
public string ValueName { get; set; }
}
@@ -1,17 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static NStandard.Measures.Length;
namespace ColorControl.Shared.EventDispatcher;
namespace ColorControl.Shared.EventDispatcher;
public class DisplayChangedEventArgs : EventArgs
{
public uint Width { get; set; }
public uint Height { get; set; }
public uint BitsPerPixel{ get; set; }
public uint BitsPerPixel { get; set; }
}
public class DisplayChangeEventDispatcher : EventDispatcher<DisplayChangedEventArgs>
@@ -2,6 +2,7 @@
using ColorControl.Shared.Forms;
using Linearstar.Windows.RawInput;
using Linearstar.Windows.RawInput.Native;
using NStandard;
namespace ColorControl.Shared.EventDispatcher;
@@ -423,11 +424,11 @@ public class KeyboardShortcutDispatcher : EventDispatcher<KeyboardShortcutEventA
return shortcutString;
}
public static bool ValidateShortcut(string shortcut)
public static bool ValidateShortcut(string shortcut, bool showMessage = true)
{
var valid = string.IsNullOrWhiteSpace(shortcut) || shortcut.Contains("+") || ShortcutIsAllowedWithoutModifier(shortcut);
var valid = string.IsNullOrWhiteSpace(shortcut) || shortcut.Split("+").Where(s => !s.IsNullOrWhiteSpace()).Count() > 1 || ShortcutIsAllowedWithoutModifier(shortcut);
if (!valid)
if (!valid && showMessage)
{
MessageForms.WarningOk("Invalid shortcut. The shortcut should have modifiers and a normal key or be F13-F24.");
}
-11
View File
@@ -124,12 +124,6 @@ namespace ColorControl.Shared.Forms
try
{
//var settings = new UISettings();
//var foregroundColorValue = settings.GetColorValue(UIColorType.Foreground);
//var backroundColorValue = settings.GetColorValue(UIColorType.Background);
//var isDarkMode = FormUtils.IsColorLight(foregroundColorValue);
SetControlTheme(form, FormUtils.CurrentBackColor, FormUtils.CurrentForeColor);
var value = toDark ? 1 : 0;
@@ -240,10 +234,5 @@ namespace ColorControl.Shared.Forms
SetMenuForeColor(item, color);
}
}
public static bool IsColorLight(Windows.UI.Color color)
{
return ((5 * color.G) + (2 * color.R) + color.B) > (8 * 128);
}
}
}
+7 -15
View File
@@ -1,12 +1,8 @@
using Windows.Devices.Enumeration;
using Windows.Devices.Enumeration.Pnp;
namespace ColorControl.Shared.Native
namespace ColorControl.Shared.Native
{
public class PnpDev
{
public DeviceInformation DevInfo { get; private set; }
public PnpObject PnpObject { get; private set; }
public bool IsCustom { get; private set; }
public string Name { get; private set; }
public string IpAddress { get; private set; }
@@ -15,24 +11,20 @@ namespace ColorControl.Shared.Native
public PnpDev(string name, string ipAddress, string macAddress)
{
IsCustom = true;
Name = name;
IpAddress = ipAddress;
MacAddress = macAddress;
}
public PnpDev(DeviceInformation devInfo, PnpObject pnpObject, string name, string ipAddress, string macAddress) : this(name, ipAddress, macAddress)
public PnpDev(bool isCustom, string name, string ipAddress, string macAddress) : this(name, ipAddress, macAddress)
{
DevInfo = devInfo;
PnpObject = pnpObject;
IsCustom = isCustom;
}
public override string ToString()
{
return (IsCustom() ? "Custom: " : "Auto detect: ") + $"{Name}" + (!string.IsNullOrEmpty(IpAddress) ? $"({IpAddress})" : string.Empty);
}
public bool IsCustom()
{
return DevInfo == null;
return (IsCustom ? "Custom: " : "Auto detect: ") + $"{Name}" + (!string.IsNullOrEmpty(IpAddress) ? $"({IpAddress})" : string.Empty);
}
}
}
+4 -1
View File
@@ -317,7 +317,7 @@ namespace ColorControl.Shared.Services
try
{
using (TaskService ts = new TaskService())
using (var ts = new TaskService())
{
if (enabled)
{
@@ -329,6 +329,9 @@ namespace ColorControl.Shared.Services
td.Triggers.Add(new LogonTrigger { UserId = WindowsIdentity.GetCurrent().Name });
td.Actions.Add(new ExecAction(file, StartUpParams.RunningFromScheduledTaskParam, directory));
td.Settings.DisallowStartIfOnBatteries = false;
td.Settings.StopIfGoingOnBatteries = false;
td.Settings.ExecutionTimeLimit = TimeSpan.Zero;
ts.RootFolder.RegisterTaskDefinition(taskName, td);
}
+9 -8
View File
@@ -1,11 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net9.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
</PropertyGroup>
<PropertyGroup>
<PathMap Condition="'$(Configuration)' == 'Release'">$(MSBuildThisFileDirectory)=.\</PathMap>
@@ -25,14 +26,14 @@
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="9.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.2.8" />
<PackageReference Include="NStandard" Version="0.59.0" />
<PackageReference Include="NWin32" Version="1.2.6" />
<PackageReference Include="System.Management" Version="8.0.0" />
<PackageReference Include="TaskScheduler" Version="2.10.1" />
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="3.4.17" />
<PackageReference Include="NLog" Version="5.3.4" />
<PackageReference Include="NStandard" Version="0.83.1" />
<PackageReference Include="NWin32" Version="1.2.8" />
<PackageReference Include="System.Management" Version="9.0.0" />
<PackageReference Include="TaskScheduler" Version="2.11.0" />
<PackageReference Include="Vanara.PInvoke.IpHlpApi" Version="4.0.4" />
<PackageReference Include="RawInput.Sharp" Version="0.1.3" />
</ItemGroup>
+4 -4
View File
@@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetFramework>net9.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AppDesignerFolder>Properties</AppDesignerFolder>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF>
<SupportedOSPlatformVersion>10.0.20348.0</SupportedOSPlatformVersion>
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
</PropertyGroup>
<PropertyGroup>
@@ -16,8 +16,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="NLog" Version="5.2.8" />
<PackageReference Include="System.Resources.Extensions" Version="8.0.0" />
<PackageReference Include="NLog" Version="5.3.4" />
<PackageReference Include="System.Resources.Extensions" Version="9.0.0" />
</ItemGroup>
<ItemGroup>