mirror of
https://github.com/Maassoft/ColorControl.git
synced 2026-10-20 07:40:34 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a33543acd5 | ||
|
|
7f6175f8ef | ||
|
|
fd51bcca99 | ||
|
|
5268e6679e | ||
|
|
91fd44d698 | ||
|
|
48b13b1c64 | ||
|
|
d2aacbb8e0 | ||
|
|
04d52d6062 | ||
|
|
13420d2855 | ||
|
|
43a4660cc5 | ||
|
|
8683cd5be0 | ||
|
|
038a70cc81 |
No files matched your search
+90
-228
@@ -23,12 +23,10 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using FARPROC = System.IntPtr;
|
||||
using HMODULE = System.IntPtr;
|
||||
using ADL_CONTEXT_HANDLE = System.IntPtr;
|
||||
|
||||
#endregion Using
|
||||
|
||||
@@ -36,52 +34,6 @@ using HMODULE = System.IntPtr;
|
||||
|
||||
namespace ATI.ADL
|
||||
{
|
||||
#region Export Delegates
|
||||
/// <summary> ADL Memory allocation function allows ADL to callback for memory allocation</summary>
|
||||
/// <param name="size">input size</param>
|
||||
/// <returns> retrun ADL Error Code</returns>
|
||||
internal delegate IntPtr ADL_Main_Memory_Alloc (int size);
|
||||
|
||||
// ///// <summary> ADL Create Function to create ADL Data</summary>
|
||||
/// <param name="callback">Call back functin pointer which is ised to allocate memeory </param>
|
||||
/// <param name="enumConnectedAdapters">If it is 1, then ADL will only retuen the physical exist adapters </param>
|
||||
///// <returns> retrun ADL Error Code</returns>
|
||||
internal delegate int ADL_Main_Control_Create(ADL_Main_Memory_Alloc callback, int enumConnectedAdapters);
|
||||
|
||||
/// <summary> ADL Destroy Function to free up ADL Data</summary>
|
||||
/// <returns> retrun ADL Error Code</returns>
|
||||
internal delegate int ADL_Main_Control_Destroy ();
|
||||
|
||||
/// <summary> ADL Function to get the number of adapters</summary>
|
||||
/// <param name="numAdapters">return number of adapters</param>
|
||||
/// <returns> retrun ADL Error Code</returns>
|
||||
internal delegate int ADL_Adapter_NumberOfAdapters_Get (ref int numAdapters);
|
||||
|
||||
/// <summary> ADL Function to get the GPU adapter information</summary>
|
||||
/// <param name="info">return GPU adapter information</param>
|
||||
/// <param name="inputSize">the size of the GPU adapter struct</param>
|
||||
/// <returns> retrun ADL Error Code</returns>
|
||||
internal delegate int ADL_Adapter_AdapterInfo_Get (IntPtr info, int inputSize);
|
||||
|
||||
/// <summary> Function to determine if the adapter is active or not.</summary>
|
||||
/// <remarks>The function is used to check if the adapter associated with iAdapterIndex is active</remarks>
|
||||
/// <param name="adapterIndex"> Adapter Index.</param>
|
||||
/// <param name="status"> Status of the adapter. True: Active; False: Dsiabled</param>
|
||||
/// <returns>Non zero is successfull</returns>
|
||||
internal delegate int ADL_Adapter_Active_Get(int adapterIndex, ref int status);
|
||||
|
||||
/// <summary>Get display information based on adapter index</summary>
|
||||
/// <param name="adapterIndex">Adapter Index</param>
|
||||
/// <param name="numDisplays">return the total number of supported displays</param>
|
||||
/// <param name="displayInfoArray">return ADLDisplayInfo Array for supported displays' information</param>
|
||||
/// <param name="forceDetect">force detect or not</param>
|
||||
/// <returns>return ADL Error Code</returns>
|
||||
internal delegate int ADL_Display_DisplayInfo_Get(int adapterIndex, ref int numDisplays, out IntPtr displayInfoArray, int forceDetect);
|
||||
|
||||
internal delegate int ADL_Display_Size_Get(int adapterIndex, int displayIndex, ref int lpWidth, ref int lpHeight, ref int lpDefaultWidth, ref int lpDefaultHeight, ref int lpMinWidth, ref int lpMinHeight, ref int lpMaxWidth, ref int lpMaxHeight, ref int lpStepWidth, ref int lpStepHeight);
|
||||
|
||||
#endregion Export Delegates
|
||||
|
||||
#region Export Struct
|
||||
|
||||
#region ADLAdapterInfo
|
||||
@@ -207,10 +159,74 @@ namespace ATI.ADL
|
||||
/// <summary> Maximum number of GL-Sync ports on the GL-Sync module </summary>
|
||||
internal const int ADL_MAX_GLSYNC_PORT_LEDS = 8;
|
||||
/// <summary> Maximum number of ADLMOdes for the adapter </summary>
|
||||
internal const int ADL_MAX_NUM_DISPLAYMODES = 1024;
|
||||
internal const int ADL_MAX_NUM_DISPLAYMODES = 1024;
|
||||
|
||||
internal static Dictionary<Type, object> ADLDelegates = new Dictionary<Type, object>();
|
||||
|
||||
#endregion Internal Constant
|
||||
|
||||
#region Export Delegates
|
||||
/// <summary> ADL Memory allocation function allows ADL to callback for memory allocation</summary>
|
||||
/// <param name="size">input size</param>
|
||||
/// <returns> retrun ADL Error Code</returns>
|
||||
internal delegate IntPtr ADL_Main_Memory_Alloc(int size);
|
||||
|
||||
// ///// <summary> ADL Create Function to create ADL Data</summary>
|
||||
/// <param name="callback">Call back functin pointer which is ised to allocate memeory </param>
|
||||
/// <param name="enumConnectedAdapters">If it is 1, then ADL will only retuen the physical exist adapters </param>
|
||||
///// <returns> retrun ADL Error Code</returns>
|
||||
internal delegate int ADL_Main_Control_Create(ADL_Main_Memory_Alloc callback, int enumConnectedAdapters);
|
||||
|
||||
internal delegate int ADL2_Main_Control_Create(ADL_Main_Memory_Alloc callback, int enumConnectedAdapters, ref ADL_CONTEXT_HANDLE context);
|
||||
|
||||
/// <summary> ADL Destroy Function to free up ADL Data</summary>
|
||||
/// <returns> retrun ADL Error Code</returns>
|
||||
internal delegate int ADL_Main_Control_Destroy();
|
||||
|
||||
internal delegate int ADL2_Main_Control_Destroy(ADL_CONTEXT_HANDLE context);
|
||||
|
||||
/// <summary> ADL Function to get the number of adapters</summary>
|
||||
/// <param name="numAdapters">return number of adapters</param>
|
||||
/// <returns> retrun ADL Error Code</returns>
|
||||
internal delegate int ADL_Adapter_NumberOfAdapters_Get(ref int numAdapters);
|
||||
|
||||
/// <summary> ADL Function to get the GPU adapter information</summary>
|
||||
/// <param name="info">return GPU adapter information</param>
|
||||
/// <param name="inputSize">the size of the GPU adapter struct</param>
|
||||
/// <returns> retrun ADL Error Code</returns>
|
||||
internal delegate int ADL_Adapter_AdapterInfo_Get(IntPtr info, int inputSize);
|
||||
|
||||
/// <summary> Function to determine if the adapter is active or not.</summary>
|
||||
/// <remarks>The function is used to check if the adapter associated with iAdapterIndex is active</remarks>
|
||||
/// <param name="adapterIndex"> Adapter Index.</param>
|
||||
/// <param name="status"> Status of the adapter. True: Active; False: Dsiabled</param>
|
||||
/// <returns>Non zero is successfull</returns>
|
||||
internal delegate int ADL_Adapter_Active_Get(int adapterIndex, ref int status);
|
||||
|
||||
/// <summary>Get display information based on adapter index</summary>
|
||||
/// <param name="adapterIndex">Adapter Index</param>
|
||||
/// <param name="numDisplays">return the total number of supported displays</param>
|
||||
/// <param name="displayInfoArray">return ADLDisplayInfo Array for supported displays' information</param>
|
||||
/// <param name="forceDetect">force detect or not</param>
|
||||
/// <returns>return ADL Error Code</returns>
|
||||
internal delegate int ADL_Display_DisplayInfo_Get(int adapterIndex, ref int numDisplays, out IntPtr displayInfoArray, int forceDetect);
|
||||
|
||||
internal delegate int ADL_Display_Size_Get(int adapterIndex, int displayIndex, ref int lpWidth, ref int lpHeight, ref int lpDefaultWidth, ref int lpDefaultHeight, ref int lpMinWidth, ref int lpMinHeight, ref int lpMaxWidth, ref int lpMaxHeight, ref int lpStepWidth, ref int lpStepHeight);
|
||||
|
||||
internal delegate int ADL_Display_PixelFormat_Get(int adapterIndex, int displayIndex, ref int pixelFormat);
|
||||
internal delegate int ADL_Display_PixelFormat_Set(int adapterIndex, int displayIndex, int pixelFormat);
|
||||
|
||||
internal delegate int ADL_Display_ColorDepth_Get(int adapterIndex, int displayIndex, ref int colorDepth);
|
||||
internal delegate int ADL_Display_ColorDepth_Set(int adapterIndex, int displayIndex, int colorDepth);
|
||||
|
||||
internal delegate int ADL_Display_DitherState_Get(int adapterIndex, int displayIndex, ref int ditherState);
|
||||
internal delegate int ADL_Display_DitherState_Set(int adapterIndex, int displayIndex, int ditherState);
|
||||
|
||||
internal delegate int ADL2_Display_HDRState_Get(ADL_CONTEXT_HANDLE context, int adapterIndex, ADLDisplayID displayID, ref int support, ref int enable);
|
||||
internal delegate int ADL2_Display_HDRState_Set(ADL_CONTEXT_HANDLE context, int adapterIndex, ADLDisplayID displayID, int enable);
|
||||
|
||||
#endregion Export Delegates
|
||||
|
||||
#region Class ADLImport
|
||||
/// <summary> ADLImport class</summary>
|
||||
private static class ADLImport
|
||||
@@ -227,31 +243,10 @@ namespace ATI.ADL
|
||||
internal static extern HMODULE GetModuleHandle (string moduleName);
|
||||
|
||||
[DllImport(Atiadlxx_FileName)]
|
||||
internal static extern int ADL_Main_Control_Create (ADL_Main_Memory_Alloc callback, int enumConnectedAdapters);
|
||||
internal static extern int ADL_Main_Control_IsFunctionValid(HMODULE module, string procName);
|
||||
|
||||
[DllImport(Atiadlxx_FileName)]
|
||||
internal static extern int ADL_Main_Control_Destroy ();
|
||||
|
||||
[DllImport(Atiadlxx_FileName)]
|
||||
internal static extern int ADL_Main_Control_IsFunctionValid (HMODULE module, string procName);
|
||||
|
||||
[DllImport(Atiadlxx_FileName)]
|
||||
internal static extern FARPROC ADL_Main_Control_GetProcAddress (HMODULE module, string procName);
|
||||
|
||||
[DllImport(Atiadlxx_FileName)]
|
||||
internal static extern int ADL_Adapter_NumberOfAdapters_Get (ref int numAdapters);
|
||||
|
||||
[DllImport(Atiadlxx_FileName)]
|
||||
internal static extern int ADL_Adapter_AdapterInfo_Get (IntPtr info, int inputSize);
|
||||
|
||||
[DllImport(Atiadlxx_FileName)]
|
||||
internal static extern int ADL_Adapter_Active_Get(int adapterIndex, ref int status);
|
||||
|
||||
[DllImport(Atiadlxx_FileName)]
|
||||
internal static extern int ADL_Display_DisplayInfo_Get(int adapterIndex, ref int numDisplays, out IntPtr displayInfoArray, int forceDetect);
|
||||
|
||||
[DllImport(Atiadlxx_FileName)]
|
||||
internal static extern int ADL_Display_Size_Get(int iAdapterIndex, int iDisplayIndex, ref int lpWidth, ref int lpHeight, ref int lpDefaultWidth, ref int lpDefaultHeight, ref int lpMinWidth, ref int lpMinHeight, ref int lpMaxWidth, ref int lpMaxHeight, ref int lpStepWidth, ref int lpStepHeight);
|
||||
internal static extern FARPROC ADL_Main_Control_GetProcAddress(HMODULE module, string procName);
|
||||
|
||||
#endregion DLLImport
|
||||
}
|
||||
@@ -291,9 +286,13 @@ namespace ATI.ADL
|
||||
/// <summary> Destructor to force calling ADL Destroy function before free up the ADL library</summary>
|
||||
~ADLCheckLibrary ()
|
||||
{
|
||||
if (System.IntPtr.Zero != ADLCheckLibrary_.ADLLibrary)
|
||||
if (IntPtr.Zero != ADLCheckLibrary_.ADLLibrary)
|
||||
{
|
||||
ADLImport.ADL_Main_Control_Destroy();
|
||||
var del = ADL.GetDelegate<ADL.ADL_Main_Control_Destroy>();
|
||||
if (del != null)
|
||||
{
|
||||
del();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion Destructor
|
||||
@@ -304,8 +303,8 @@ namespace ATI.ADL
|
||||
/// <returns>return true, if function exists</returns>
|
||||
internal static bool IsFunctionValid (string functionName)
|
||||
{
|
||||
bool result = false;
|
||||
if (System.IntPtr.Zero != ADLCheckLibrary_.ADLLibrary)
|
||||
var result = false;
|
||||
if (IntPtr.Zero != ADLCheckLibrary_.ADLLibrary)
|
||||
{
|
||||
if (1 == ADLImport.ADL_Main_Control_IsFunctionValid(ADLCheckLibrary_.ADLLibrary, functionName))
|
||||
{
|
||||
@@ -322,8 +321,8 @@ namespace ATI.ADL
|
||||
/// <returns>return function pointer, if function exists</returns>
|
||||
internal static FARPROC GetProcAddress (string functionName)
|
||||
{
|
||||
FARPROC result = System.IntPtr.Zero;
|
||||
if (System.IntPtr.Zero != ADLCheckLibrary_.ADLLibrary)
|
||||
var result = IntPtr.Zero;
|
||||
if (IntPtr.Zero != ADLCheckLibrary_.ADLLibrary)
|
||||
{
|
||||
result = ADLImport.ADL_Main_Control_GetProcAddress(ADLCheckLibrary_.ADLLibrary, functionName);
|
||||
}
|
||||
@@ -337,7 +336,7 @@ namespace ATI.ADL
|
||||
|
||||
#region ADL_Main_Memory_Alloc
|
||||
/// <summary> Build in memory allocation function</summary>
|
||||
internal static ADL_Main_Memory_Alloc ADL_Main_Memory_Alloc = ADL_Main_Memory_Alloc_;
|
||||
internal static ADL_Main_Memory_Alloc ADL_Main_Memory_Alloc_Func = ADL_Main_Memory_Alloc_;
|
||||
/// <summary> Build in memory allocation function</summary>
|
||||
/// <param name="size">input size</param>
|
||||
/// <returns>return the memory buffer</returns>
|
||||
@@ -360,166 +359,29 @@ namespace ATI.ADL
|
||||
}
|
||||
#endregion ADL_Main_Memory_Free
|
||||
|
||||
#region ADL_Main_Control_Create
|
||||
/// <summary> ADL_Main_Control_Create Delegates</summary>
|
||||
internal static ADL_Main_Control_Create ADL_Main_Control_Create
|
||||
public static T GetDelegate<T>() where T : class
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!ADL_Main_Control_Create_Check && null == ADL_Main_Control_Create_)
|
||||
{
|
||||
ADL_Main_Control_Create_Check = true;
|
||||
if (ADLCheckLibrary.IsFunctionValid("ADL_Main_Control_Create"))
|
||||
{
|
||||
ADL_Main_Control_Create_ = ADLImport.ADL_Main_Control_Create;
|
||||
}
|
||||
}
|
||||
return ADL_Main_Control_Create_;
|
||||
}
|
||||
}
|
||||
/// <summary> Private Delegate</summary>
|
||||
private static ADL_Main_Control_Create ADL_Main_Control_Create_ = null;
|
||||
/// <summary> check flag to indicate the delegate has been checked</summary>
|
||||
private static bool ADL_Main_Control_Create_Check = false;
|
||||
#endregion ADL_Main_Control_Create
|
||||
var type = typeof(T);
|
||||
|
||||
#region ADL_Main_Control_Destroy
|
||||
/// <summary> ADL_Main_Control_Destroy Delegates</summary>
|
||||
internal static ADL_Main_Control_Destroy ADL_Main_Control_Destroy
|
||||
{
|
||||
get
|
||||
lock (ADLDelegates)
|
||||
{
|
||||
if (!ADL_Main_Control_Destroy_Check && null == ADL_Main_Control_Destroy_)
|
||||
if (ADLDelegates.ContainsKey(type))
|
||||
{
|
||||
ADL_Main_Control_Destroy_Check = true;
|
||||
if (ADLCheckLibrary.IsFunctionValid("ADL_Main_Control_Destroy"))
|
||||
{
|
||||
ADL_Main_Control_Destroy_ = ADLImport.ADL_Main_Control_Destroy;
|
||||
}
|
||||
return ADLDelegates[type] as T;
|
||||
}
|
||||
return ADL_Main_Control_Destroy_;
|
||||
}
|
||||
}
|
||||
/// <summary> Private Delegate</summary>
|
||||
private static ADL_Main_Control_Destroy ADL_Main_Control_Destroy_ = null;
|
||||
/// <summary> check flag to indicate the delegate has been checked</summary>
|
||||
private static bool ADL_Main_Control_Destroy_Check = false;
|
||||
#endregion ADL_Main_Control_Destroy
|
||||
|
||||
#region ADL_Adapter_NumberOfAdapters_Get
|
||||
/// <summary> ADL_Adapter_NumberOfAdapters_Get Delegates</summary>
|
||||
internal static ADL_Adapter_NumberOfAdapters_Get ADL_Adapter_NumberOfAdapters_Get
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!ADL_Adapter_NumberOfAdapters_Get_Check && null == ADL_Adapter_NumberOfAdapters_Get_)
|
||||
var ptr = ADLCheckLibrary.GetProcAddress(type.Name);
|
||||
if (ptr != FARPROC.Zero)
|
||||
{
|
||||
ADL_Adapter_NumberOfAdapters_Get_Check = true;
|
||||
if (ADLCheckLibrary.IsFunctionValid("ADL_Adapter_NumberOfAdapters_Get"))
|
||||
{
|
||||
ADL_Adapter_NumberOfAdapters_Get_ = ADLImport.ADL_Adapter_NumberOfAdapters_Get;
|
||||
}
|
||||
}
|
||||
return ADL_Adapter_NumberOfAdapters_Get_;
|
||||
}
|
||||
}
|
||||
/// <summary> Private Delegate</summary>
|
||||
private static ADL_Adapter_NumberOfAdapters_Get ADL_Adapter_NumberOfAdapters_Get_ = null;
|
||||
/// <summary> check flag to indicate the delegate has been checked</summary>
|
||||
private static bool ADL_Adapter_NumberOfAdapters_Get_Check = false;
|
||||
#endregion ADL_Adapter_NumberOfAdapters_Get
|
||||
var delegateValue = Marshal.GetDelegateForFunctionPointer(ptr, type);
|
||||
ADLDelegates.Add(type, delegateValue);
|
||||
|
||||
#region ADL_Adapter_AdapterInfo_Get
|
||||
/// <summary> ADL_Adapter_AdapterInfo_Get Delegates</summary>
|
||||
internal static ADL_Adapter_AdapterInfo_Get ADL_Adapter_AdapterInfo_Get
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!ADL_Adapter_AdapterInfo_Get_Check && null == ADL_Adapter_AdapterInfo_Get_)
|
||||
{
|
||||
ADL_Adapter_AdapterInfo_Get_Check = true;
|
||||
if (ADLCheckLibrary.IsFunctionValid("ADL_Adapter_AdapterInfo_Get"))
|
||||
{
|
||||
ADL_Adapter_AdapterInfo_Get_ = ADLImport.ADL_Adapter_AdapterInfo_Get;
|
||||
}
|
||||
return delegateValue as T;
|
||||
}
|
||||
return ADL_Adapter_AdapterInfo_Get_;
|
||||
}
|
||||
}
|
||||
/// <summary> Private Delegate</summary>
|
||||
private static ADL_Adapter_AdapterInfo_Get ADL_Adapter_AdapterInfo_Get_ = null;
|
||||
/// <summary> check flag to indicate the delegate has been checked</summary>
|
||||
private static bool ADL_Adapter_AdapterInfo_Get_Check = false;
|
||||
#endregion ADL_Adapter_AdapterInfo_Get
|
||||
|
||||
#region ADL_Adapter_Active_Get
|
||||
/// <summary> ADL_Adapter_Active_Get Delegates</summary>
|
||||
internal static ADL_Adapter_Active_Get ADL_Adapter_Active_Get
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!ADL_Adapter_Active_Get_Check && null == ADL_Adapter_Active_Get_)
|
||||
{
|
||||
ADL_Adapter_Active_Get_Check = true;
|
||||
if (ADLCheckLibrary.IsFunctionValid("ADL_Adapter_Active_Get"))
|
||||
{
|
||||
ADL_Adapter_Active_Get_ = ADLImport.ADL_Adapter_Active_Get;
|
||||
}
|
||||
}
|
||||
return ADL_Adapter_Active_Get_;
|
||||
}
|
||||
throw new InvalidProgramException("ADL-function not supported");
|
||||
}
|
||||
/// <summary> Private Delegate</summary>
|
||||
private static ADL_Adapter_Active_Get ADL_Adapter_Active_Get_ = null;
|
||||
/// <summary> check flag to indicate the delegate has been checked</summary>
|
||||
private static bool ADL_Adapter_Active_Get_Check = false;
|
||||
#endregion ADL_Adapter_Active_Get
|
||||
|
||||
#region ADL_Display_DisplayInfo_Get
|
||||
/// <summary> ADL_Display_DisplayInfo_Get Delegates</summary>
|
||||
internal static ADL_Display_DisplayInfo_Get ADL_Display_DisplayInfo_Get
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!ADL_Display_DisplayInfo_Get_Check && null == ADL_Display_DisplayInfo_Get_)
|
||||
{
|
||||
ADL_Display_DisplayInfo_Get_Check = true;
|
||||
if (ADLCheckLibrary.IsFunctionValid("ADL_Display_DisplayInfo_Get"))
|
||||
{
|
||||
ADL_Display_DisplayInfo_Get_ = ADLImport.ADL_Display_DisplayInfo_Get;
|
||||
}
|
||||
}
|
||||
return ADL_Display_DisplayInfo_Get_;
|
||||
}
|
||||
}
|
||||
/// <summary> Private Delegate</summary>
|
||||
private static ADL_Display_DisplayInfo_Get ADL_Display_DisplayInfo_Get_ = null;
|
||||
/// <summary> check flag to indicate the delegate has been checked</summary>
|
||||
private static bool ADL_Display_DisplayInfo_Get_Check = false;
|
||||
#endregion ADL_Display_DisplayInfo_Get
|
||||
|
||||
#region ADL_Display_Size_Get
|
||||
/// <summary> ADL_Display_Size_Get Delegates</summary>
|
||||
internal static ADL_Display_Size_Get ADL_Display_Size_Get
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!ADL_Display_Size_Get_Check && null == ADL_Display_Size_Get)
|
||||
{
|
||||
ADL_Display_Size_Get_Check = true;
|
||||
if (ADLCheckLibrary.IsFunctionValid("ADL_Display_Size_Get"))
|
||||
{
|
||||
ADL_Display_Size_Get_ = ADLImport.ADL_Display_Size_Get;
|
||||
}
|
||||
}
|
||||
return ADL_Display_Size_Get_;
|
||||
}
|
||||
}
|
||||
/// <summary> Private Delegate</summary>
|
||||
private static ADL_Display_Size_Get ADL_Display_Size_Get_ = null;
|
||||
/// <summary> check flag to indicate the delegate has been checked</summary>
|
||||
private static bool ADL_Display_Size_Get_Check = false;
|
||||
#endregion ADL_Display_Size_Get
|
||||
|
||||
#endregion Export Functions
|
||||
}
|
||||
|
||||
+284
-53
@@ -3,28 +3,114 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using ADL_CONTEXT_HANDLE = System.IntPtr;
|
||||
|
||||
namespace ColorControl
|
||||
{
|
||||
enum ADLPixelFormat
|
||||
{
|
||||
UNKNOWN = 0,
|
||||
RGB_FULL_RANGE = 1,
|
||||
YCRCB444 = 2,
|
||||
YCRCB422 = 3,
|
||||
RGB_LIMITED_RANGE = 4,
|
||||
YCRCB420 = 8
|
||||
}
|
||||
|
||||
enum ADLColorDepth
|
||||
{
|
||||
UNKNOWN = 0,
|
||||
BPC6 = 1,
|
||||
BPC8 = 2,
|
||||
BPC10 = 3,
|
||||
BPC12 = 4,
|
||||
BPC14 = 5,
|
||||
BPC16 = 6
|
||||
}
|
||||
|
||||
enum ADLDitherState
|
||||
{
|
||||
DISABLED = 0,
|
||||
DRIVER_DEFAULT = 1,
|
||||
FM6 = 2,
|
||||
FM8 = 3,
|
||||
FM10 = 4,
|
||||
DITH6 = 5,
|
||||
DITH8 = 6,
|
||||
DITH10 = 7,
|
||||
DITH6_NO_FRAME_RAND = 8,
|
||||
DITH8_NO_FRAME_RAND = 9,
|
||||
DITH10_NO_FRAME_RAND = 10,
|
||||
TRUN6 = 11,
|
||||
TRUN8 = 12,
|
||||
TRUN10 = 13,
|
||||
TRUN8_DITH8 = 14,
|
||||
TRUN10_DUTH6 = 15,
|
||||
TRUN10_FM8 = 16,
|
||||
TRUN10_FM6 = 17,
|
||||
TRUN10_DITH8_FM6 = 18,
|
||||
DITH10_FM8 = 19,
|
||||
DITH10_FM6 = 20,
|
||||
TRUN8_DITH6 = 21,
|
||||
TRUN8_FM6 = 22,
|
||||
DITH8_FM6 = 23
|
||||
}
|
||||
|
||||
class ADLWrapper
|
||||
{
|
||||
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
private static ADL_CONTEXT_HANDLE context = IntPtr.Zero;
|
||||
|
||||
public static bool Initialize()
|
||||
{
|
||||
int ADLRet = -1;
|
||||
|
||||
if (null != ADL.ADL_Main_Control_Create)
|
||||
Logger.Debug("Initialize");
|
||||
|
||||
var del = ADL.GetDelegate<ADL.ADL_Main_Control_Create>();
|
||||
|
||||
if (del != null)
|
||||
{
|
||||
// Second parameter is 1: Get only the present adapters
|
||||
ADLRet = ADL.ADL_Main_Control_Create(ADL.ADL_Main_Memory_Alloc, 1);
|
||||
ADLRet = del(ADL.ADL_Main_Memory_Alloc_Func, 1);
|
||||
CheckError(ADLRet, nameof(ADL.ADL_Main_Control_Create));
|
||||
}
|
||||
|
||||
Logger.Debug("ADLRet1: " + ADLRet);
|
||||
|
||||
var del2 = ADL.GetDelegate<ADL.ADL2_Main_Control_Create>();
|
||||
|
||||
if (del2 != null)
|
||||
{
|
||||
// Second parameter is 1: Get only the present adapters
|
||||
ADLRet = del2(ADL.ADL_Main_Memory_Alloc_Func, 1, ref context);
|
||||
Logger.Debug("ADLRet2: " + ADLRet);
|
||||
CheckError(ADLRet, nameof(ADL.ADL2_Main_Control_Create));
|
||||
}
|
||||
|
||||
return (ADL.ADL_SUCCESS == ADLRet);
|
||||
}
|
||||
|
||||
public static void Uninitialze()
|
||||
{
|
||||
if (null != ADL.ADL_Main_Control_Destroy)
|
||||
if (!ADL.ADLDelegates.Any())
|
||||
{
|
||||
ADL.ADL_Main_Control_Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
var del = ADL.GetDelegate<ADL.ADL_Main_Control_Destroy>();
|
||||
|
||||
if (null != del)
|
||||
{
|
||||
del();
|
||||
}
|
||||
|
||||
var del2 = ADL.GetDelegate<ADL.ADL2_Main_Control_Destroy>();
|
||||
|
||||
if (null != del2 && context != IntPtr.Zero)
|
||||
{
|
||||
del2(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +119,13 @@ namespace ColorControl
|
||||
int ADLRet = -1;
|
||||
int NumberOfAdapters = 0;
|
||||
|
||||
if (null != ADL.ADL_Adapter_NumberOfAdapters_Get)
|
||||
var delNumberOfAdapters = ADL.GetDelegate<ADL.ADL_Adapter_NumberOfAdapters_Get>();
|
||||
|
||||
if (null != delNumberOfAdapters)
|
||||
{
|
||||
ADL.ADL_Adapter_NumberOfAdapters_Get(ref NumberOfAdapters);
|
||||
delNumberOfAdapters(ref NumberOfAdapters);
|
||||
}
|
||||
Console.WriteLine("Number Of Adapters: " + NumberOfAdapters.ToString() + "\n");
|
||||
Logger.Debug("Number Of Adapters: " + NumberOfAdapters.ToString() + "\n");
|
||||
|
||||
if (NumberOfAdapters > 0)
|
||||
{
|
||||
@@ -45,37 +133,38 @@ namespace ColorControl
|
||||
ADLAdapterInfoArray OSAdapterInfoData;
|
||||
OSAdapterInfoData = new ADLAdapterInfoArray();
|
||||
|
||||
if (null != ADL.ADL_Adapter_AdapterInfo_Get)
|
||||
var delAdapterInfo = ADL.GetDelegate<ADL.ADL_Adapter_AdapterInfo_Get>();
|
||||
|
||||
if (null != delAdapterInfo)
|
||||
{
|
||||
IntPtr AdapterBuffer = IntPtr.Zero;
|
||||
int size = Marshal.SizeOf(OSAdapterInfoData);
|
||||
AdapterBuffer = Marshal.AllocCoTaskMem((int)size);
|
||||
Marshal.StructureToPtr(OSAdapterInfoData, AdapterBuffer, false);
|
||||
|
||||
if (null != ADL.ADL_Adapter_AdapterInfo_Get)
|
||||
ADLRet = delAdapterInfo(AdapterBuffer, size);
|
||||
if (ADL.ADL_SUCCESS == ADLRet)
|
||||
{
|
||||
ADLRet = ADL.ADL_Adapter_AdapterInfo_Get(AdapterBuffer, size);
|
||||
if (ADL.ADL_SUCCESS == ADLRet)
|
||||
OSAdapterInfoData = (ADLAdapterInfoArray)Marshal.PtrToStructure(AdapterBuffer, OSAdapterInfoData.GetType());
|
||||
int IsActive = 0;
|
||||
|
||||
var delActive = ADL.GetDelegate<ADL.ADL_Adapter_Active_Get>();
|
||||
|
||||
for (int i = 0; i < NumberOfAdapters; i++)
|
||||
{
|
||||
OSAdapterInfoData = (ADLAdapterInfoArray)Marshal.PtrToStructure(AdapterBuffer, OSAdapterInfoData.GetType());
|
||||
int IsActive = 0;
|
||||
// Check if the adapter is active
|
||||
if (null != delActive)
|
||||
ADLRet = delActive(OSAdapterInfoData.ADLAdapterInfo[i].AdapterIndex, ref IsActive);
|
||||
|
||||
for (int i = 0; i < NumberOfAdapters; i++)
|
||||
if (ADL.ADL_SUCCESS == ADLRet)
|
||||
{
|
||||
// Check if the adapter is active
|
||||
if (null != ADL.ADL_Adapter_Active_Get)
|
||||
ADLRet = ADL.ADL_Adapter_Active_Get(OSAdapterInfoData.ADLAdapterInfo[i].AdapterIndex, ref IsActive);
|
||||
|
||||
if (ADL.ADL_SUCCESS == ADLRet)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("ADL_Adapter_AdapterInfo_Get() returned error code " + ADLRet.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Debug("ADL_Adapter_AdapterInfo_Get() returned error code " + ADLRet.ToString());
|
||||
}
|
||||
// Release the memory for the AdapterInfo structure
|
||||
if (IntPtr.Zero != AdapterBuffer)
|
||||
@@ -88,7 +177,7 @@ namespace ColorControl
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<ADLDisplayInfo> GetAllDisplays()
|
||||
public static List<ADLDisplayInfo> GetAllDisplays(bool connected = true)
|
||||
{
|
||||
int ADLRet;
|
||||
int NumberOfDisplays = 0;
|
||||
@@ -104,24 +193,28 @@ namespace ColorControl
|
||||
|
||||
ADLDisplayInfo oneDisplayInfo = new ADLDisplayInfo();
|
||||
|
||||
if (null != ADL.ADL_Display_DisplayInfo_Get)
|
||||
var del = ADL.GetDelegate<ADL.ADL_Display_DisplayInfo_Get>();
|
||||
|
||||
if (null != del)
|
||||
{
|
||||
IntPtr DisplayBuffer = IntPtr.Zero;
|
||||
int j = 0;
|
||||
|
||||
// Force the display detection and get the Display Info. Use 0 as last parameter to NOT force detection
|
||||
ADLRet = ADL.ADL_Display_DisplayInfo_Get(primaryAdapter.AdapterIndex, ref NumberOfDisplays, out DisplayBuffer, 1);
|
||||
ADLRet = del(primaryAdapter.AdapterIndex, ref NumberOfDisplays, out DisplayBuffer, 1);
|
||||
if (ADL.ADL_SUCCESS == ADLRet)
|
||||
{
|
||||
for (j = 0; j < NumberOfDisplays; j++)
|
||||
{
|
||||
oneDisplayInfo = (ADLDisplayInfo)Marshal.PtrToStructure(new IntPtr(DisplayBuffer.ToInt32() + j * Marshal.SizeOf(oneDisplayInfo)), oneDisplayInfo.GetType());
|
||||
DisplayInfoData.Add(oneDisplayInfo);
|
||||
oneDisplayInfo = (ADLDisplayInfo)Marshal.PtrToStructure(new IntPtr(DisplayBuffer.ToInt64() + j * Marshal.SizeOf(oneDisplayInfo)), oneDisplayInfo.GetType());
|
||||
if (!connected || (1 == (oneDisplayInfo.DisplayInfoValue & 1))) {
|
||||
DisplayInfoData.Add(oneDisplayInfo);
|
||||
}
|
||||
}
|
||||
Console.WriteLine("\nTotal Number of Displays supported: " + NumberOfDisplays.ToString());
|
||||
Console.WriteLine("\nDispID AdpID Type OutType CnctType Connected Mapped InfoValue DisplayName ");
|
||||
Logger.Debug("Total Number of Displays supported: " + NumberOfDisplays.ToString());
|
||||
Logger.Debug("DispID DispPhyId AdpID Type OutType CnctType Connected Mapped InfoValue DisplayName ");
|
||||
|
||||
for (j = 0; j < NumberOfDisplays; j++)
|
||||
for (j = 0; j < DisplayInfoData.Count; j++)
|
||||
{
|
||||
int InfoValue = DisplayInfoData[j].DisplayInfoValue;
|
||||
string StrConnected = (1 == (InfoValue & 1)) ? "Yes" : "No ";
|
||||
@@ -129,21 +222,21 @@ namespace ColorControl
|
||||
int AdpID = DisplayInfoData[j].DisplayID.DisplayLogicalAdapterIndex;
|
||||
string StrAdpID = (AdpID < 0) ? "--" : AdpID.ToString("d2");
|
||||
|
||||
Console.WriteLine(DisplayInfoData[j].DisplayID.DisplayLogicalIndex.ToString() + " " +
|
||||
StrAdpID + " " +
|
||||
DisplayInfoData[j].DisplayType.ToString() + " " +
|
||||
DisplayInfoData[j].DisplayOutputType.ToString() + " " +
|
||||
DisplayInfoData[j].DisplayConnector.ToString() + " " +
|
||||
StrConnected + " " +
|
||||
StrMapped + " " +
|
||||
InfoValue.ToString("x4") + " " +
|
||||
DisplayInfoData[j].DisplayName.ToString());
|
||||
Logger.Debug(DisplayInfoData[j].DisplayID.DisplayLogicalIndex.ToString() + " " +
|
||||
DisplayInfoData[j].DisplayID.DisplayPhysicalIndex.ToString() + " " +
|
||||
StrAdpID + " " +
|
||||
DisplayInfoData[j].DisplayType.ToString() + " " +
|
||||
DisplayInfoData[j].DisplayOutputType.ToString() + " " +
|
||||
DisplayInfoData[j].DisplayConnector.ToString() + " " +
|
||||
StrConnected + " " +
|
||||
StrMapped + " " +
|
||||
InfoValue.ToString("x4") + " " +
|
||||
DisplayInfoData[j].DisplayName.ToString());
|
||||
}
|
||||
Console.WriteLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("ADL_Display_DisplayInfo_Get() returned error code " + ADLRet.ToString());
|
||||
Logger.Debug("ADL_Display_DisplayInfo_Get() returned error code " + ADLRet.ToString());
|
||||
}
|
||||
// Release the memory for the DisplayInfo structure
|
||||
if (IntPtr.Zero != DisplayBuffer)
|
||||
@@ -152,17 +245,155 @@ namespace ColorControl
|
||||
return DisplayInfoData;
|
||||
}
|
||||
|
||||
public static bool GetDisplayResolution(string displayName, ref int horizontal, ref int vertical)
|
||||
private static bool CheckError(int ADLRet, string functionName)
|
||||
{
|
||||
var displays = GetAllDisplays();
|
||||
var display = displays.FirstOrDefault(d => d.DisplayName.Equals(displayName, StringComparison.OrdinalIgnoreCase));
|
||||
if (display.DisplayID.DisplayPhysicalIndex >= 0 && ADL.ADL_Display_Size_Get != null)
|
||||
{
|
||||
int lpDefaultWidth, lpDefaultHeight, lpMinWidth, lpMinHeight, lpMaxWidth, lpMaxHeight, lpStepWidth, lpStepHeight;
|
||||
lpDefaultWidth = lpDefaultHeight = lpMinWidth = lpMinHeight = lpMaxWidth = lpMaxHeight = lpStepWidth = lpStepHeight = 0;
|
||||
var ADLRet = ADL.ADL_Display_Size_Get(display.DisplayID.DisplayPhysicalAdapterIndex, display.DisplayID.DisplayPhysicalIndex, ref horizontal, ref vertical, ref lpDefaultWidth, ref lpDefaultHeight, ref lpMinWidth, ref lpMinHeight, ref lpMaxWidth, ref lpMaxHeight, ref lpStepWidth, ref lpStepHeight);
|
||||
var result = ADLRet == ADL.ADL_SUCCESS;
|
||||
|
||||
return ADLRet == ADL.ADL_SUCCESS;
|
||||
if (!result)
|
||||
{
|
||||
Logger.Error($"Error calling ADL ({functionName}): {ADLRet}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool GetDisplayResolution(ADLDisplayInfo display, ref int horizontal, ref int vertical)
|
||||
{
|
||||
var screen = Screen.PrimaryScreen;
|
||||
var bounds = screen.Bounds;
|
||||
|
||||
horizontal = bounds.Width;
|
||||
vertical = bounds.Height;
|
||||
|
||||
Logger.Debug($"GetDisplayResolution: {horizontal}x{vertical}");
|
||||
|
||||
//var del = ADL.GetDelegate<ADL.ADL_Display_Size_Get>();
|
||||
|
||||
//if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null)
|
||||
//{
|
||||
// int lpDefaultWidth, lpDefaultHeight, lpMinWidth, lpMinHeight, lpMaxWidth, lpMaxHeight, lpStepWidth, lpStepHeight;
|
||||
// lpDefaultWidth = lpDefaultHeight = lpMinWidth = lpMinHeight = lpMaxWidth = lpMaxHeight = lpStepWidth = lpStepHeight = 0;
|
||||
// var ADLRet = del(display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID.DisplayLogicalIndex, ref horizontal, ref vertical, ref lpDefaultWidth, ref lpDefaultHeight, ref lpMinWidth, ref lpMinHeight, ref lpMaxWidth, ref lpMaxHeight, ref lpStepWidth, ref lpStepHeight);
|
||||
|
||||
// return CheckError(ADLRet, nameof(ADL.ADL_Display_Size_Get));
|
||||
//}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool GetDisplayPixelFormat(ADLDisplayInfo display, ref ADLPixelFormat pixelFormat)
|
||||
{
|
||||
var del = ADL.GetDelegate<ADL.ADL_Display_PixelFormat_Get>();
|
||||
|
||||
if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null)
|
||||
{
|
||||
int pixelFormatInt = 0;
|
||||
var ADLRet = del(display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID.DisplayLogicalIndex, ref pixelFormatInt);
|
||||
|
||||
pixelFormat = (ADLPixelFormat)pixelFormatInt;
|
||||
|
||||
return CheckError(ADLRet, nameof(ADL.ADL_Display_PixelFormat_Get));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool SetDisplayPixelFormat(ADLDisplayInfo display, ADLPixelFormat pixelFormat)
|
||||
{
|
||||
var del = ADL.GetDelegate<ADL.ADL_Display_PixelFormat_Set>();
|
||||
|
||||
if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null)
|
||||
{
|
||||
var ADLRet = del(display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID.DisplayLogicalIndex, (int)pixelFormat);
|
||||
|
||||
return CheckError(ADLRet, nameof(ADL.ADL_Display_PixelFormat_Set));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool GetDisplayColorDepth(ADLDisplayInfo display, ref ADLColorDepth colorDepth)
|
||||
{
|
||||
var del = ADL.GetDelegate<ADL.ADL_Display_ColorDepth_Get>();
|
||||
|
||||
if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null)
|
||||
{
|
||||
int colorDepthInt = 0;
|
||||
var ADLRet = del(display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID.DisplayLogicalIndex, ref colorDepthInt);
|
||||
|
||||
colorDepth = (ADLColorDepth)colorDepthInt;
|
||||
|
||||
return CheckError(ADLRet, nameof(ADL.ADL_Display_ColorDepth_Get));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool SetDisplayColorDepth(ADLDisplayInfo display, ADLColorDepth colorDepth)
|
||||
{
|
||||
var del = ADL.GetDelegate<ADL.ADL_Display_ColorDepth_Set>();
|
||||
|
||||
if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null)
|
||||
{
|
||||
var ADLRet = del(display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID.DisplayLogicalIndex, (int)colorDepth);
|
||||
|
||||
return CheckError(ADLRet, nameof(ADL.ADL_Display_ColorDepth_Set));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool GetDisplayDitherState(ADLDisplayInfo display, ref ADLDitherState ditherState)
|
||||
{
|
||||
var del = ADL.GetDelegate<ADL.ADL_Display_DitherState_Get>();
|
||||
|
||||
if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null)
|
||||
{
|
||||
var ditherStateInt = 0;
|
||||
var ADLRet = del(display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID.DisplayLogicalIndex, ref ditherStateInt);
|
||||
|
||||
ditherState = (ADLDitherState)ditherStateInt;
|
||||
|
||||
return CheckError(ADLRet, nameof(ADL.ADL_Display_DitherState_Get));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool SetDisplayDitherState(ADLDisplayInfo display, ADLDitherState ditherState)
|
||||
{
|
||||
var del = ADL.GetDelegate<ADL.ADL_Display_DitherState_Set>();
|
||||
|
||||
if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null)
|
||||
{
|
||||
var ADLRet = del(display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID.DisplayLogicalIndex, (int)ditherState);
|
||||
|
||||
return CheckError(ADLRet, nameof(ADL.ADL_Display_DitherState_Set));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool GetDisplayHDRState(ADLDisplayInfo display, ref bool supported, ref bool enabled)
|
||||
{
|
||||
var del = ADL.GetDelegate<ADL.ADL2_Display_HDRState_Get>();
|
||||
|
||||
if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null)
|
||||
{
|
||||
var supportedInt = 0;
|
||||
var enabledInt = 0;
|
||||
var ADLRet = del(context, display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID, ref supportedInt, ref enabledInt);
|
||||
|
||||
supported = supportedInt != 0;
|
||||
enabled = enabledInt != 0;
|
||||
|
||||
return CheckError(ADLRet, nameof(ADL.ADL2_Display_HDRState_Get));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool SetDisplayHDRState(ADLDisplayInfo display, bool enabled)
|
||||
{
|
||||
var del = ADL.GetDelegate<ADL.ADL2_Display_HDRState_Set>();
|
||||
|
||||
if (display.DisplayID.DisplayPhysicalIndex >= 0 && del != null)
|
||||
{
|
||||
var ADLRet = del(context, display.DisplayID.DisplayLogicalAdapterIndex, display.DisplayID, enabled ? 1 : 0);
|
||||
|
||||
return CheckError(ADLRet, nameof(ADL.ADL2_Display_HDRState_Set));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using ATI.ADL;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ColorControl
|
||||
{
|
||||
class AmdDisplayInfo
|
||||
{
|
||||
public ADLDisplayInfo Display { get; }
|
||||
|
||||
public List<string> Values { get; }
|
||||
|
||||
public string InfoLine { get; }
|
||||
|
||||
public AmdDisplayInfo(ADLDisplayInfo display, List<string> values, string infoLine)
|
||||
{
|
||||
Display = display;
|
||||
Values = values;
|
||||
InfoLine = infoLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-72
@@ -1,6 +1,4 @@
|
||||
using NvAPIWrapper.Display;
|
||||
using NvAPIWrapper.Native.Display;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
@@ -9,12 +7,13 @@ namespace ColorControl
|
||||
class AmdPreset : PresetBase
|
||||
{
|
||||
public bool applyColorData { get; set; }
|
||||
public ColorData colorData { get; set; }
|
||||
public ADLColorDepth colorDepth { get; set; }
|
||||
public ADLPixelFormat pixelFormat { get; set; }
|
||||
public bool applyHDR { get; set; }
|
||||
public bool HDREnabled { get; set; }
|
||||
public bool toggleHDR { get; set; }
|
||||
public bool applyDithering { get; set; }
|
||||
public bool ditheringEnabled { get; set; }
|
||||
public ADLDitherState ditherState { get; set; }
|
||||
public bool applyRefreshRate { get; set; }
|
||||
public uint refreshRate { get; set; }
|
||||
public bool primaryDisplay { get; set; }
|
||||
@@ -24,7 +23,7 @@ namespace ColorControl
|
||||
{
|
||||
applyColorData = true;
|
||||
applyDithering = false;
|
||||
ditheringEnabled = true;
|
||||
ditherState = ADLDitherState.DRIVER_DEFAULT;
|
||||
applyHDR = false;
|
||||
HDREnabled = false;
|
||||
toggleHDR = false;
|
||||
@@ -33,12 +32,6 @@ namespace ColorControl
|
||||
primaryDisplay = true;
|
||||
}
|
||||
|
||||
public AmdPreset(ColorData colorData) : this()
|
||||
{
|
||||
id = GetNewId();
|
||||
this.colorData = colorData;
|
||||
}
|
||||
|
||||
public AmdPreset(AmdPreset preset): this()
|
||||
{
|
||||
id = GetNewId();
|
||||
@@ -46,15 +39,15 @@ namespace ColorControl
|
||||
primaryDisplay = preset.primaryDisplay;
|
||||
displayName = preset.displayName;
|
||||
|
||||
var colorData = preset.colorData;
|
||||
this.colorData = new ColorData(colorData.ColorFormat, dynamicRange: colorData.DynamicRange, colorDepth: colorData.ColorDepth, colorSelectionPolicy: colorData.SelectionPolicy);
|
||||
applyColorData = preset.applyColorData;
|
||||
colorDepth = preset.colorDepth;
|
||||
pixelFormat = preset.pixelFormat;
|
||||
|
||||
applyHDR = preset.applyHDR;
|
||||
HDREnabled = preset.HDREnabled;
|
||||
toggleHDR = preset.toggleHDR;
|
||||
applyDithering = preset.applyDithering;
|
||||
ditheringEnabled = preset.ditheringEnabled;
|
||||
ditherState = preset.ditherState;
|
||||
applyRefreshRate = preset.applyRefreshRate;
|
||||
refreshRate = preset.refreshRate;
|
||||
}
|
||||
@@ -69,28 +62,24 @@ namespace ColorControl
|
||||
public static string[] GetColumnNames()
|
||||
{
|
||||
//return new[] { "BPC", "Format", "Dynamic range", "Toggle HDR", "Shortcut" };
|
||||
return new[] { "Display|140", "Color settings (BPC, format, dyn. range, color space)|260", "Refresh rate|100", "Dithering", "HDR", "Shortcut" };
|
||||
return new[] { "Display|140", "Color settings (BPC, format)|260", "Refresh rate|100", "Dithering", "HDR", "Shortcut", "Apply on startup" };
|
||||
}
|
||||
|
||||
public List<string> GetDisplayValues()
|
||||
public override List<string> GetDisplayValues(Config config = null)
|
||||
{
|
||||
var values = new List<string>();
|
||||
|
||||
var display = string.Format("{0}", primaryDisplay ? "Primary" : displayName);
|
||||
values.Add(display);
|
||||
|
||||
var colorSettings = string.Format("{0}: {1}, {2}, {3}, {4}", applyColorData ? "Included" : "Excluded", colorData.ColorDepth, colorData.ColorFormat, colorData.DynamicRange, colorData.Colorimetry);
|
||||
var colorSettings = string.Format("{0}: {1}, {2}", applyColorData ? "Included" : "Excluded", colorDepth, pixelFormat);
|
||||
|
||||
values.Add(colorSettings);
|
||||
values.Add(string.Format("{0}: {1}Hz", applyRefreshRate ? "Included" : "Excluded", refreshRate));
|
||||
values.Add(string.Format("{0}: {1}", applyDithering ? "Included" : "Excluded", ditheringEnabled ? "Enabled" : "Disabled"));
|
||||
values.Add(string.Format("{0}: {1}", applyDithering ? "Included" : "Excluded", ditherState));
|
||||
values.Add(string.Format("{0}: {1}", applyHDR ? "Included" : "Excluded", toggleHDR ? "Toggle" : HDREnabled ? "Enabled" : "Disabled"));
|
||||
|
||||
//values.Add(colorData.ColorDepth.ToString());
|
||||
//values.Add(colorData.ColorFormat.ToString());
|
||||
//values.Add(colorData.DynamicRange.ToString());
|
||||
//values.Add(toggleHDR.ToString());
|
||||
values.Add(shortcut);
|
||||
values.Add(string.Format("{0}", config?.AmdPresetId_ApplyOnStartup == id ? "Yes" : string.Empty));
|
||||
|
||||
return values;
|
||||
}
|
||||
@@ -99,21 +88,11 @@ namespace ColorControl
|
||||
{
|
||||
var presets = new List<AmdPreset>();
|
||||
|
||||
presets.Add(new AmdPreset(new ColorData(ColorDataFormat.Auto, dynamicRange: ColorDataDynamicRange.Auto, colorDepth: ColorDataDepth.Default, colorSelectionPolicy: ColorDataSelectionPolicy.BestQuality)));
|
||||
var preset = new AmdPreset();
|
||||
preset.colorDepth = ADLColorDepth.BPC8;
|
||||
preset.pixelFormat = ADLPixelFormat.RGB_FULL_RANGE;
|
||||
|
||||
for (var dynamicRange = ColorDataDynamicRange.VESA; dynamicRange <= ColorDataDynamicRange.CEA; dynamicRange++)
|
||||
{
|
||||
presets.Add(new AmdPreset(new ColorData(ColorDataFormat.RGB, dynamicRange: dynamicRange, colorDepth: ColorDataDepth.BPC8, colorSelectionPolicy: ColorDataSelectionPolicy.User)));
|
||||
presets.Add(new AmdPreset(new ColorData(ColorDataFormat.RGB, dynamicRange: dynamicRange, colorDepth: ColorDataDepth.BPC10, colorSelectionPolicy: ColorDataSelectionPolicy.User)));
|
||||
presets.Add(new AmdPreset(new ColorData(ColorDataFormat.RGB, dynamicRange: dynamicRange, colorDepth: ColorDataDepth.BPC12, colorSelectionPolicy: ColorDataSelectionPolicy.User)));
|
||||
}
|
||||
|
||||
for (var format = ColorDataFormat.YUV422; format <= ColorDataFormat.YUV420; format++)
|
||||
{
|
||||
presets.Add(new AmdPreset(new ColorData(format, dynamicRange: ColorDataDynamicRange.Auto, colorDepth: ColorDataDepth.BPC8, colorSelectionPolicy: ColorDataSelectionPolicy.User)));
|
||||
presets.Add(new AmdPreset(new ColorData(format, dynamicRange: ColorDataDynamicRange.Auto, colorDepth: ColorDataDepth.BPC10, colorSelectionPolicy: ColorDataSelectionPolicy.User)));
|
||||
presets.Add(new AmdPreset(new ColorData(format, dynamicRange: ColorDataDynamicRange.Auto, colorDepth: ColorDataDepth.BPC12, colorSelectionPolicy: ColorDataSelectionPolicy.User)));
|
||||
}
|
||||
presets.Add(preset);
|
||||
|
||||
return presets;
|
||||
}
|
||||
@@ -127,7 +106,7 @@ namespace ColorControl
|
||||
}
|
||||
if (applyColorData)
|
||||
{
|
||||
var colorSettings = string.Format("Format: {0}, {1}, {2}", colorData.ColorDepth, colorData.ColorFormat, colorData.DynamicRange);
|
||||
var colorSettings = string.Format("Format: {0}, {1}", colorDepth, pixelFormat);
|
||||
sb.Append(colorSettings);
|
||||
sb.Append(" / ");
|
||||
}
|
||||
@@ -138,7 +117,7 @@ namespace ColorControl
|
||||
}
|
||||
if (applyDithering)
|
||||
{
|
||||
sb.AppendFormat("Dithering: {0}", ditheringEnabled ? "Yes" : "No");
|
||||
sb.AppendFormat("Dithering: {0}", ditherState);
|
||||
sb.Append(" / ");
|
||||
}
|
||||
if (applyHDR)
|
||||
@@ -149,38 +128,6 @@ namespace ColorControl
|
||||
|
||||
return sb.ToString(0, Math.Max(0, sb.Length - 3));
|
||||
}
|
||||
|
||||
public static ColorData GenerateColorData(IDictionary<string, object> dictionary)
|
||||
{
|
||||
var format = ColorDataFormat.RGB;
|
||||
var dynamicRange = ColorDataDynamicRange.VESA;
|
||||
var colorDepth = ColorDataDepth.BPC8;
|
||||
var colorimetry = ColorDataColorimetry.Auto;
|
||||
var selectionPolicy = ColorDataSelectionPolicy.User;
|
||||
object value;
|
||||
if (dictionary.TryGetValue("ColorFormat", out value))
|
||||
{
|
||||
format = (ColorDataFormat)Enum.ToObject(typeof(ColorDataFormat), value);
|
||||
}
|
||||
if (dictionary.TryGetValue("ColorDepth", out value))
|
||||
{
|
||||
colorDepth = (ColorDataDepth)Enum.ToObject(typeof(ColorDataDepth), value);
|
||||
}
|
||||
if (dictionary.TryGetValue("Colorimetry", out value))
|
||||
{
|
||||
colorimetry = (ColorDataColorimetry)Enum.ToObject(typeof(ColorDataColorimetry), value);
|
||||
}
|
||||
if (dictionary.TryGetValue("DynamicRange", out value))
|
||||
{
|
||||
dynamicRange = (ColorDataDynamicRange)Enum.ToObject(typeof(ColorDataDynamicRange), value);
|
||||
}
|
||||
if (dictionary.TryGetValue("SelectionPolicy", out value))
|
||||
{
|
||||
selectionPolicy = (ColorDataSelectionPolicy)Enum.ToObject(typeof(ColorDataSelectionPolicy), value);
|
||||
}
|
||||
return new ColorData(format, dynamicRange: dynamicRange, colorimetry: colorimetry, colorDepth: colorDepth, colorSelectionPolicy: selectionPolicy);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+258
-45
@@ -1,86 +1,209 @@
|
||||
//using ATI.ADL;
|
||||
using ATI.ADL;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace ColorControl
|
||||
{
|
||||
class AmdService : GraphicsService
|
||||
{
|
||||
private string CurrentDisplay;
|
||||
private ADLDisplayInfo _currentDisplay;
|
||||
|
||||
public AmdService()
|
||||
private List<AmdPreset> _presets;
|
||||
|
||||
private AmdPreset _lastAppliedPreset;
|
||||
|
||||
public AmdService(string dataPath) : base(dataPath)
|
||||
{
|
||||
LoadPresets();
|
||||
}
|
||||
|
||||
public List<AmdPreset> GetPresets()
|
||||
{
|
||||
return _presets;
|
||||
}
|
||||
|
||||
public AmdPreset GetLastAppliedPreset()
|
||||
{
|
||||
return _lastAppliedPreset;
|
||||
}
|
||||
|
||||
private void LoadPresets()
|
||||
{
|
||||
_presetsFilename = Path.Combine(_dataPath, "AmdPresets.json");
|
||||
|
||||
if (File.Exists(_presetsFilename))
|
||||
{
|
||||
var json = File.ReadAllText(_presetsFilename);
|
||||
|
||||
_presets = _JsonDeserializer.Deserialize<List<AmdPreset>>(json);
|
||||
}
|
||||
else
|
||||
{
|
||||
_presets = AmdPreset.GetDefaultPresets();
|
||||
}
|
||||
}
|
||||
|
||||
private void SavePresets()
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = _JsonSerializer.Serialize(_presets);
|
||||
File.WriteAllText(_presetsFilename, json);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e.ToLogString());
|
||||
}
|
||||
}
|
||||
|
||||
public void GlobalSave()
|
||||
{
|
||||
SavePresets();
|
||||
}
|
||||
|
||||
public bool HasDisplaysAttached()
|
||||
{
|
||||
try
|
||||
{
|
||||
return GetDisplays().Any();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCurrentDisplay(AmdPreset preset)
|
||||
{
|
||||
CurrentDisplay = preset.displayName;
|
||||
var displays = GetDisplays();
|
||||
if (preset.primaryDisplay)
|
||||
{
|
||||
_currentDisplay = displays.FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentDisplay = displays.FirstOrDefault(x => x.DisplayName.Equals(preset.displayName));
|
||||
}
|
||||
}
|
||||
|
||||
public string GetCurrentDisplay()
|
||||
public ADLDisplayInfo GetCurrentDisplay()
|
||||
{
|
||||
return CurrentDisplay;
|
||||
if (string.IsNullOrEmpty(_currentDisplay.DisplayName))
|
||||
{
|
||||
_currentDisplay = GetDisplays().FirstOrDefault();
|
||||
}
|
||||
|
||||
return _currentDisplay;
|
||||
}
|
||||
|
||||
public bool ApplyPreset(AmdPreset preset, Config config)
|
||||
{
|
||||
SetCurrentDisplay(preset);
|
||||
|
||||
if (string.IsNullOrEmpty(_currentDisplay.DisplayName))
|
||||
{
|
||||
Logger.Error("Could not set current display");
|
||||
return false;
|
||||
}
|
||||
|
||||
var result = true;
|
||||
|
||||
if (preset.applyHDR)
|
||||
{
|
||||
if (preset.toggleHDR || preset.HDREnabled != IsHDREnabled())
|
||||
var hdrEnabled = IsHDREnabled();
|
||||
if (preset.toggleHDR)
|
||||
{
|
||||
ToggleHDR(config.DisplaySettingsDelay);
|
||||
result = ADLWrapper.SetDisplayHDRState(_currentDisplay, !hdrEnabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ADLWrapper.SetDisplayHDRState(_currentDisplay, preset.HDREnabled);
|
||||
}
|
||||
|
||||
//if (preset.toggleHDR || preset.HDREnabled != hdrEnabled)
|
||||
//{
|
||||
// ToggleHDR(config.DisplaySettingsDelay);
|
||||
//}
|
||||
}
|
||||
|
||||
if (preset.applyRefreshRate)
|
||||
{
|
||||
SetRefreshRate(preset.refreshRate);
|
||||
if (!SetRefreshRate(preset.refreshRate))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (preset.applyColorData)
|
||||
{
|
||||
var display = GetCurrentDisplay();
|
||||
// TODO: ADL call to set color format, depth, space
|
||||
// ADL_Display_PixelFormat_Set
|
||||
// ADL_Display_ColorDepth_Set
|
||||
|
||||
//var data = new ColorData(ColorDataFormat.YUV444, ColorDataColorimetry.YCC709, ColorDataDynamicRange.Auto, ColorDataDepth.BPC8, preset.colorData.SelectionPolicy, ColorDataDesktopDepth.Default);
|
||||
//display.DisplayDevice.SetColorData(preset.colorData);
|
||||
if (!ADLWrapper.SetDisplayColorDepth(_currentDisplay, preset.colorDepth))
|
||||
{
|
||||
Logger.Error("Could not set color depth");
|
||||
result = false;
|
||||
}
|
||||
if (preset.pixelFormat != ADLPixelFormat.UNKNOWN && !ADLWrapper.SetDisplayPixelFormat(_currentDisplay, preset.pixelFormat))
|
||||
{
|
||||
Logger.Error("Could not set pixel format");
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (preset.applyDithering)
|
||||
{
|
||||
SetDithering(preset.ditheringEnabled);
|
||||
if (!SetDithering(preset.ditherState))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
_lastAppliedPreset = preset;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SetDithering(bool enabled)
|
||||
public bool SetDithering(ADLDitherState ditherState)
|
||||
{
|
||||
// TODO: ADL call to set dithering state
|
||||
// ADL_Display_DitherState_Get
|
||||
var display = GetCurrentDisplay();
|
||||
|
||||
return ADLWrapper.SetDisplayDitherState(display, ditherState);
|
||||
}
|
||||
|
||||
public bool GetDithering()
|
||||
public ADLDitherState GetDithering(ADLDisplayInfo display = default(ADLDisplayInfo))
|
||||
{
|
||||
// TODO: ADL call to get dithering state
|
||||
// ADL_Display_DitherState_Set
|
||||
return false;
|
||||
if (string.IsNullOrEmpty(display.DisplayName))
|
||||
{
|
||||
display = GetCurrentDisplay();
|
||||
}
|
||||
|
||||
var ditherState = ADLDitherState.DRIVER_DEFAULT;
|
||||
|
||||
if (ADLWrapper.GetDisplayDitherState(display, ref ditherState))
|
||||
{
|
||||
return ditherState;
|
||||
}
|
||||
|
||||
return ditherState;
|
||||
}
|
||||
|
||||
public string GetDisplayDeviceName(ADLDisplayInfo display)
|
||||
{
|
||||
return Screen.PrimaryScreen.DeviceName;
|
||||
}
|
||||
|
||||
public bool SetRefreshRate(uint refreshRate)
|
||||
{
|
||||
var portrait = false;
|
||||
var horizontal = 3840;
|
||||
var vertical = 2160;
|
||||
var display = GetCurrentDisplay();
|
||||
|
||||
//ADLWrapper.GetDisplayResolution(display, ref horizontal, ref vertical);
|
||||
ADLWrapper.GetDisplayResolution(display, ref horizontal, ref vertical);
|
||||
|
||||
return SetRefreshRateInternal(display, refreshRate, portrait, horizontal, vertical);
|
||||
var portrait = vertical > horizontal;
|
||||
|
||||
return SetRefreshRateInternal(GetDisplayDeviceName(display), refreshRate, portrait, horizontal, vertical);
|
||||
}
|
||||
|
||||
public List<uint> GetAvailableRefreshRates(AmdPreset preset = null)
|
||||
@@ -90,43 +213,133 @@ namespace ColorControl
|
||||
SetCurrentDisplay(preset);
|
||||
}
|
||||
|
||||
var portrait = false;
|
||||
var horizontal = 3840;
|
||||
var vertical = 2160;
|
||||
var display = GetCurrentDisplay();
|
||||
|
||||
//ADLWrapper.GetDisplayResolution(display, ref horizontal, ref vertical);
|
||||
ADLWrapper.GetDisplayResolution(display, ref horizontal, ref vertical);
|
||||
|
||||
return GetAvailableRefreshRatesInternal(display, portrait, horizontal, vertical);
|
||||
var portrait = vertical > horizontal;
|
||||
|
||||
return GetAvailableRefreshRatesInternal(GetDisplayDeviceName(display), portrait, horizontal, vertical);
|
||||
}
|
||||
|
||||
public bool IsHDREnabled()
|
||||
{
|
||||
// TODO: ADL call to get HDR state
|
||||
//var displayDevice = GetCurrentDisplay().DisplayDevice;
|
||||
//var hdr = displayDevice.HDRColorData;
|
||||
//return hdr?.HDRMode == ColorDataHDRMode.UHDA;
|
||||
return false;
|
||||
var display = GetCurrentDisplay();
|
||||
|
||||
var supported = false;
|
||||
var enabled = false;
|
||||
ADLWrapper.GetDisplayHDRState(display, ref supported, ref enabled);
|
||||
|
||||
Logger.Debug($"IsHDREnabled: supported {supported}, enabled {enabled}");
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public List<string> GetDisplays()
|
||||
public List<ADLDisplayInfo> GetDisplays()
|
||||
{
|
||||
//return ADLWrapper.GetAllDisplays();
|
||||
return null;
|
||||
var displays = ADLWrapper.GetAllDisplays();
|
||||
|
||||
//if (!displays.Any())
|
||||
//{
|
||||
// displays.Add(new ADLDisplayInfo
|
||||
// {
|
||||
// DisplayName = "Dummy"
|
||||
// });
|
||||
//}
|
||||
|
||||
return displays;
|
||||
}
|
||||
|
||||
public string GetFullDisplayName(ADLDisplayInfo display)
|
||||
{
|
||||
var name = display.DisplayName;
|
||||
|
||||
var screen = GetScreenForDisplay(display);
|
||||
if (screen != null)
|
||||
{
|
||||
name = $"{screen.DeviceName} ({name})";
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
public Screen GetScreenForDisplay(ADLDisplayInfo display)
|
||||
{
|
||||
var index = 0;
|
||||
foreach (var screen in Screen.AllScreens)
|
||||
{
|
||||
Logger.Debug($"SCREEN[{index}]: {screen.DeviceName}, {screen.DeviceFriendlyName()}, {screen.Primary}");
|
||||
index++;
|
||||
}
|
||||
return Screen.AllScreens.FirstOrDefault(x => x.DeviceFriendlyName().Equals(display.DisplayName));
|
||||
}
|
||||
|
||||
public List<AmdDisplayInfo> GetDisplayInfos()
|
||||
{
|
||||
List<ADLDisplayInfo> displays;
|
||||
try
|
||||
{
|
||||
displays = GetDisplays();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error("Error while getting displays: " + e.ToLogString());
|
||||
return null;
|
||||
}
|
||||
|
||||
var list = new List<AmdDisplayInfo>();
|
||||
|
||||
foreach (var display in displays)
|
||||
{
|
||||
var values = new List<string>();
|
||||
|
||||
var screen = GetScreenForDisplay(display);
|
||||
|
||||
var name = GetFullDisplayName(display);
|
||||
values.Add(name);
|
||||
|
||||
var colorDepth = ADLColorDepth.UNKNOWN;
|
||||
ADLWrapper.GetDisplayColorDepth(display, ref colorDepth);
|
||||
|
||||
var pixelFormat = ADLPixelFormat.UNKNOWN;
|
||||
ADLWrapper.GetDisplayPixelFormat(display, ref pixelFormat);
|
||||
|
||||
var colorSettings = $"{colorDepth}, {pixelFormat}";
|
||||
values.Add(colorSettings);
|
||||
|
||||
var refreshRate = GetCurrentRefreshRate(screen?.DeviceName);
|
||||
values.Add($"{refreshRate}Hz");
|
||||
|
||||
var ditherState = GetDithering(display);
|
||||
values.Add(ditherState.ToString());
|
||||
|
||||
var hdrEnabled = IsHDREnabled();
|
||||
values.Add(hdrEnabled ? "Yes" : "No");
|
||||
|
||||
var infoLine = string.Format("{0}: {1}, {2}Hz, HDR: {3}", name, colorSettings, refreshRate, hdrEnabled ? "Yes" : "No");
|
||||
|
||||
var displayInfo = new AmdDisplayInfo(display, values, infoLine);
|
||||
|
||||
list.Add(displayInfo);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
//if (!ADLWrapper.Initialize())
|
||||
//{
|
||||
// throw new InvalidOperationException("Cannot load AMD API");
|
||||
//}
|
||||
throw new InvalidOperationException("Cannot load AMD API");
|
||||
if (!ADLWrapper.Initialize())
|
||||
{
|
||||
throw new InvalidOperationException("Cannot load AMD API");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Uninitialize()
|
||||
{
|
||||
//ADLWrapper.Uninitialze();
|
||||
ADLWrapper.Uninitialze();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@
|
||||
<ProductName>ColorControl</ProductName>
|
||||
<PublisherName>Maassoft</PublisherName>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.3.6.0</ApplicationVersion>
|
||||
<ApplicationVersion>2.0.0.0</ApplicationVersion>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<PublishWizardCompleted>true</PublishWizardCompleted>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
@@ -172,9 +172,21 @@
|
||||
<Reference Include="WindowsBase" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ADL.cs" />
|
||||
<Compile Include="ADLWrapper.cs" />
|
||||
<Compile Include="AmdDisplayInfo.cs" />
|
||||
<Compile Include="ServiceBase.cs" />
|
||||
<Compile Include="NvDisplayInfo.cs" />
|
||||
<Compile Include="MessageForms.cs" />
|
||||
<Compile Include="GraphicsService.cs" />
|
||||
<Compile Include="AmdService.cs" />
|
||||
<Compile Include="AmdPreset.cs" />
|
||||
<Compile Include="RemoteControlForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="RemoteControlForm.Designer.cs">
|
||||
<DependentUpon>RemoteControlForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="StartUpParams.cs" />
|
||||
<Compile Include="LgServiceConfig.cs" />
|
||||
<Compile Include="WOL.cs" />
|
||||
@@ -223,6 +235,9 @@
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="RemoteControlForm.resx">
|
||||
<DependentUpon>RemoteControlForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<None Include="ColorControl_TemporaryKey.pfx" />
|
||||
<Content Include="LgPresets.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
public int FormWidth { get; set; }
|
||||
public int FormHeight { get; set; }
|
||||
|
||||
public int NvPresetId_ApplyOnStartup { get; set; }
|
||||
|
||||
public int AmdPresetId_ApplyOnStartup { get; set; }
|
||||
|
||||
public Config()
|
||||
{
|
||||
DisplaySettingsDelay = 1000;
|
||||
|
||||
@@ -9,11 +9,15 @@ using System.Threading;
|
||||
|
||||
namespace ColorControl
|
||||
{
|
||||
class GraphicsService
|
||||
class GraphicsService : ServiceBase
|
||||
{
|
||||
protected static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool EnumDisplaySettingsA(string deviceName, int modeNum, out DEVMODEA devMode);
|
||||
|
||||
public GraphicsService()
|
||||
const int ENUM_CURRENT_SETTINGS = -1;
|
||||
const int ENUM_REGISTRY_SETTINGS = -2;
|
||||
|
||||
public GraphicsService(string dataPath) : base(dataPath)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
@@ -23,16 +27,6 @@ namespace ColorControl
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
protected virtual void Initialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected virtual void Uninitialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected void ToggleHDR(int delay = 1000)
|
||||
{
|
||||
Process.Start("ms-settings:display");
|
||||
@@ -48,6 +42,18 @@ namespace ColorControl
|
||||
}
|
||||
}
|
||||
|
||||
protected void OpenDisplaySettings(int delay = 1000)
|
||||
{
|
||||
Process.Start("ms-settings:display");
|
||||
Thread.Sleep(delay);
|
||||
|
||||
var process = Process.GetProcessesByName("SystemSettings").FirstOrDefault();
|
||||
if (process != null)
|
||||
{
|
||||
System.Windows.Forms.SendKeys.SendWait("%{F4}");
|
||||
}
|
||||
}
|
||||
|
||||
protected bool SetRefreshRateInternal(string displayName, uint refreshRate, bool portrait, int horizontal, int vertical)
|
||||
{
|
||||
uint i = 0;
|
||||
@@ -93,5 +99,15 @@ namespace ColorControl
|
||||
return list;
|
||||
}
|
||||
|
||||
protected uint GetCurrentRefreshRate(string displayName)
|
||||
{
|
||||
DEVMODEA devMode;
|
||||
// NativeMethods defines modeNum as an 'uint' but we need to pass '-1'
|
||||
if (EnumDisplaySettingsA(displayName, ENUM_CURRENT_SETTINGS, out devMode))
|
||||
{
|
||||
return devMode.dmDisplayFrequency;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ namespace ColorControl
|
||||
return new List<string>() { "Name", "App|200", "Steps|400", "Shortcut" };
|
||||
}
|
||||
|
||||
public List<string> GetDisplayValues()
|
||||
public override List<string> GetDisplayValues(Config config = null)
|
||||
{
|
||||
var values = new List<string>();
|
||||
|
||||
|
||||
+299
-51
@@ -1,16 +1,13 @@
|
||||
using LgTv;
|
||||
using Newtonsoft.Json;
|
||||
using NLog.Config;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Script.Serialization;
|
||||
using System.Windows.Forms;
|
||||
using Windows.Data.Json;
|
||||
|
||||
namespace ColorControl
|
||||
{
|
||||
@@ -20,7 +17,7 @@ namespace ColorControl
|
||||
|
||||
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
public string FriendlyScreenName { get; private set; }
|
||||
//public string FriendlyScreenName { get; private set; }
|
||||
|
||||
public List<PnpDev> Devices { get; private set; }
|
||||
public PnpDev SelectedDevice
|
||||
@@ -35,34 +32,109 @@ namespace ColorControl
|
||||
|
||||
public LgServiceConfig Config { get; private set; }
|
||||
|
||||
private List<LgPreset> _lgPresets;
|
||||
private string _lgPresetsFilename;
|
||||
|
||||
private LgTvApi _lgTvApi;
|
||||
private string _dataDir;
|
||||
private string _configFilename;
|
||||
private bool _allowPowerOn;
|
||||
private bool _justWokeUp;
|
||||
private PnpDev _selectedDevice;
|
||||
private string _rcButtonsFilename;
|
||||
private List<LgPreset> _remoteControlButtons;
|
||||
private List<LgApp> _lgApps = new List<LgApp>();
|
||||
|
||||
private JavaScriptSerializer _JsonSerializer = new JavaScriptSerializer();
|
||||
private JavaScriptSerializer _JsonDeserializer = new JavaScriptSerializer();
|
||||
|
||||
private Dictionary<string, Func<bool>> _invokableActions = new Dictionary<string, Func<bool>>();
|
||||
|
||||
public LgService(string dataDir, bool allowPowerOn)
|
||||
{
|
||||
_dataDir = dataDir;
|
||||
_allowPowerOn = allowPowerOn;
|
||||
|
||||
_invokableActions.Add("WOL", new Func<bool>(WakeSelectedDevice));
|
||||
|
||||
LgPreset.LgApps = _lgApps;
|
||||
|
||||
LoadConfig();
|
||||
LoadPresets();
|
||||
LoadRemoteControlButtons();
|
||||
|
||||
foreach (var screen in Screen.AllScreens)
|
||||
{
|
||||
var name = screen.DeviceFriendlyName();
|
||||
if (name.Contains("LG"))
|
||||
{
|
||||
FriendlyScreenName = name;
|
||||
}
|
||||
}
|
||||
//foreach (var screen in Screen.AllScreens)
|
||||
//{
|
||||
// var name = screen.DeviceFriendlyName();
|
||||
// if (name.Contains("LG"))
|
||||
// {
|
||||
// FriendlyScreenName = name;
|
||||
// }
|
||||
//}
|
||||
|
||||
RefreshDevices();
|
||||
var _ = RefreshDevices(afterStartUp: true);
|
||||
}
|
||||
|
||||
~LgService()
|
||||
{
|
||||
GlobalSave();
|
||||
}
|
||||
|
||||
public void GlobalSave()
|
||||
{
|
||||
SaveConfig();
|
||||
SavePresets();
|
||||
SaveRemoteControlButtons();
|
||||
}
|
||||
|
||||
public List<LgPreset> GetPresets()
|
||||
{
|
||||
return _lgPresets;
|
||||
}
|
||||
|
||||
public LgPreset CreateNewPreset()
|
||||
{
|
||||
var preset = new LgPreset();
|
||||
var name = "New preset";
|
||||
string fullname;
|
||||
var number = 1;
|
||||
do
|
||||
{
|
||||
fullname = $"{name} ({number})";
|
||||
number++;
|
||||
} while (_lgPresets.Any(x => x.name.Equals(fullname)));
|
||||
|
||||
preset.name = fullname;
|
||||
|
||||
return preset;
|
||||
}
|
||||
|
||||
private void LoadPresets()
|
||||
{
|
||||
_lgPresetsFilename = Path.Combine(_dataDir, "LgPresets.json");
|
||||
var toCopy = Path.Combine(Directory.GetCurrentDirectory(), "LgPresets.json");
|
||||
if (!File.Exists(_lgPresetsFilename) && File.Exists(toCopy))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Copy(toCopy, _lgPresetsFilename);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Error while copying {toCopy} to {_lgPresetsFilename}: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
if (File.Exists(_lgPresetsFilename))
|
||||
{
|
||||
var json = File.ReadAllText(_lgPresetsFilename);
|
||||
|
||||
_lgPresets = _JsonDeserializer.Deserialize<List<LgPreset>>(json);
|
||||
}
|
||||
else
|
||||
{
|
||||
_lgPresets = new List<LgPreset>();
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadConfig()
|
||||
@@ -78,25 +150,133 @@ namespace ColorControl
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveConfig()
|
||||
private void LoadRemoteControlButtons()
|
||||
{
|
||||
var defaultButtons = GenerateDefaultRemoteControlButtons();
|
||||
|
||||
_rcButtonsFilename = Path.Combine(_dataDir, "LgRemoteControlButtons.json");
|
||||
//if (File.Exists(_rcButtonsFilename))
|
||||
//{
|
||||
// var json = File.ReadAllText(_rcButtonsFilename);
|
||||
|
||||
// _remoteControlButtons = _JsonDeserializer.Deserialize<List<LgPreset>>(json);
|
||||
|
||||
// var missingButtons = defaultButtons.Where(b => !_remoteControlButtons.Any(x => x.name.Equals(b.name)));
|
||||
// _remoteControlButtons.AddRange(missingButtons);
|
||||
//}
|
||||
//else
|
||||
{
|
||||
_remoteControlButtons = defaultButtons;
|
||||
}
|
||||
}
|
||||
|
||||
public List<LgPreset> GetRemoteControlButtons()
|
||||
{
|
||||
return _remoteControlButtons;
|
||||
}
|
||||
|
||||
public Dictionary<string, Func<bool>> GetInvokableActions()
|
||||
{
|
||||
return _invokableActions;
|
||||
}
|
||||
|
||||
private List<LgPreset> GenerateDefaultRemoteControlButtons()
|
||||
{
|
||||
var list = new List<LgPreset>();
|
||||
|
||||
for (var i = 1; i < 11; i++)
|
||||
{
|
||||
var button = i < 10 ? i : 0;
|
||||
list.Add(GeneratePreset(button.ToString()));
|
||||
}
|
||||
|
||||
list.Add(GeneratePreset("Settings", appId: "com.palm.app.settings", key: Keys.S));
|
||||
|
||||
list.Add(GeneratePreset("Vol +", step: "VOLUMEUP", key: Keys.VolumeUp));
|
||||
list.Add(GeneratePreset("Vol -", step: "VOLUMEDOWN", key: Keys.VolumeDown));
|
||||
list.Add(GeneratePreset("Mute", step: "MUTE", key: Keys.VolumeMute));
|
||||
|
||||
list.Add(GeneratePreset("Up", step: "UP", key: Keys.Up));
|
||||
list.Add(GeneratePreset("Down", step: "DOWN", key: Keys.Down));
|
||||
list.Add(GeneratePreset("Left", step: "LEFT", key: Keys.Left));
|
||||
list.Add(GeneratePreset("Right", step: "RIGHT", key: Keys.Right));
|
||||
|
||||
list.Add(GeneratePreset("Enter", step: "ENTER", key: Keys.Enter));
|
||||
list.Add(GeneratePreset("Back", step: "BACK", key: Keys.Back));
|
||||
list.Add(GeneratePreset("Exit", step: "EXIT", key: Keys.Escape));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private LgPreset GeneratePreset(string name, string step = null, string appId = null, Keys key = Keys.None)
|
||||
{
|
||||
var preset = new LgPreset();
|
||||
|
||||
var cvt = new KeysConverter();
|
||||
var shortcut = key != Keys.None ? (string)cvt.ConvertTo(key, typeof(string)) : null;
|
||||
|
||||
preset.name = name;
|
||||
preset.appId = appId;
|
||||
preset.shortcut = shortcut;
|
||||
if (appId == null)
|
||||
{
|
||||
preset.steps.Add(step == null ? name : step);
|
||||
}
|
||||
|
||||
return preset;
|
||||
}
|
||||
|
||||
private void SavePresets()
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = _JsonSerializer.Serialize(_lgPresets);
|
||||
File.WriteAllText(_lgPresetsFilename, json);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e.ToLogString());
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveConfig()
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(Config);
|
||||
File.WriteAllText(_configFilename, json);
|
||||
}
|
||||
|
||||
public async Task RefreshDevices(bool connect = true)
|
||||
private void SaveRemoteControlButtons()
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(_remoteControlButtons);
|
||||
File.WriteAllText(_rcButtonsFilename, json);
|
||||
}
|
||||
|
||||
public async Task RefreshDevices(bool connect = true, bool afterStartUp = false)
|
||||
{
|
||||
var devices = await Utils.GetPnpDevices(Config.DeviceSearchKey);
|
||||
SetDevices(devices);
|
||||
|
||||
if (afterStartUp && SelectedDevice == null && Config.PowerOnAfterStartup && !string.IsNullOrEmpty(Config.PreferredMacAddress))
|
||||
{
|
||||
Logger.Debug("No device has been found, trying to wake it first...");
|
||||
|
||||
WakeSelectedDevice(Config.PreferredMacAddress);
|
||||
|
||||
await Task.Delay(4000);
|
||||
await RefreshDevices();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (connect && SelectedDevice != null)
|
||||
{
|
||||
if (Config.PowerOnAfterStartup && _allowPowerOn)
|
||||
{
|
||||
WakeAndConnectToSelectedDevice(0);
|
||||
var _ = WakeAndConnectToSelectedDeviceWithRetries();
|
||||
}
|
||||
else
|
||||
{
|
||||
ConnectToSelectedDevice();
|
||||
var _ = ConnectToSelectedDevice();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,6 +298,8 @@ namespace ColorControl
|
||||
{
|
||||
DisposeConnection();
|
||||
_lgTvApi = await LgTvApi.CreateLgTvApi(SelectedDevice.IpAddress, retries);
|
||||
|
||||
//_lgTvApi.GetServiceList();
|
||||
return _lgTvApi != null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -152,6 +334,17 @@ namespace ColorControl
|
||||
{
|
||||
var hasApp = !string.IsNullOrEmpty(preset.appId);
|
||||
|
||||
var hasWOL = preset.steps.Any(s => s.Equals("WOL", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (hasWOL)
|
||||
{
|
||||
var connected = await WakeAndConnectToSelectedDevice(0);
|
||||
if (!connected)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (var tries = 0; tries <= 1; tries++)
|
||||
{
|
||||
if (!await Connected(reconnect || tries == 1))
|
||||
@@ -225,13 +418,19 @@ namespace ColorControl
|
||||
foreach (var step in preset.steps)
|
||||
{
|
||||
var keySpec = step.Split(':');
|
||||
var key = keySpec[0].ToUpper();
|
||||
if (_invokableActions.ContainsKey(key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (keySpec.Length == 2)
|
||||
{
|
||||
SendKey(mouse, keySpec[0], int.Parse(keySpec[1]));
|
||||
SendKey(mouse, key, int.Parse(keySpec[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
SendKey(mouse, keySpec[0]);
|
||||
SendKey(mouse, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,23 +446,30 @@ namespace ColorControl
|
||||
Thread.Sleep(delay);
|
||||
}
|
||||
|
||||
public async Task<List<LgApp>> RefreshApps(bool force = false)
|
||||
public async Task<LgWebOsMouseService> GetMouseAsync()
|
||||
{
|
||||
return await _lgTvApi.GetMouse();
|
||||
}
|
||||
|
||||
public async Task RefreshApps(bool force = false)
|
||||
{
|
||||
if (SelectedDevice == null)
|
||||
{
|
||||
Logger.Debug("Cannot refresh apps: no device has been selected");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!await Connected(force))
|
||||
{
|
||||
Logger.Debug("Cannot refresh apps: no connection could be made");
|
||||
return null;
|
||||
}
|
||||
|
||||
var list = await _lgTvApi.GetApps(force);
|
||||
_lgApps.Clear();
|
||||
_lgApps.AddRange(await _lgTvApi.GetApps(force));
|
||||
}
|
||||
|
||||
return list.ToList();
|
||||
public List<LgApp> GetApps()
|
||||
{
|
||||
return _lgApps;
|
||||
}
|
||||
|
||||
internal void DisposeConnection()
|
||||
@@ -286,52 +492,94 @@ namespace ColorControl
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void WakeSelectedDevice()
|
||||
internal bool WakeSelectedDevice()
|
||||
{
|
||||
if (SelectedDevice != null)
|
||||
return WakeSelectedDevice(SelectedDevice?.MacAddress ?? Config.PreferredMacAddress);
|
||||
}
|
||||
|
||||
internal bool WakeSelectedDevice(string macAddress)
|
||||
{
|
||||
var result = false;
|
||||
|
||||
macAddress = string.IsNullOrEmpty(macAddress) ? SelectedDevice?.MacAddress : macAddress;
|
||||
if (macAddress != null)
|
||||
{
|
||||
WOL.WakeFunction(SelectedDevice.MacAddress);
|
||||
result = WOL.WakeFunction(macAddress, Config.UseOldNpcapWol);
|
||||
_justWokeUp = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Debug("Cannot wake device: no device has been selected");
|
||||
Logger.Debug("Cannot wake device: no device has been selected or there is no preferred MAC-address stored in the configuration");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void WakeAfterResume()
|
||||
{
|
||||
if (Config.PowerOnAfterResume)
|
||||
{
|
||||
WakeAndConnectToSelectedDevice(Config.PowerOnDelayAfterResume);
|
||||
var _ = WakeAndConnectToSelectedDeviceWithRetries();
|
||||
}
|
||||
}
|
||||
|
||||
private void WakeAndConnectToSelectedDevice(int wakeDelay = 5000, int connectDelay = 1000)
|
||||
private async Task<bool> WakeAndConnectToSelectedDeviceWithRetries()
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
//if (wakeDelay == 0)
|
||||
//{
|
||||
// if (await ConnectToSelectedDevice())
|
||||
// {
|
||||
// Logger.Debug("Already connected, no wake needed?");
|
||||
// return;
|
||||
// };
|
||||
//}
|
||||
var wakeDelay = 0;
|
||||
var maxRetries = Config.PowerOnRetries <= 1 ? 5 : Config.PowerOnRetries;
|
||||
|
||||
await Task.Delay(wakeDelay);
|
||||
WakeSelectedDevice();
|
||||
await Task.Delay(connectDelay);
|
||||
await ConnectToSelectedDevice();
|
||||
}
|
||||
catch (Exception e)
|
||||
var result = false;
|
||||
for (var retry = 0; retry < maxRetries && !result; retry++)
|
||||
{
|
||||
Logger.Debug($"WakeAndConnectToSelectedDeviceWithRetries: attempt {retry + 1} of {maxRetries}...");
|
||||
|
||||
var ms = DateTimeOffset.Now.ToUnixTimeMilliseconds();
|
||||
result = await WakeAndConnectToSelectedDevice(retry == 0 ? wakeDelay : 0);
|
||||
ms = DateTimeOffset.Now.ToUnixTimeMilliseconds() - ms;
|
||||
if (!result)
|
||||
{
|
||||
Logger.Error("WakeAndConnectToSelectedDevice: " + e.ToLogString());
|
||||
var delay = 2000 - ms;
|
||||
if (delay > 0)
|
||||
{
|
||||
await Task.Delay((int)delay);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<bool> WakeAndConnectToSelectedDevice(int wakeDelay = 5000, int connectDelay = 500)
|
||||
{
|
||||
try
|
||||
{
|
||||
//if (wakeDelay == 0)
|
||||
//{
|
||||
// if (await ConnectToSelectedDevice())
|
||||
// {
|
||||
// Logger.Debug("Already connected, no wake needed?");
|
||||
// return;
|
||||
// };
|
||||
//}
|
||||
|
||||
await Task.Delay(wakeDelay);
|
||||
var result = WakeSelectedDevice();
|
||||
if (!result)
|
||||
{
|
||||
Logger.Debug("WOL failed");
|
||||
return false;
|
||||
}
|
||||
Logger.Debug("WOL succeeded");
|
||||
await Task.Delay(connectDelay);
|
||||
result = await ConnectToSelectedDevice();
|
||||
Logger.Debug("Connect succeeded: " + result);
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error("WakeAndConnectToSelectedDevice: " + e.ToLogString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,14 +12,19 @@
|
||||
|
||||
public int PowerOnDelayAfterResume { get; set; }
|
||||
|
||||
public int PowerOnRetries { get; set; }
|
||||
|
||||
public string PreferredMacAddress { get; set; }
|
||||
|
||||
public string DeviceSearchKey { get; set; }
|
||||
|
||||
public bool UseOldNpcapWol { get; set; }
|
||||
|
||||
public LgServiceConfig()
|
||||
{
|
||||
PowerOnDelayAfterResume = 5000;
|
||||
DeviceSearchKey = "[LG]";
|
||||
PowerOnRetries = 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+646
-79
@@ -42,6 +42,7 @@
|
||||
this.btnChange = new System.Windows.Forms.Button();
|
||||
this.mnuNvPresets = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.miNvApply = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miNvPresetApplyOnStartup = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuNvDisplay = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miNvPrimaryDisplay = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -52,6 +53,16 @@
|
||||
this.miNvPresetDithering = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miNvPresetApplyDithering = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miNvPresetDitheringEnabled = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuNvDitheringBitDepth = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miNvDithering6bit = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miNvDithering8bit = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miNvDithering10bit = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuNvDitheringMode = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.spatial1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.spatial2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.spatialDynamic2x2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.spatialStatic2x2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.temporalToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miNvHDR = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miHDRIncluded = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miToggleHDR = new System.Windows.Forms.ToolStripMenuItem();
|
||||
@@ -59,11 +70,40 @@
|
||||
this.btnApply = new System.Windows.Forms.Button();
|
||||
this.lvNvPresets = new System.Windows.Forms.ListView();
|
||||
this.tabAMD = new System.Windows.Forms.TabPage();
|
||||
this.btnAddAmd = new System.Windows.Forms.Button();
|
||||
this.lblErrorAMD = new System.Windows.Forms.Label();
|
||||
this.btnDeleteAmd = new System.Windows.Forms.Button();
|
||||
this.btnCloneAmd = new System.Windows.Forms.Button();
|
||||
this.btnSetAmdShortcut = new System.Windows.Forms.Button();
|
||||
this.lblAmdShortcut = new System.Windows.Forms.Label();
|
||||
this.edtAmdShortcut = new System.Windows.Forms.TextBox();
|
||||
this.btnChangeAmd = new System.Windows.Forms.Button();
|
||||
this.mnuAmdPresets = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.miAmdApply = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miAmdPresetApplyOnStartup = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuAmdDisplay = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miAmdPrimaryDisplay = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuAmdColorSettings = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miAmdColorSettingsIncluded = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuAmdRefreshRate = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miAmdRefreshRateIncluded = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuAmdDithering = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miAmdDitheringIncluded = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuAmdHDR = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miAmdHDRIncluded = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miAmdHDRToggle = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miAmdHDREnabled = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.btnApplyAmd = new System.Windows.Forms.Button();
|
||||
this.lvAmdPresets = new System.Windows.Forms.ListView();
|
||||
this.tabLG = new System.Windows.Forms.TabPage();
|
||||
this.btnLGRemoteControl = new System.Windows.Forms.Button();
|
||||
this.btnLgDeviceFilterRefresh = new System.Windows.Forms.Button();
|
||||
this.clbLgPower = new System.Windows.Forms.CheckedListBox();
|
||||
this.btnLgAddButton = new System.Windows.Forms.Button();
|
||||
this.mnuLgButtons = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.mnuLgRcButtons = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuLgActions = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.cbxLgDevices = new System.Windows.Forms.ComboBox();
|
||||
this.btnLgRefreshApps = new System.Windows.Forms.Button();
|
||||
@@ -85,17 +125,25 @@
|
||||
this.btnApplyLg = new System.Windows.Forms.Button();
|
||||
this.lvLgPresets = new System.Windows.Forms.ListView();
|
||||
this.tabOptions = new System.Windows.Forms.TabPage();
|
||||
this.grpNvidiaOptions = new System.Windows.Forms.GroupBox();
|
||||
this.lblDitheringMode = new System.Windows.Forms.Label();
|
||||
this.cbxDitheringMode = new System.Windows.Forms.ComboBox();
|
||||
this.lblDitheringBitDepth = new System.Windows.Forms.Label();
|
||||
this.cbxDitheringBitDepth = new System.Windows.Forms.ComboBox();
|
||||
this.chkDitheringEnabled = new System.Windows.Forms.CheckBox();
|
||||
this.pbGradient = new System.Windows.Forms.PictureBox();
|
||||
this.grpMiscellaneousOptions = new System.Windows.Forms.GroupBox();
|
||||
this.btnSetShortcutScreenSaver = new System.Windows.Forms.Button();
|
||||
this.label11 = new System.Windows.Forms.Label();
|
||||
this.edtBlankScreenSaverShortcut = new System.Windows.Forms.TextBox();
|
||||
this.label10 = new System.Windows.Forms.Label();
|
||||
this.lblFixChromeFontsDescription = new System.Windows.Forms.Label();
|
||||
this.chkFixChromeFonts = new System.Windows.Forms.CheckBox();
|
||||
this.grpLGOptions = new System.Windows.Forms.GroupBox();
|
||||
this.chkLgOldWolMechanism = new System.Windows.Forms.CheckBox();
|
||||
this.btnLGTestPower = new System.Windows.Forms.Button();
|
||||
this.label9 = new System.Windows.Forms.Label();
|
||||
this.edtLgPowerOnAfterResumeDelay = new System.Windows.Forms.NumericUpDown();
|
||||
this.label8 = new System.Windows.Forms.Label();
|
||||
this.lblLgMaxPowerOnRetriesDescription = new System.Windows.Forms.Label();
|
||||
this.edtLgMaxPowerOnRetries = new System.Windows.Forms.NumericUpDown();
|
||||
this.lblLgMaxPowerOnRetries = new System.Windows.Forms.Label();
|
||||
this.grpHDROptions = new System.Windows.Forms.GroupBox();
|
||||
this.edtDelayDisplaySettings = new System.Windows.Forms.NumericUpDown();
|
||||
this.label6 = new System.Windows.Forms.Label();
|
||||
@@ -114,16 +162,19 @@
|
||||
this.lbPlugins = new System.Windows.Forms.ListBox();
|
||||
this.label7 = new System.Windows.Forms.Label();
|
||||
this.lblInfo = new System.Windows.Forms.Label();
|
||||
this.btnLgDeviceFilterRefresh = new System.Windows.Forms.Button();
|
||||
this.tcMain.SuspendLayout();
|
||||
this.tabNVIDIA.SuspendLayout();
|
||||
this.mnuNvPresets.SuspendLayout();
|
||||
this.tabAMD.SuspendLayout();
|
||||
this.mnuAmdPresets.SuspendLayout();
|
||||
this.tabLG.SuspendLayout();
|
||||
this.mnuLgButtons.SuspendLayout();
|
||||
this.tabOptions.SuspendLayout();
|
||||
this.grpNvidiaOptions.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pbGradient)).BeginInit();
|
||||
this.grpMiscellaneousOptions.SuspendLayout();
|
||||
this.grpLGOptions.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.edtLgPowerOnAfterResumeDelay)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.edtLgMaxPowerOnRetries)).BeginInit();
|
||||
this.grpHDROptions.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.edtDelayDisplaySettings)).BeginInit();
|
||||
this.grpGeneralOptions.SuspendLayout();
|
||||
@@ -269,6 +320,7 @@
|
||||
this.mnuNvPresets.ImageScalingSize = new System.Drawing.Size(20, 20);
|
||||
this.mnuNvPresets.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.miNvApply,
|
||||
this.miNvPresetApplyOnStartup,
|
||||
this.toolStripSeparator1,
|
||||
this.mnuNvDisplay,
|
||||
this.mnuNvPresetsColorSettings,
|
||||
@@ -276,27 +328,35 @@
|
||||
this.miNvPresetDithering,
|
||||
this.miNvHDR});
|
||||
this.mnuNvPresets.Name = "mnuNvPresets";
|
||||
this.mnuNvPresets.Size = new System.Drawing.Size(148, 142);
|
||||
this.mnuNvPresets.Size = new System.Drawing.Size(163, 164);
|
||||
this.mnuNvPresets.Opening += new System.ComponentModel.CancelEventHandler(this.mnuNvPresets_Opening);
|
||||
//
|
||||
// miNvApply
|
||||
//
|
||||
this.miNvApply.Name = "miNvApply";
|
||||
this.miNvApply.Size = new System.Drawing.Size(147, 22);
|
||||
this.miNvApply.Size = new System.Drawing.Size(162, 22);
|
||||
this.miNvApply.Text = "Apply";
|
||||
this.miNvApply.Click += new System.EventHandler(this.miNvApply_Click);
|
||||
this.miNvApply.Click += new System.EventHandler(this.btnApply_Click);
|
||||
//
|
||||
// miNvPresetApplyOnStartup
|
||||
//
|
||||
this.miNvPresetApplyOnStartup.CheckOnClick = true;
|
||||
this.miNvPresetApplyOnStartup.Name = "miNvPresetApplyOnStartup";
|
||||
this.miNvPresetApplyOnStartup.Size = new System.Drawing.Size(162, 22);
|
||||
this.miNvPresetApplyOnStartup.Text = "Apply on startup";
|
||||
this.miNvPresetApplyOnStartup.Click += new System.EventHandler(this.miNvPresetApplyOnStartup_Click);
|
||||
//
|
||||
// toolStripSeparator1
|
||||
//
|
||||
this.toolStripSeparator1.Name = "toolStripSeparator1";
|
||||
this.toolStripSeparator1.Size = new System.Drawing.Size(144, 6);
|
||||
this.toolStripSeparator1.Size = new System.Drawing.Size(159, 6);
|
||||
//
|
||||
// mnuNvDisplay
|
||||
//
|
||||
this.mnuNvDisplay.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.miNvPrimaryDisplay});
|
||||
this.mnuNvDisplay.Name = "mnuNvDisplay";
|
||||
this.mnuNvDisplay.Size = new System.Drawing.Size(147, 22);
|
||||
this.mnuNvDisplay.Size = new System.Drawing.Size(162, 22);
|
||||
this.mnuNvDisplay.Text = "Display";
|
||||
//
|
||||
// miNvPrimaryDisplay
|
||||
@@ -311,7 +371,7 @@
|
||||
this.mnuNvPresetsColorSettings.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.miNvPresetColorSettings});
|
||||
this.mnuNvPresetsColorSettings.Name = "mnuNvPresetsColorSettings";
|
||||
this.mnuNvPresetsColorSettings.Size = new System.Drawing.Size(147, 22);
|
||||
this.mnuNvPresetsColorSettings.Size = new System.Drawing.Size(162, 22);
|
||||
this.mnuNvPresetsColorSettings.Text = "Color settings";
|
||||
//
|
||||
// miNvPresetColorSettings
|
||||
@@ -326,7 +386,7 @@
|
||||
this.mnuRefreshRate.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.miRefreshRateIncluded});
|
||||
this.mnuRefreshRate.Name = "mnuRefreshRate";
|
||||
this.mnuRefreshRate.Size = new System.Drawing.Size(147, 22);
|
||||
this.mnuRefreshRate.Size = new System.Drawing.Size(162, 22);
|
||||
this.mnuRefreshRate.Text = "Refresh Rate";
|
||||
//
|
||||
// miRefreshRateIncluded
|
||||
@@ -340,25 +400,113 @@
|
||||
//
|
||||
this.miNvPresetDithering.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.miNvPresetApplyDithering,
|
||||
this.miNvPresetDitheringEnabled});
|
||||
this.miNvPresetDitheringEnabled,
|
||||
this.mnuNvDitheringBitDepth,
|
||||
this.mnuNvDitheringMode});
|
||||
this.miNvPresetDithering.Name = "miNvPresetDithering";
|
||||
this.miNvPresetDithering.Size = new System.Drawing.Size(147, 22);
|
||||
this.miNvPresetDithering.Size = new System.Drawing.Size(162, 22);
|
||||
this.miNvPresetDithering.Text = "Dithering";
|
||||
//
|
||||
// miNvPresetApplyDithering
|
||||
//
|
||||
this.miNvPresetApplyDithering.Name = "miNvPresetApplyDithering";
|
||||
this.miNvPresetApplyDithering.Size = new System.Drawing.Size(120, 22);
|
||||
this.miNvPresetApplyDithering.Size = new System.Drawing.Size(122, 22);
|
||||
this.miNvPresetApplyDithering.Text = "Included";
|
||||
this.miNvPresetApplyDithering.Click += new System.EventHandler(this.miNvPresetApplyDithering_Click);
|
||||
//
|
||||
// miNvPresetDitheringEnabled
|
||||
//
|
||||
this.miNvPresetDitheringEnabled.Name = "miNvPresetDitheringEnabled";
|
||||
this.miNvPresetDitheringEnabled.Size = new System.Drawing.Size(120, 22);
|
||||
this.miNvPresetDitheringEnabled.Size = new System.Drawing.Size(122, 22);
|
||||
this.miNvPresetDitheringEnabled.Text = "Enabled";
|
||||
this.miNvPresetDitheringEnabled.Click += new System.EventHandler(this.miNvPresetDitheringEnabled_Click);
|
||||
//
|
||||
// mnuNvDitheringBitDepth
|
||||
//
|
||||
this.mnuNvDitheringBitDepth.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.miNvDithering6bit,
|
||||
this.miNvDithering8bit,
|
||||
this.miNvDithering10bit});
|
||||
this.mnuNvDitheringBitDepth.Name = "mnuNvDitheringBitDepth";
|
||||
this.mnuNvDitheringBitDepth.Size = new System.Drawing.Size(122, 22);
|
||||
this.mnuNvDitheringBitDepth.Text = "Bit depth";
|
||||
//
|
||||
// miNvDithering6bit
|
||||
//
|
||||
this.miNvDithering6bit.Name = "miNvDithering6bit";
|
||||
this.miNvDithering6bit.Size = new System.Drawing.Size(105, 22);
|
||||
this.miNvDithering6bit.Tag = "0";
|
||||
this.miNvDithering6bit.Text = "6-bit";
|
||||
this.miNvDithering6bit.Click += new System.EventHandler(this.miNvDithering6bit_Click);
|
||||
//
|
||||
// miNvDithering8bit
|
||||
//
|
||||
this.miNvDithering8bit.Name = "miNvDithering8bit";
|
||||
this.miNvDithering8bit.Size = new System.Drawing.Size(105, 22);
|
||||
this.miNvDithering8bit.Tag = "1";
|
||||
this.miNvDithering8bit.Text = "8-bit";
|
||||
this.miNvDithering8bit.Click += new System.EventHandler(this.miNvDithering6bit_Click);
|
||||
//
|
||||
// miNvDithering10bit
|
||||
//
|
||||
this.miNvDithering10bit.Name = "miNvDithering10bit";
|
||||
this.miNvDithering10bit.Size = new System.Drawing.Size(105, 22);
|
||||
this.miNvDithering10bit.Tag = "2";
|
||||
this.miNvDithering10bit.Text = "10-bit";
|
||||
this.miNvDithering10bit.Click += new System.EventHandler(this.miNvDithering6bit_Click);
|
||||
//
|
||||
// mnuNvDitheringMode
|
||||
//
|
||||
this.mnuNvDitheringMode.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.spatial1ToolStripMenuItem,
|
||||
this.spatial2ToolStripMenuItem,
|
||||
this.spatialDynamic2x2ToolStripMenuItem,
|
||||
this.spatialStatic2x2ToolStripMenuItem,
|
||||
this.temporalToolStripMenuItem});
|
||||
this.mnuNvDitheringMode.Name = "mnuNvDitheringMode";
|
||||
this.mnuNvDitheringMode.Size = new System.Drawing.Size(122, 22);
|
||||
this.mnuNvDitheringMode.Text = "Mode";
|
||||
//
|
||||
// spatial1ToolStripMenuItem
|
||||
//
|
||||
this.spatial1ToolStripMenuItem.Name = "spatial1ToolStripMenuItem";
|
||||
this.spatial1ToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.spatial1ToolStripMenuItem.Tag = "0";
|
||||
this.spatial1ToolStripMenuItem.Text = "Spatial Dynamic";
|
||||
this.spatial1ToolStripMenuItem.Click += new System.EventHandler(this.spatial1ToolStripMenuItem_Click);
|
||||
//
|
||||
// spatial2ToolStripMenuItem
|
||||
//
|
||||
this.spatial2ToolStripMenuItem.Name = "spatial2ToolStripMenuItem";
|
||||
this.spatial2ToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.spatial2ToolStripMenuItem.Tag = "1";
|
||||
this.spatial2ToolStripMenuItem.Text = "Spatial Static";
|
||||
this.spatial2ToolStripMenuItem.Click += new System.EventHandler(this.spatial1ToolStripMenuItem_Click);
|
||||
//
|
||||
// spatialDynamic2x2ToolStripMenuItem
|
||||
//
|
||||
this.spatialDynamic2x2ToolStripMenuItem.Name = "spatialDynamic2x2ToolStripMenuItem";
|
||||
this.spatialDynamic2x2ToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.spatialDynamic2x2ToolStripMenuItem.Tag = "2";
|
||||
this.spatialDynamic2x2ToolStripMenuItem.Text = "Spatial Dynamic 2x2";
|
||||
this.spatialDynamic2x2ToolStripMenuItem.Click += new System.EventHandler(this.spatial1ToolStripMenuItem_Click);
|
||||
//
|
||||
// spatialStatic2x2ToolStripMenuItem
|
||||
//
|
||||
this.spatialStatic2x2ToolStripMenuItem.Name = "spatialStatic2x2ToolStripMenuItem";
|
||||
this.spatialStatic2x2ToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.spatialStatic2x2ToolStripMenuItem.Tag = "3";
|
||||
this.spatialStatic2x2ToolStripMenuItem.Text = "Spatial Static 2x2";
|
||||
this.spatialStatic2x2ToolStripMenuItem.Click += new System.EventHandler(this.spatial1ToolStripMenuItem_Click);
|
||||
//
|
||||
// temporalToolStripMenuItem
|
||||
//
|
||||
this.temporalToolStripMenuItem.Name = "temporalToolStripMenuItem";
|
||||
this.temporalToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
|
||||
this.temporalToolStripMenuItem.Tag = "4";
|
||||
this.temporalToolStripMenuItem.Text = "Temporal";
|
||||
this.temporalToolStripMenuItem.Click += new System.EventHandler(this.spatial1ToolStripMenuItem_Click);
|
||||
//
|
||||
// miNvHDR
|
||||
//
|
||||
this.miNvHDR.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
@@ -366,7 +514,7 @@
|
||||
this.miToggleHDR,
|
||||
this.miHDREnabled});
|
||||
this.miNvHDR.Name = "miNvHDR";
|
||||
this.miNvHDR.Size = new System.Drawing.Size(147, 22);
|
||||
this.miNvHDR.Size = new System.Drawing.Size(162, 22);
|
||||
this.miNvHDR.Text = "HDR";
|
||||
//
|
||||
// miHDRIncluded
|
||||
@@ -418,11 +566,20 @@
|
||||
this.lvNvPresets.UseCompatibleStateImageBehavior = false;
|
||||
this.lvNvPresets.View = System.Windows.Forms.View.Details;
|
||||
this.lvNvPresets.SelectedIndexChanged += new System.EventHandler(this.lvNvPresets_SelectedIndexChanged);
|
||||
this.lvNvPresets.DoubleClick += new System.EventHandler(this.lvNvPresets_DoubleClick);
|
||||
this.lvNvPresets.DoubleClick += new System.EventHandler(this.btnApply_Click);
|
||||
//
|
||||
// tabAMD
|
||||
//
|
||||
this.tabAMD.Controls.Add(this.btnAddAmd);
|
||||
this.tabAMD.Controls.Add(this.lblErrorAMD);
|
||||
this.tabAMD.Controls.Add(this.btnDeleteAmd);
|
||||
this.tabAMD.Controls.Add(this.btnCloneAmd);
|
||||
this.tabAMD.Controls.Add(this.btnSetAmdShortcut);
|
||||
this.tabAMD.Controls.Add(this.lblAmdShortcut);
|
||||
this.tabAMD.Controls.Add(this.edtAmdShortcut);
|
||||
this.tabAMD.Controls.Add(this.btnChangeAmd);
|
||||
this.tabAMD.Controls.Add(this.btnApplyAmd);
|
||||
this.tabAMD.Controls.Add(this.lvAmdPresets);
|
||||
this.tabAMD.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabAMD.Name = "tabAMD";
|
||||
this.tabAMD.Padding = new System.Windows.Forms.Padding(3);
|
||||
@@ -431,18 +588,259 @@
|
||||
this.tabAMD.Text = "AMD controller";
|
||||
this.tabAMD.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnAddAmd
|
||||
//
|
||||
this.btnAddAmd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btnAddAmd.Location = new System.Drawing.Point(574, 417);
|
||||
this.btnAddAmd.Name = "btnAddAmd";
|
||||
this.btnAddAmd.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnAddAmd.TabIndex = 18;
|
||||
this.btnAddAmd.Text = "Add";
|
||||
this.btnAddAmd.UseVisualStyleBackColor = true;
|
||||
this.btnAddAmd.Click += new System.EventHandler(this.btnAddAmd_Click);
|
||||
//
|
||||
// lblErrorAMD
|
||||
//
|
||||
this.lblErrorAMD.AutoSize = true;
|
||||
this.lblErrorAMD.Location = new System.Drawing.Point(6, 3);
|
||||
this.lblErrorAMD.Location = new System.Drawing.Point(6, 6);
|
||||
this.lblErrorAMD.Name = "lblErrorAMD";
|
||||
this.lblErrorAMD.Size = new System.Drawing.Size(50, 13);
|
||||
this.lblErrorAMD.TabIndex = 8;
|
||||
this.lblErrorAMD.Text = "ErrorText";
|
||||
this.lblErrorAMD.Visible = false;
|
||||
//
|
||||
// btnDeleteAmd
|
||||
//
|
||||
this.btnDeleteAmd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btnDeleteAmd.Enabled = false;
|
||||
this.btnDeleteAmd.Location = new System.Drawing.Point(493, 417);
|
||||
this.btnDeleteAmd.Name = "btnDeleteAmd";
|
||||
this.btnDeleteAmd.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnDeleteAmd.TabIndex = 17;
|
||||
this.btnDeleteAmd.Text = "Delete";
|
||||
this.btnDeleteAmd.UseVisualStyleBackColor = true;
|
||||
this.btnDeleteAmd.Click += new System.EventHandler(this.btnDeleteAmd_Click);
|
||||
//
|
||||
// btnCloneAmd
|
||||
//
|
||||
this.btnCloneAmd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btnCloneAmd.Enabled = false;
|
||||
this.btnCloneAmd.Location = new System.Drawing.Point(412, 417);
|
||||
this.btnCloneAmd.Name = "btnCloneAmd";
|
||||
this.btnCloneAmd.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnCloneAmd.TabIndex = 16;
|
||||
this.btnCloneAmd.Text = "Clone";
|
||||
this.btnCloneAmd.UseVisualStyleBackColor = true;
|
||||
this.btnCloneAmd.Click += new System.EventHandler(this.btnCloneAmd_Click);
|
||||
//
|
||||
// btnSetAmdShortcut
|
||||
//
|
||||
this.btnSetAmdShortcut.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btnSetAmdShortcut.Enabled = false;
|
||||
this.btnSetAmdShortcut.Location = new System.Drawing.Point(372, 417);
|
||||
this.btnSetAmdShortcut.Name = "btnSetAmdShortcut";
|
||||
this.btnSetAmdShortcut.Size = new System.Drawing.Size(34, 23);
|
||||
this.btnSetAmdShortcut.TabIndex = 15;
|
||||
this.btnSetAmdShortcut.Text = "Set";
|
||||
this.btnSetAmdShortcut.UseVisualStyleBackColor = true;
|
||||
this.btnSetAmdShortcut.Click += new System.EventHandler(this.btnSetAmdShortcut_Click);
|
||||
//
|
||||
// lblAmdShortcut
|
||||
//
|
||||
this.lblAmdShortcut.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.lblAmdShortcut.AutoSize = true;
|
||||
this.lblAmdShortcut.Location = new System.Drawing.Point(168, 422);
|
||||
this.lblAmdShortcut.Name = "lblAmdShortcut";
|
||||
this.lblAmdShortcut.Size = new System.Drawing.Size(50, 13);
|
||||
this.lblAmdShortcut.TabIndex = 14;
|
||||
this.lblAmdShortcut.Text = "Shortcut:";
|
||||
//
|
||||
// edtAmdShortcut
|
||||
//
|
||||
this.edtAmdShortcut.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.edtAmdShortcut.Enabled = false;
|
||||
this.edtAmdShortcut.Location = new System.Drawing.Point(224, 419);
|
||||
this.edtAmdShortcut.Name = "edtAmdShortcut";
|
||||
this.edtAmdShortcut.ReadOnly = true;
|
||||
this.edtAmdShortcut.Size = new System.Drawing.Size(142, 20);
|
||||
this.edtAmdShortcut.TabIndex = 13;
|
||||
this.edtAmdShortcut.TextChanged += new System.EventHandler(this.edtAmdShortcut_TextChanged);
|
||||
this.edtAmdShortcut.KeyDown += new System.Windows.Forms.KeyEventHandler(this.edtShortcut_KeyDown);
|
||||
this.edtAmdShortcut.KeyUp += new System.Windows.Forms.KeyEventHandler(this.edtShortcut_KeyUp);
|
||||
//
|
||||
// btnChangeAmd
|
||||
//
|
||||
this.btnChangeAmd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btnChangeAmd.ContextMenuStrip = this.mnuAmdPresets;
|
||||
this.btnChangeAmd.Enabled = false;
|
||||
this.btnChangeAmd.Location = new System.Drawing.Point(87, 417);
|
||||
this.btnChangeAmd.Name = "btnChangeAmd";
|
||||
this.btnChangeAmd.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnChangeAmd.TabIndex = 12;
|
||||
this.btnChangeAmd.Text = "Change...";
|
||||
this.btnChangeAmd.UseVisualStyleBackColor = true;
|
||||
this.btnChangeAmd.Click += new System.EventHandler(this.btnChangeAmd_Click);
|
||||
//
|
||||
// mnuAmdPresets
|
||||
//
|
||||
this.mnuAmdPresets.ImageScalingSize = new System.Drawing.Size(20, 20);
|
||||
this.mnuAmdPresets.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.miAmdApply,
|
||||
this.miAmdPresetApplyOnStartup,
|
||||
this.toolStripSeparator2,
|
||||
this.mnuAmdDisplay,
|
||||
this.mnuAmdColorSettings,
|
||||
this.mnuAmdRefreshRate,
|
||||
this.mnuAmdDithering,
|
||||
this.mnuAmdHDR});
|
||||
this.mnuAmdPresets.Name = "mnuNvPresets";
|
||||
this.mnuAmdPresets.Size = new System.Drawing.Size(163, 164);
|
||||
this.mnuAmdPresets.Opening += new System.ComponentModel.CancelEventHandler(this.mnuAmdPresets_Opening);
|
||||
//
|
||||
// miAmdApply
|
||||
//
|
||||
this.miAmdApply.Name = "miAmdApply";
|
||||
this.miAmdApply.Size = new System.Drawing.Size(162, 22);
|
||||
this.miAmdApply.Text = "Apply";
|
||||
this.miAmdApply.Click += new System.EventHandler(this.btnApplyAmd_Click);
|
||||
//
|
||||
// miAmdPresetApplyOnStartup
|
||||
//
|
||||
this.miAmdPresetApplyOnStartup.CheckOnClick = true;
|
||||
this.miAmdPresetApplyOnStartup.Name = "miAmdPresetApplyOnStartup";
|
||||
this.miAmdPresetApplyOnStartup.Size = new System.Drawing.Size(162, 22);
|
||||
this.miAmdPresetApplyOnStartup.Text = "Apply on startup";
|
||||
this.miAmdPresetApplyOnStartup.Click += new System.EventHandler(this.miAmdPresetApplyOnStartup_Click);
|
||||
//
|
||||
// toolStripSeparator2
|
||||
//
|
||||
this.toolStripSeparator2.Name = "toolStripSeparator2";
|
||||
this.toolStripSeparator2.Size = new System.Drawing.Size(159, 6);
|
||||
//
|
||||
// mnuAmdDisplay
|
||||
//
|
||||
this.mnuAmdDisplay.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.miAmdPrimaryDisplay});
|
||||
this.mnuAmdDisplay.Name = "mnuAmdDisplay";
|
||||
this.mnuAmdDisplay.Size = new System.Drawing.Size(162, 22);
|
||||
this.mnuAmdDisplay.Text = "Display";
|
||||
//
|
||||
// miAmdPrimaryDisplay
|
||||
//
|
||||
this.miAmdPrimaryDisplay.Name = "miAmdPrimaryDisplay";
|
||||
this.miAmdPrimaryDisplay.Size = new System.Drawing.Size(155, 22);
|
||||
this.miAmdPrimaryDisplay.Text = "Primary display";
|
||||
this.miAmdPrimaryDisplay.Click += new System.EventHandler(this.displayMenuItemAmd_Click);
|
||||
//
|
||||
// mnuAmdColorSettings
|
||||
//
|
||||
this.mnuAmdColorSettings.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.miAmdColorSettingsIncluded});
|
||||
this.mnuAmdColorSettings.Name = "mnuAmdColorSettings";
|
||||
this.mnuAmdColorSettings.Size = new System.Drawing.Size(162, 22);
|
||||
this.mnuAmdColorSettings.Text = "Color settings";
|
||||
//
|
||||
// miAmdColorSettingsIncluded
|
||||
//
|
||||
this.miAmdColorSettingsIncluded.Name = "miAmdColorSettingsIncluded";
|
||||
this.miAmdColorSettingsIncluded.Size = new System.Drawing.Size(120, 22);
|
||||
this.miAmdColorSettingsIncluded.Text = "Included";
|
||||
this.miAmdColorSettingsIncluded.Click += new System.EventHandler(this.miAmdColorSettingsIncluded_Click);
|
||||
//
|
||||
// mnuAmdRefreshRate
|
||||
//
|
||||
this.mnuAmdRefreshRate.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.miAmdRefreshRateIncluded});
|
||||
this.mnuAmdRefreshRate.Name = "mnuAmdRefreshRate";
|
||||
this.mnuAmdRefreshRate.Size = new System.Drawing.Size(162, 22);
|
||||
this.mnuAmdRefreshRate.Text = "Refresh Rate";
|
||||
//
|
||||
// miAmdRefreshRateIncluded
|
||||
//
|
||||
this.miAmdRefreshRateIncluded.Name = "miAmdRefreshRateIncluded";
|
||||
this.miAmdRefreshRateIncluded.Size = new System.Drawing.Size(120, 22);
|
||||
this.miAmdRefreshRateIncluded.Text = "Included";
|
||||
this.miAmdRefreshRateIncluded.Click += new System.EventHandler(this.miAmdRefreshRateIncluded_Click);
|
||||
//
|
||||
// mnuAmdDithering
|
||||
//
|
||||
this.mnuAmdDithering.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.miAmdDitheringIncluded});
|
||||
this.mnuAmdDithering.Name = "mnuAmdDithering";
|
||||
this.mnuAmdDithering.Size = new System.Drawing.Size(162, 22);
|
||||
this.mnuAmdDithering.Text = "Dithering";
|
||||
//
|
||||
// miAmdDitheringIncluded
|
||||
//
|
||||
this.miAmdDitheringIncluded.Name = "miAmdDitheringIncluded";
|
||||
this.miAmdDitheringIncluded.Size = new System.Drawing.Size(120, 22);
|
||||
this.miAmdDitheringIncluded.Text = "Included";
|
||||
this.miAmdDitheringIncluded.Click += new System.EventHandler(this.miAmdDitheringIncluded_Click);
|
||||
//
|
||||
// mnuAmdHDR
|
||||
//
|
||||
this.mnuAmdHDR.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.miAmdHDRIncluded,
|
||||
this.miAmdHDRToggle,
|
||||
this.miAmdHDREnabled});
|
||||
this.mnuAmdHDR.Name = "mnuAmdHDR";
|
||||
this.mnuAmdHDR.Size = new System.Drawing.Size(162, 22);
|
||||
this.mnuAmdHDR.Text = "HDR";
|
||||
//
|
||||
// miAmdHDRIncluded
|
||||
//
|
||||
this.miAmdHDRIncluded.Name = "miAmdHDRIncluded";
|
||||
this.miAmdHDRIncluded.Size = new System.Drawing.Size(136, 22);
|
||||
this.miAmdHDRIncluded.Text = "Included";
|
||||
this.miAmdHDRIncluded.Click += new System.EventHandler(this.miAmdHDRIncluded_Click);
|
||||
//
|
||||
// miAmdHDRToggle
|
||||
//
|
||||
this.miAmdHDRToggle.Name = "miAmdHDRToggle";
|
||||
this.miAmdHDRToggle.Size = new System.Drawing.Size(136, 22);
|
||||
this.miAmdHDRToggle.Text = "Toggle HDR";
|
||||
this.miAmdHDRToggle.Click += new System.EventHandler(this.miAmdHDRToggle_Click);
|
||||
//
|
||||
// miAmdHDREnabled
|
||||
//
|
||||
this.miAmdHDREnabled.Name = "miAmdHDREnabled";
|
||||
this.miAmdHDREnabled.Size = new System.Drawing.Size(136, 22);
|
||||
this.miAmdHDREnabled.Text = "Enabled";
|
||||
this.miAmdHDREnabled.Click += new System.EventHandler(this.miAmdHDREnabled_Click);
|
||||
//
|
||||
// btnApplyAmd
|
||||
//
|
||||
this.btnApplyAmd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.btnApplyAmd.Enabled = false;
|
||||
this.btnApplyAmd.Location = new System.Drawing.Point(6, 417);
|
||||
this.btnApplyAmd.Name = "btnApplyAmd";
|
||||
this.btnApplyAmd.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnApplyAmd.TabIndex = 11;
|
||||
this.btnApplyAmd.Text = "Apply";
|
||||
this.btnApplyAmd.UseVisualStyleBackColor = true;
|
||||
this.btnApplyAmd.Click += new System.EventHandler(this.btnApplyAmd_Click);
|
||||
//
|
||||
// lvAmdPresets
|
||||
//
|
||||
this.lvAmdPresets.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.lvAmdPresets.ContextMenuStrip = this.mnuAmdPresets;
|
||||
this.lvAmdPresets.FullRowSelect = true;
|
||||
this.lvAmdPresets.HideSelection = false;
|
||||
this.lvAmdPresets.Location = new System.Drawing.Point(6, 6);
|
||||
this.lvAmdPresets.MultiSelect = false;
|
||||
this.lvAmdPresets.Name = "lvAmdPresets";
|
||||
this.lvAmdPresets.Size = new System.Drawing.Size(829, 405);
|
||||
this.lvAmdPresets.TabIndex = 10;
|
||||
this.lvAmdPresets.UseCompatibleStateImageBehavior = false;
|
||||
this.lvAmdPresets.View = System.Windows.Forms.View.Details;
|
||||
this.lvAmdPresets.SelectedIndexChanged += new System.EventHandler(this.lvAmdPresets_SelectedIndexChanged);
|
||||
this.lvAmdPresets.DoubleClick += new System.EventHandler(this.btnApplyAmd_Click);
|
||||
//
|
||||
// tabLG
|
||||
//
|
||||
this.tabLG.Controls.Add(this.btnLGRemoteControl);
|
||||
this.tabLG.Controls.Add(this.btnLgDeviceFilterRefresh);
|
||||
this.tabLG.Controls.Add(this.clbLgPower);
|
||||
this.tabLG.Controls.Add(this.btnLgAddButton);
|
||||
@@ -474,6 +872,26 @@
|
||||
this.tabLG.Text = "LG controller";
|
||||
this.tabLG.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnLGRemoteControl
|
||||
//
|
||||
this.btnLGRemoteControl.Location = new System.Drawing.Point(675, 5);
|
||||
this.btnLGRemoteControl.Name = "btnLGRemoteControl";
|
||||
this.btnLGRemoteControl.Size = new System.Drawing.Size(95, 23);
|
||||
this.btnLGRemoteControl.TabIndex = 36;
|
||||
this.btnLGRemoteControl.Text = "Remote Control";
|
||||
this.btnLGRemoteControl.UseVisualStyleBackColor = true;
|
||||
this.btnLGRemoteControl.Click += new System.EventHandler(this.btnLGRemoteControl_Click);
|
||||
//
|
||||
// btnLgDeviceFilterRefresh
|
||||
//
|
||||
this.btnLgDeviceFilterRefresh.Location = new System.Drawing.Point(594, 5);
|
||||
this.btnLgDeviceFilterRefresh.Name = "btnLgDeviceFilterRefresh";
|
||||
this.btnLgDeviceFilterRefresh.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnLgDeviceFilterRefresh.TabIndex = 35;
|
||||
this.btnLgDeviceFilterRefresh.Text = "Refresh";
|
||||
this.btnLgDeviceFilterRefresh.UseVisualStyleBackColor = true;
|
||||
this.btnLgDeviceFilterRefresh.Click += new System.EventHandler(this.btnLgDeviceFilterRefresh_Click);
|
||||
//
|
||||
// clbLgPower
|
||||
//
|
||||
this.clbLgPower.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
@@ -504,15 +922,30 @@
|
||||
this.btnLgAddButton.Name = "btnLgAddButton";
|
||||
this.btnLgAddButton.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnLgAddButton.TabIndex = 32;
|
||||
this.btnLgAddButton.Text = "Add button";
|
||||
this.btnLgAddButton.Text = "Add step";
|
||||
this.btnLgAddButton.UseVisualStyleBackColor = true;
|
||||
this.btnLgAddButton.Click += new System.EventHandler(this.btnLgAddButton_Click);
|
||||
//
|
||||
// mnuLgButtons
|
||||
//
|
||||
this.mnuLgButtons.ImageScalingSize = new System.Drawing.Size(20, 20);
|
||||
this.mnuLgButtons.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.mnuLgRcButtons,
|
||||
this.mnuLgActions});
|
||||
this.mnuLgButtons.Name = "mnuLgButtons";
|
||||
this.mnuLgButtons.Size = new System.Drawing.Size(61, 4);
|
||||
this.mnuLgButtons.Size = new System.Drawing.Size(116, 48);
|
||||
//
|
||||
// mnuLgRcButtons
|
||||
//
|
||||
this.mnuLgRcButtons.Name = "mnuLgRcButtons";
|
||||
this.mnuLgRcButtons.Size = new System.Drawing.Size(115, 22);
|
||||
this.mnuLgRcButtons.Text = "Buttons";
|
||||
//
|
||||
// mnuLgActions
|
||||
//
|
||||
this.mnuLgActions.Name = "mnuLgActions";
|
||||
this.mnuLgActions.Size = new System.Drawing.Size(115, 22);
|
||||
this.mnuLgActions.Text = "Actions";
|
||||
//
|
||||
// label3
|
||||
//
|
||||
@@ -698,8 +1131,9 @@
|
||||
this.edtShortcutLg.ReadOnly = true;
|
||||
this.edtShortcutLg.Size = new System.Drawing.Size(200, 20);
|
||||
this.edtShortcutLg.TabIndex = 11;
|
||||
this.edtShortcutLg.TextChanged += new System.EventHandler(this.edtShortcutLg_TextChanged);
|
||||
this.edtShortcutLg.KeyDown += new System.Windows.Forms.KeyEventHandler(this.edtShortcut_KeyDown);
|
||||
this.edtShortcutLg.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.edtShortcut_KeyPress);
|
||||
this.edtShortcutLg.KeyUp += new System.Windows.Forms.KeyEventHandler(this.edtShortcut_KeyUp);
|
||||
//
|
||||
// btnApplyLg
|
||||
//
|
||||
@@ -732,6 +1166,7 @@
|
||||
//
|
||||
// tabOptions
|
||||
//
|
||||
this.tabOptions.Controls.Add(this.grpNvidiaOptions);
|
||||
this.tabOptions.Controls.Add(this.grpMiscellaneousOptions);
|
||||
this.tabOptions.Controls.Add(this.grpLGOptions);
|
||||
this.tabOptions.Controls.Add(this.grpHDROptions);
|
||||
@@ -744,12 +1179,94 @@
|
||||
this.tabOptions.Text = "Options";
|
||||
this.tabOptions.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// grpNvidiaOptions
|
||||
//
|
||||
this.grpNvidiaOptions.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.grpNvidiaOptions.Controls.Add(this.lblDitheringMode);
|
||||
this.grpNvidiaOptions.Controls.Add(this.cbxDitheringMode);
|
||||
this.grpNvidiaOptions.Controls.Add(this.lblDitheringBitDepth);
|
||||
this.grpNvidiaOptions.Controls.Add(this.cbxDitheringBitDepth);
|
||||
this.grpNvidiaOptions.Controls.Add(this.chkDitheringEnabled);
|
||||
this.grpNvidiaOptions.Controls.Add(this.pbGradient);
|
||||
this.grpNvidiaOptions.Location = new System.Drawing.Point(412, 6);
|
||||
this.grpNvidiaOptions.Name = "grpNvidiaOptions";
|
||||
this.grpNvidiaOptions.Size = new System.Drawing.Size(400, 297);
|
||||
this.grpNvidiaOptions.TabIndex = 6;
|
||||
this.grpNvidiaOptions.TabStop = false;
|
||||
this.grpNvidiaOptions.Text = "NVIDIA options - test dithering";
|
||||
//
|
||||
// lblDitheringMode
|
||||
//
|
||||
this.lblDitheringMode.AutoSize = true;
|
||||
this.lblDitheringMode.Location = new System.Drawing.Point(6, 70);
|
||||
this.lblDitheringMode.Name = "lblDitheringMode";
|
||||
this.lblDitheringMode.Size = new System.Drawing.Size(37, 13);
|
||||
this.lblDitheringMode.TabIndex = 7;
|
||||
this.lblDitheringMode.Text = "Mode:";
|
||||
//
|
||||
// cbxDitheringMode
|
||||
//
|
||||
this.cbxDitheringMode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cbxDitheringMode.FormattingEnabled = true;
|
||||
this.cbxDitheringMode.Location = new System.Drawing.Point(64, 65);
|
||||
this.cbxDitheringMode.Name = "cbxDitheringMode";
|
||||
this.cbxDitheringMode.Size = new System.Drawing.Size(117, 21);
|
||||
this.cbxDitheringMode.TabIndex = 6;
|
||||
this.cbxDitheringMode.SelectedIndexChanged += new System.EventHandler(this.cbxDitheringMode_SelectedIndexChanged);
|
||||
//
|
||||
// lblDitheringBitDepth
|
||||
//
|
||||
this.lblDitheringBitDepth.AutoSize = true;
|
||||
this.lblDitheringBitDepth.Location = new System.Drawing.Point(6, 43);
|
||||
this.lblDitheringBitDepth.Name = "lblDitheringBitDepth";
|
||||
this.lblDitheringBitDepth.Size = new System.Drawing.Size(52, 13);
|
||||
this.lblDitheringBitDepth.TabIndex = 5;
|
||||
this.lblDitheringBitDepth.Text = "Bit-depth:";
|
||||
//
|
||||
// cbxDitheringBitDepth
|
||||
//
|
||||
this.cbxDitheringBitDepth.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cbxDitheringBitDepth.FormattingEnabled = true;
|
||||
this.cbxDitheringBitDepth.Location = new System.Drawing.Point(64, 38);
|
||||
this.cbxDitheringBitDepth.Name = "cbxDitheringBitDepth";
|
||||
this.cbxDitheringBitDepth.Size = new System.Drawing.Size(117, 21);
|
||||
this.cbxDitheringBitDepth.TabIndex = 4;
|
||||
this.cbxDitheringBitDepth.SelectedIndexChanged += new System.EventHandler(this.cbxDitheringBitDepth_SelectedIndexChanged);
|
||||
//
|
||||
// chkDitheringEnabled
|
||||
//
|
||||
this.chkDitheringEnabled.AutoSize = true;
|
||||
this.chkDitheringEnabled.Checked = true;
|
||||
this.chkDitheringEnabled.CheckState = System.Windows.Forms.CheckState.Checked;
|
||||
this.chkDitheringEnabled.Location = new System.Drawing.Point(6, 19);
|
||||
this.chkDitheringEnabled.Name = "chkDitheringEnabled";
|
||||
this.chkDitheringEnabled.Size = new System.Drawing.Size(109, 17);
|
||||
this.chkDitheringEnabled.TabIndex = 3;
|
||||
this.chkDitheringEnabled.Text = "Dithering enabled";
|
||||
this.chkDitheringEnabled.UseVisualStyleBackColor = true;
|
||||
this.chkDitheringEnabled.CheckedChanged += new System.EventHandler(this.chkDitheringEnabled_CheckedChanged);
|
||||
//
|
||||
// pbGradient
|
||||
//
|
||||
this.pbGradient.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.pbGradient.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.pbGradient.Location = new System.Drawing.Point(6, 92);
|
||||
this.pbGradient.Name = "pbGradient";
|
||||
this.pbGradient.Size = new System.Drawing.Size(388, 198);
|
||||
this.pbGradient.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
|
||||
this.pbGradient.TabIndex = 0;
|
||||
this.pbGradient.TabStop = false;
|
||||
//
|
||||
// grpMiscellaneousOptions
|
||||
//
|
||||
this.grpMiscellaneousOptions.Controls.Add(this.btnSetShortcutScreenSaver);
|
||||
this.grpMiscellaneousOptions.Controls.Add(this.label11);
|
||||
this.grpMiscellaneousOptions.Controls.Add(this.edtBlankScreenSaverShortcut);
|
||||
this.grpMiscellaneousOptions.Controls.Add(this.label10);
|
||||
this.grpMiscellaneousOptions.Controls.Add(this.lblFixChromeFontsDescription);
|
||||
this.grpMiscellaneousOptions.Controls.Add(this.chkFixChromeFonts);
|
||||
this.grpMiscellaneousOptions.Location = new System.Drawing.Point(6, 309);
|
||||
this.grpMiscellaneousOptions.Name = "grpMiscellaneousOptions";
|
||||
@@ -787,14 +1304,14 @@
|
||||
this.edtBlankScreenSaverShortcut.KeyDown += new System.Windows.Forms.KeyEventHandler(this.edtShortcut_KeyDown);
|
||||
this.edtBlankScreenSaverShortcut.KeyUp += new System.Windows.Forms.KeyEventHandler(this.edtShortcut_KeyUp);
|
||||
//
|
||||
// label10
|
||||
// lblFixChromeFontsDescription
|
||||
//
|
||||
this.label10.AutoSize = true;
|
||||
this.label10.Location = new System.Drawing.Point(3, 39);
|
||||
this.label10.Name = "label10";
|
||||
this.label10.Size = new System.Drawing.Size(373, 13);
|
||||
this.label10.TabIndex = 6;
|
||||
this.label10.Text = "This will add the parameter --disable-lcd-text to Chrome and requires elevation.";
|
||||
this.lblFixChromeFontsDescription.AutoSize = true;
|
||||
this.lblFixChromeFontsDescription.Location = new System.Drawing.Point(3, 39);
|
||||
this.lblFixChromeFontsDescription.Name = "lblFixChromeFontsDescription";
|
||||
this.lblFixChromeFontsDescription.Size = new System.Drawing.Size(373, 13);
|
||||
this.lblFixChromeFontsDescription.TabIndex = 6;
|
||||
this.lblFixChromeFontsDescription.Text = "This will add the parameter --disable-lcd-text to Chrome and requires elevation.";
|
||||
//
|
||||
// chkFixChromeFonts
|
||||
//
|
||||
@@ -809,10 +1326,11 @@
|
||||
//
|
||||
// grpLGOptions
|
||||
//
|
||||
this.grpLGOptions.Controls.Add(this.chkLgOldWolMechanism);
|
||||
this.grpLGOptions.Controls.Add(this.btnLGTestPower);
|
||||
this.grpLGOptions.Controls.Add(this.label9);
|
||||
this.grpLGOptions.Controls.Add(this.edtLgPowerOnAfterResumeDelay);
|
||||
this.grpLGOptions.Controls.Add(this.label8);
|
||||
this.grpLGOptions.Controls.Add(this.lblLgMaxPowerOnRetriesDescription);
|
||||
this.grpLGOptions.Controls.Add(this.edtLgMaxPowerOnRetries);
|
||||
this.grpLGOptions.Controls.Add(this.lblLgMaxPowerOnRetries);
|
||||
this.grpLGOptions.Location = new System.Drawing.Point(6, 196);
|
||||
this.grpLGOptions.Name = "grpLGOptions";
|
||||
this.grpLGOptions.Size = new System.Drawing.Size(403, 107);
|
||||
@@ -820,6 +1338,17 @@
|
||||
this.grpLGOptions.TabStop = false;
|
||||
this.grpLGOptions.Text = "LG controller";
|
||||
//
|
||||
// chkLgOldWolMechanism
|
||||
//
|
||||
this.chkLgOldWolMechanism.AutoSize = true;
|
||||
this.chkLgOldWolMechanism.Location = new System.Drawing.Point(158, 72);
|
||||
this.chkLgOldWolMechanism.Name = "chkLgOldWolMechanism";
|
||||
this.chkLgOldWolMechanism.Size = new System.Drawing.Size(187, 17);
|
||||
this.chkLgOldWolMechanism.TabIndex = 7;
|
||||
this.chkLgOldWolMechanism.Text = "Use old WOL mechanism (Npcap)";
|
||||
this.chkLgOldWolMechanism.UseVisualStyleBackColor = true;
|
||||
this.chkLgOldWolMechanism.CheckedChanged += new System.EventHandler(this.chkLgAlternateWolMechanism_CheckedChanged);
|
||||
//
|
||||
// btnLGTestPower
|
||||
//
|
||||
this.btnLGTestPower.Location = new System.Drawing.Point(9, 68);
|
||||
@@ -830,43 +1359,39 @@
|
||||
this.btnLGTestPower.UseVisualStyleBackColor = true;
|
||||
this.btnLGTestPower.Click += new System.EventHandler(this.btnLGTestPower_Click);
|
||||
//
|
||||
// label9
|
||||
// lblLgMaxPowerOnRetriesDescription
|
||||
//
|
||||
this.label9.AutoSize = true;
|
||||
this.label9.Location = new System.Drawing.Point(6, 40);
|
||||
this.label9.Name = "label9";
|
||||
this.label9.Size = new System.Drawing.Size(332, 13);
|
||||
this.label9.TabIndex = 5;
|
||||
this.label9.Text = "This delay is necessary to wait for the network link to be established. ";
|
||||
this.lblLgMaxPowerOnRetriesDescription.AutoSize = true;
|
||||
this.lblLgMaxPowerOnRetriesDescription.Location = new System.Drawing.Point(6, 40);
|
||||
this.lblLgMaxPowerOnRetriesDescription.Name = "lblLgMaxPowerOnRetriesDescription";
|
||||
this.lblLgMaxPowerOnRetriesDescription.Size = new System.Drawing.Size(375, 13);
|
||||
this.lblLgMaxPowerOnRetriesDescription.TabIndex = 5;
|
||||
this.lblLgMaxPowerOnRetriesDescription.Text = "Retries are necessary to wait for the network link of your pc to be established. " +
|
||||
"";
|
||||
//
|
||||
// edtLgPowerOnAfterResumeDelay
|
||||
// edtLgMaxPowerOnRetries
|
||||
//
|
||||
this.edtLgPowerOnAfterResumeDelay.Increment = new decimal(new int[] {
|
||||
100,
|
||||
this.edtLgMaxPowerOnRetries.Location = new System.Drawing.Point(299, 17);
|
||||
this.edtLgMaxPowerOnRetries.Maximum = new decimal(new int[] {
|
||||
25,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.edtLgPowerOnAfterResumeDelay.Location = new System.Drawing.Point(299, 17);
|
||||
this.edtLgPowerOnAfterResumeDelay.Maximum = new decimal(new int[] {
|
||||
5000,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.edtLgPowerOnAfterResumeDelay.Name = "edtLgPowerOnAfterResumeDelay";
|
||||
this.edtLgPowerOnAfterResumeDelay.ReadOnly = true;
|
||||
this.edtLgPowerOnAfterResumeDelay.Size = new System.Drawing.Size(74, 20);
|
||||
this.edtLgPowerOnAfterResumeDelay.TabIndex = 1;
|
||||
this.edtLgPowerOnAfterResumeDelay.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
|
||||
this.edtLgPowerOnAfterResumeDelay.ValueChanged += new System.EventHandler(this.edtLgPowerOnAfterResumeDelay_ValueChanged);
|
||||
this.edtLgMaxPowerOnRetries.Name = "edtLgMaxPowerOnRetries";
|
||||
this.edtLgMaxPowerOnRetries.ReadOnly = true;
|
||||
this.edtLgMaxPowerOnRetries.Size = new System.Drawing.Size(74, 20);
|
||||
this.edtLgMaxPowerOnRetries.TabIndex = 1;
|
||||
this.edtLgMaxPowerOnRetries.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
|
||||
this.edtLgMaxPowerOnRetries.ValueChanged += new System.EventHandler(this.edtLgPowerOnAfterResumeDelay_ValueChanged);
|
||||
//
|
||||
// label8
|
||||
// lblLgMaxPowerOnRetries
|
||||
//
|
||||
this.label8.AutoSize = true;
|
||||
this.label8.Location = new System.Drawing.Point(6, 19);
|
||||
this.label8.Name = "label8";
|
||||
this.label8.Size = new System.Drawing.Size(214, 13);
|
||||
this.label8.TabIndex = 0;
|
||||
this.label8.Text = "Delay before powering on after resume (ms):";
|
||||
this.lblLgMaxPowerOnRetries.AutoSize = true;
|
||||
this.lblLgMaxPowerOnRetries.Location = new System.Drawing.Point(6, 19);
|
||||
this.lblLgMaxPowerOnRetries.Name = "lblLgMaxPowerOnRetries";
|
||||
this.lblLgMaxPowerOnRetries.Size = new System.Drawing.Size(294, 13);
|
||||
this.lblLgMaxPowerOnRetries.TabIndex = 0;
|
||||
this.lblLgMaxPowerOnRetries.Text = "Maximum number of retries powering on after startup/resume:";
|
||||
//
|
||||
// grpHDROptions
|
||||
//
|
||||
@@ -1073,16 +1598,6 @@
|
||||
this.lblInfo.TabIndex = 1;
|
||||
this.lblInfo.Text = "Info";
|
||||
//
|
||||
// btnLgDeviceFilterRefresh
|
||||
//
|
||||
this.btnLgDeviceFilterRefresh.Location = new System.Drawing.Point(594, 5);
|
||||
this.btnLgDeviceFilterRefresh.Name = "btnLgDeviceFilterRefresh";
|
||||
this.btnLgDeviceFilterRefresh.Size = new System.Drawing.Size(75, 23);
|
||||
this.btnLgDeviceFilterRefresh.TabIndex = 35;
|
||||
this.btnLgDeviceFilterRefresh.Text = "Refresh";
|
||||
this.btnLgDeviceFilterRefresh.UseVisualStyleBackColor = true;
|
||||
this.btnLgDeviceFilterRefresh.Click += new System.EventHandler(this.btnLgDeviceFilterRefresh_Click);
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
@@ -1095,9 +1610,9 @@
|
||||
this.Name = "MainForm";
|
||||
this.Text = "ColorControl";
|
||||
this.Activated += new System.EventHandler(this.MainForm_Activated);
|
||||
this.Deactivate += new System.EventHandler(this.MainForm_Deactivate);
|
||||
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing);
|
||||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.MainForm_FormClosed);
|
||||
this.Load += new System.EventHandler(this.MainForm_Load);
|
||||
this.Shown += new System.EventHandler(this.MainForm_Shown);
|
||||
this.Resize += new System.EventHandler(this.MainForm_Resize);
|
||||
this.tcMain.ResumeLayout(false);
|
||||
@@ -1106,14 +1621,19 @@
|
||||
this.mnuNvPresets.ResumeLayout(false);
|
||||
this.tabAMD.ResumeLayout(false);
|
||||
this.tabAMD.PerformLayout();
|
||||
this.mnuAmdPresets.ResumeLayout(false);
|
||||
this.tabLG.ResumeLayout(false);
|
||||
this.tabLG.PerformLayout();
|
||||
this.mnuLgButtons.ResumeLayout(false);
|
||||
this.tabOptions.ResumeLayout(false);
|
||||
this.grpNvidiaOptions.ResumeLayout(false);
|
||||
this.grpNvidiaOptions.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.pbGradient)).EndInit();
|
||||
this.grpMiscellaneousOptions.ResumeLayout(false);
|
||||
this.grpMiscellaneousOptions.PerformLayout();
|
||||
this.grpLGOptions.ResumeLayout(false);
|
||||
this.grpLGOptions.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.edtLgPowerOnAfterResumeDelay)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.edtLgMaxPowerOnRetries)).EndInit();
|
||||
this.grpHDROptions.ResumeLayout(false);
|
||||
this.grpHDROptions.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.edtDelayDisplaySettings)).EndInit();
|
||||
@@ -1200,13 +1720,13 @@
|
||||
private System.Windows.Forms.ToolStripMenuItem miNvPresetColorSettings;
|
||||
private System.Windows.Forms.CheckedListBox clbLgPower;
|
||||
private System.Windows.Forms.GroupBox grpLGOptions;
|
||||
private System.Windows.Forms.NumericUpDown edtLgPowerOnAfterResumeDelay;
|
||||
private System.Windows.Forms.Label label8;
|
||||
private System.Windows.Forms.NumericUpDown edtLgMaxPowerOnRetries;
|
||||
private System.Windows.Forms.Label lblLgMaxPowerOnRetries;
|
||||
private System.Windows.Forms.Button btnLGTestPower;
|
||||
private System.Windows.Forms.Label label9;
|
||||
private System.Windows.Forms.Label lblLgMaxPowerOnRetriesDescription;
|
||||
private System.Windows.Forms.GroupBox grpMiscellaneousOptions;
|
||||
private System.Windows.Forms.CheckBox chkFixChromeFonts;
|
||||
private System.Windows.Forms.Label label10;
|
||||
private System.Windows.Forms.Label lblFixChromeFontsDescription;
|
||||
private System.Windows.Forms.Button btnSetShortcutScreenSaver;
|
||||
private System.Windows.Forms.Label label11;
|
||||
private System.Windows.Forms.TextBox edtBlankScreenSaverShortcut;
|
||||
@@ -1216,6 +1736,53 @@
|
||||
private System.Windows.Forms.Label lblErrorAMD;
|
||||
private System.Windows.Forms.Button btnClearLog;
|
||||
private System.Windows.Forms.Button btnLgDeviceFilterRefresh;
|
||||
private System.Windows.Forms.GroupBox grpNvidiaOptions;
|
||||
private System.Windows.Forms.PictureBox pbGradient;
|
||||
private System.Windows.Forms.Label lblDitheringMode;
|
||||
private System.Windows.Forms.ComboBox cbxDitheringMode;
|
||||
private System.Windows.Forms.Label lblDitheringBitDepth;
|
||||
private System.Windows.Forms.ComboBox cbxDitheringBitDepth;
|
||||
private System.Windows.Forms.CheckBox chkDitheringEnabled;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuNvDitheringBitDepth;
|
||||
private System.Windows.Forms.ToolStripMenuItem miNvDithering6bit;
|
||||
private System.Windows.Forms.ToolStripMenuItem miNvDithering8bit;
|
||||
private System.Windows.Forms.ToolStripMenuItem miNvDithering10bit;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuNvDitheringMode;
|
||||
private System.Windows.Forms.ToolStripMenuItem spatial1ToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem spatial2ToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem spatialDynamic2x2ToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem spatialStatic2x2ToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem temporalToolStripMenuItem;
|
||||
private System.Windows.Forms.Button btnLGRemoteControl;
|
||||
private System.Windows.Forms.ToolStripMenuItem miNvPresetApplyOnStartup;
|
||||
private System.Windows.Forms.CheckBox chkLgOldWolMechanism;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuLgRcButtons;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuLgActions;
|
||||
private System.Windows.Forms.Button btnDeleteAmd;
|
||||
private System.Windows.Forms.Button btnCloneAmd;
|
||||
private System.Windows.Forms.Button btnSetAmdShortcut;
|
||||
private System.Windows.Forms.Label lblAmdShortcut;
|
||||
private System.Windows.Forms.TextBox edtAmdShortcut;
|
||||
private System.Windows.Forms.Button btnChangeAmd;
|
||||
private System.Windows.Forms.ContextMenuStrip mnuAmdPresets;
|
||||
private System.Windows.Forms.ToolStripMenuItem miAmdApply;
|
||||
private System.Windows.Forms.ToolStripMenuItem miAmdPresetApplyOnStartup;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuAmdDisplay;
|
||||
private System.Windows.Forms.ToolStripMenuItem miAmdPrimaryDisplay;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuAmdColorSettings;
|
||||
private System.Windows.Forms.ToolStripMenuItem miAmdColorSettingsIncluded;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuAmdRefreshRate;
|
||||
private System.Windows.Forms.ToolStripMenuItem miAmdRefreshRateIncluded;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuAmdDithering;
|
||||
private System.Windows.Forms.ToolStripMenuItem miAmdDitheringIncluded;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuAmdHDR;
|
||||
private System.Windows.Forms.ToolStripMenuItem miAmdHDRIncluded;
|
||||
private System.Windows.Forms.ToolStripMenuItem miAmdHDRToggle;
|
||||
private System.Windows.Forms.ToolStripMenuItem miAmdHDREnabled;
|
||||
private System.Windows.Forms.Button btnApplyAmd;
|
||||
private System.Windows.Forms.ListView lvAmdPresets;
|
||||
private System.Windows.Forms.Button btnAddAmd;
|
||||
}
|
||||
}
|
||||
|
||||
+852
-543
File diff suppressed because it is too large.
Load diff
@@ -120,6 +120,9 @@
|
||||
<metadata name="mnuNvPresets.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="mnuAmdPresets.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>278, 17</value>
|
||||
</metadata>
|
||||
<metadata name="mnuLgButtons.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>147, 17</value>
|
||||
</metadata>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace ColorControl
|
||||
{
|
||||
class MessageForms
|
||||
{
|
||||
public static Form MainForm;
|
||||
|
||||
public static void WarningOk(string text)
|
||||
{
|
||||
MessageBox.Show(text, MainForm?.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
}
|
||||
|
||||
public static void ErrorOk(string text)
|
||||
{
|
||||
MessageBox.Show(text, MainForm?.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
|
||||
public static void InfoOk(string text)
|
||||
{
|
||||
MessageBox.Show(text, MainForm?.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
|
||||
public static DialogResult QuestionYesNo(string text)
|
||||
{
|
||||
return MessageBox.Show(text, MainForm?.Text, MessageBoxButtons.YesNo, MessageBoxIcon.Information);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using NvAPIWrapper.Display;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ColorControl
|
||||
{
|
||||
class NvDisplayInfo
|
||||
{
|
||||
public Display Display { get; }
|
||||
|
||||
public List<string> Values { get; }
|
||||
|
||||
public string InfoLine { get; }
|
||||
|
||||
public NvDisplayInfo(Display display, List<string> values, string infoLine)
|
||||
{
|
||||
Display = display;
|
||||
Values = values;
|
||||
InfoLine = infoLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ namespace ColorControl
|
||||
public uint refreshRate { get; set; }
|
||||
public bool primaryDisplay { get; set; }
|
||||
public string displayName { get; set; }
|
||||
public uint ditheringBits { get; set; }
|
||||
public uint ditheringMode { get; set; }
|
||||
|
||||
public NvPreset()
|
||||
{
|
||||
@@ -31,6 +33,8 @@ namespace ColorControl
|
||||
applyRefreshRate = false;
|
||||
refreshRate = 60;
|
||||
primaryDisplay = true;
|
||||
ditheringBits = 1;
|
||||
ditheringMode = 4;
|
||||
}
|
||||
|
||||
public NvPreset(ColorData colorData) : this()
|
||||
@@ -69,10 +73,10 @@ namespace ColorControl
|
||||
public static string[] GetColumnNames()
|
||||
{
|
||||
//return new[] { "BPC", "Format", "Dynamic range", "Toggle HDR", "Shortcut" };
|
||||
return new[] { "Display|140", "Color settings (BPC, format, dyn. range, color space)|260", "Refresh rate|100", "Dithering", "HDR", "Shortcut" };
|
||||
return new[] { "Display|140", "Color settings (BPC, format, dyn. range, color space)|260", "Refresh rate|100", "Dithering", "HDR", "Shortcut", "Apply on startup" };
|
||||
}
|
||||
|
||||
public List<string> GetDisplayValues()
|
||||
public override List<string> GetDisplayValues(Config config = null)
|
||||
{
|
||||
var values = new List<string>();
|
||||
|
||||
@@ -83,7 +87,10 @@ namespace ColorControl
|
||||
|
||||
values.Add(colorSettings);
|
||||
values.Add(string.Format("{0}: {1}Hz", applyRefreshRate ? "Included" : "Excluded", refreshRate));
|
||||
values.Add(string.Format("{0}: {1}", applyDithering ? "Included" : "Excluded", ditheringEnabled ? "Enabled" : "Disabled"));
|
||||
|
||||
var dithering = GetDitheringDescription();
|
||||
|
||||
values.Add(string.Format("{0}: {1}", applyDithering ? "Included" : "Excluded", dithering));
|
||||
values.Add(string.Format("{0}: {1}", applyHDR ? "Included" : "Excluded", toggleHDR ? "Toggle" : HDREnabled ? "Enabled" : "Disabled"));
|
||||
|
||||
//values.Add(colorData.ColorDepth.ToString());
|
||||
@@ -92,9 +99,23 @@ namespace ColorControl
|
||||
//values.Add(toggleHDR.ToString());
|
||||
values.Add(shortcut);
|
||||
|
||||
values.Add(string.Format("{0}", config?.NvPresetId_ApplyOnStartup == id ? "Yes" : string.Empty));
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
public string GetDitheringDescription(string disabledText = "Disabled")
|
||||
{
|
||||
var dithering = ditheringEnabled ? string.Empty : disabledText;
|
||||
if (ditheringEnabled)
|
||||
{
|
||||
var ditherBitsDescription = ((NvDitherBits)ditheringBits).GetDescription();
|
||||
var ditherModeDescription = ((NvDitherMode)ditheringMode).GetDescription();
|
||||
dithering = string.Format("{0} {1}", ditherBitsDescription, ditherModeDescription);
|
||||
}
|
||||
return dithering;
|
||||
}
|
||||
|
||||
public static List<NvPreset> GetDefaultPresets()
|
||||
{
|
||||
var presets = new List<NvPreset>();
|
||||
@@ -138,7 +159,8 @@ namespace ColorControl
|
||||
}
|
||||
if (applyDithering)
|
||||
{
|
||||
sb.AppendFormat("Dithering: {0}", ditheringEnabled ? "Yes" : "No");
|
||||
var dithering = GetDitheringDescription("No");
|
||||
sb.AppendFormat("Dithering: {0}", dithering);
|
||||
sb.Append(" / ");
|
||||
}
|
||||
if (applyHDR)
|
||||
|
||||
+273
-32
@@ -1,14 +1,43 @@
|
||||
using NvAPIWrapper;
|
||||
using NvAPIWrapper.Display;
|
||||
using NvAPIWrapper.Native.Display;
|
||||
using NvAPIWrapper.Native.Display.Structures;
|
||||
using NvAPIWrapper.Native.GPU.Structures;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using Windows.Graphics.Display;
|
||||
|
||||
namespace ColorControl
|
||||
{
|
||||
enum NvDitherBits
|
||||
{
|
||||
[Description("6-bit")]
|
||||
Bits6 = 0,
|
||||
[Description("8-bit")]
|
||||
Bits8 = 1,
|
||||
[Description("10-bit")]
|
||||
Bits10 = 2
|
||||
}
|
||||
|
||||
enum NvDitherMode
|
||||
{
|
||||
[Description("Spatial Dynamic")]
|
||||
SpatialDynamic = 0,
|
||||
[Description("Spatial Static")]
|
||||
SpatialStatic = 1,
|
||||
[Description("Spatial Dynamic 2x2")]
|
||||
SpatialDynamic2x2 = 2,
|
||||
[Description("Spatial Static 2x2")]
|
||||
SpatialStatic2x2 = 3,
|
||||
[Description("Temporal")]
|
||||
Temporal = 4
|
||||
}
|
||||
|
||||
class NvService : GraphicsService
|
||||
{
|
||||
[DllImport(@"nvapi64", EntryPoint = @"nvapi_QueryInterface", CallingConvention = CallingConvention.Cdecl,
|
||||
@@ -26,9 +55,9 @@ namespace ColorControl
|
||||
public delegate long NvAPI_Disp_GetDitherControl(
|
||||
[In] PhysicalGPUHandle physicalGpu,
|
||||
[In] uint OutputId,
|
||||
[In][Out] IntPtr ditherControl);
|
||||
[In] IntPtr ditherControl);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct NV_GPU_DITHER_CONTROL_V1
|
||||
{
|
||||
public int version;
|
||||
@@ -37,11 +66,17 @@ namespace ColorControl
|
||||
public uint mode;
|
||||
};
|
||||
|
||||
private Display _currentDisplay;
|
||||
private bool _initialized = false;
|
||||
private List<NvPreset> _presets;
|
||||
|
||||
public NvService()
|
||||
private Display _currentDisplay;
|
||||
private NvPreset _lastAppliedPreset;
|
||||
|
||||
public NvService(string dataPath) : base(dataPath)
|
||||
{
|
||||
var converter = new ColorDataConverter();
|
||||
_JsonDeserializer.RegisterConverters(new[] { converter });
|
||||
|
||||
LoadPresets();
|
||||
}
|
||||
|
||||
public Display GetCurrentDisplay()
|
||||
@@ -54,6 +89,57 @@ namespace ColorControl
|
||||
return _currentDisplay;
|
||||
}
|
||||
|
||||
public bool HasDisplaysAttached()
|
||||
{
|
||||
try
|
||||
{
|
||||
return DisplayDevice.GetGDIPrimaryDisplayDevice() != null;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void GlobalSave()
|
||||
{
|
||||
SavePresets();
|
||||
}
|
||||
|
||||
public List<NvPreset> GetPresets()
|
||||
{
|
||||
return _presets;
|
||||
}
|
||||
|
||||
private void LoadPresets()
|
||||
{
|
||||
_presetsFilename = Path.Combine(_dataPath, "NvPresets.json");
|
||||
|
||||
if (File.Exists(_presetsFilename))
|
||||
{
|
||||
var json = File.ReadAllText(_presetsFilename);
|
||||
|
||||
_presets = _JsonDeserializer.Deserialize<List<NvPreset>>(json);
|
||||
}
|
||||
else
|
||||
{
|
||||
_presets = NvPreset.GetDefaultPresets();
|
||||
}
|
||||
}
|
||||
|
||||
private void SavePresets()
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = _JsonSerializer.Serialize(_presets);
|
||||
File.WriteAllText(_presetsFilename, json);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e.ToLogString());
|
||||
}
|
||||
}
|
||||
|
||||
private void SetCurrentDisplay(NvPreset preset)
|
||||
{
|
||||
if (preset.primaryDisplay)
|
||||
@@ -67,52 +153,116 @@ namespace ColorControl
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool ApplyPreset(NvPreset preset, Config config)
|
||||
{
|
||||
var result = true;
|
||||
|
||||
if (!HasDisplaysAttached())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SetCurrentDisplay(preset);
|
||||
|
||||
if (preset.applyHDR)
|
||||
{
|
||||
if (preset.toggleHDR || preset.HDREnabled != IsHDREnabled())
|
||||
{
|
||||
ToggleHDR(config.DisplaySettingsDelay);
|
||||
}
|
||||
}
|
||||
var hdrEnabled = IsHDREnabled();
|
||||
|
||||
if (preset.applyRefreshRate)
|
||||
{
|
||||
SetRefreshRate(preset.refreshRate);
|
||||
}
|
||||
var newHdrEnabled = preset.applyHDR && (preset.HDREnabled || (preset.toggleHDR && !hdrEnabled));
|
||||
var applyHdr = preset.applyHDR && (preset.toggleHDR || preset.HDREnabled != hdrEnabled);
|
||||
|
||||
if (preset.applyColorData)
|
||||
if (preset.applyColorData && (ColorDataDiffers(preset.colorData) || (!newHdrEnabled && preset.applyColorData && preset.colorData.Colorimetry != ColorDataColorimetry.Auto)))
|
||||
{
|
||||
var display = GetCurrentDisplay();
|
||||
//var data = new ColorData(ColorDataFormat.YUV444, ColorDataColorimetry.Auto, ColorDataDynamicRange.Auto, ColorDataDepth.BPC10, preset.colorData.SelectionPolicy, ColorDataDesktopDepth.Default);
|
||||
if (hdrEnabled)
|
||||
{
|
||||
SetHDRState(display, false);
|
||||
|
||||
applyHdr = false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
display.DisplayDevice.SetColorData(preset.colorData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error($"SetColorData threw an exception: {ex.Message}");
|
||||
result = false;
|
||||
}
|
||||
|
||||
//var master = display.DisplayDevice.HDRColorData.MasteringDisplayData;
|
||||
//var newMaster = new MasteringDisplayColorData(master.FirstColorCoordinate, master.SecondColorCoordinate, master.ThirdColorCoordinate, new ColorDataColorCoordinate(0.25f, 0.25f), 50, 0, 50, 50);
|
||||
//var hdr = new HDRColorData(ColorDataHDRMode.UHDA, newMaster, ColorDataFormat.YUV444, ColorDataDynamicRange.Auto, ColorDataDepth.BPC8);
|
||||
//display.DisplayDevice.SetHDRColorData(hdr);
|
||||
if (hdrEnabled && newHdrEnabled)
|
||||
{
|
||||
SetHDRState(display, true);
|
||||
|
||||
applyHdr = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (applyHdr)
|
||||
{
|
||||
var display = GetCurrentDisplay();
|
||||
|
||||
var colorData = preset.applyColorData ? preset.colorData : display.DisplayDevice.CurrentColorData;
|
||||
|
||||
SetHDRState(display, newHdrEnabled, colorData);
|
||||
}
|
||||
|
||||
if (preset.applyRefreshRate)
|
||||
{
|
||||
if (!SetRefreshRate(preset.refreshRate))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (preset.applyDithering)
|
||||
{
|
||||
SetDithering(preset.ditheringEnabled);
|
||||
if (!SetDithering(preset.ditheringEnabled, preset: preset))
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
_lastAppliedPreset = preset;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void SetDithering(bool enabled)
|
||||
private bool ColorDataDiffers(ColorData colorData)
|
||||
{
|
||||
var display = GetCurrentDisplay();
|
||||
|
||||
var currentColorData = display.DisplayDevice.CurrentColorData;
|
||||
|
||||
var settingRange = colorData.DynamicRange == ColorDataDynamicRange.Auto ? colorData.ColorFormat == ColorDataFormat.RGB ? ColorDataDynamicRange.VESA : ColorDataDynamicRange.CEA : colorData.DynamicRange;
|
||||
|
||||
var settingSpace = colorData.Colorimetry;
|
||||
|
||||
return colorData.ColorFormat != currentColorData.ColorFormat || colorData.ColorDepth != currentColorData.ColorDepth || settingRange != currentColorData.DynamicRange || settingSpace != currentColorData.Colorimetry;
|
||||
}
|
||||
|
||||
private void SetHDRState(Display display, bool enabled, ColorData colorData = null)
|
||||
{
|
||||
var newMaster = new MasteringDisplayColorData();
|
||||
var hdr = new HDRColorData(enabled ? ColorDataHDRMode.UHDA : ColorDataHDRMode.Off, newMaster, colorData?.ColorFormat, colorData?.DynamicRange, colorData?.ColorDepth);
|
||||
|
||||
display.DisplayDevice.SetHDRColorData(hdr);
|
||||
|
||||
// HDR will not always be disabled this way, then we can only disable it through the display settings
|
||||
if (!enabled && IsHDREnabled())
|
||||
{
|
||||
ToggleHDR();
|
||||
}
|
||||
else if (enabled)
|
||||
{
|
||||
// Currectly there seems to be a bug that after enabling HDR via NVAPI, some settings are only applied upon opening the Display Settings...
|
||||
////OpenDisplaySettings();
|
||||
}
|
||||
}
|
||||
|
||||
public bool SetDithering(bool enabled, uint bits = 1, uint mode = 4, NvPreset preset = null)
|
||||
{
|
||||
var result = true;
|
||||
|
||||
var ptr = NvAPI64_QueryInterface(0xDF0DFCDD);
|
||||
if (ptr != IntPtr.Zero)
|
||||
{
|
||||
@@ -123,16 +273,34 @@ namespace ColorControl
|
||||
var gpuHandle = displayDevice.PhysicalGPU.Handle;
|
||||
var displayId = displayDevice.DisplayId;
|
||||
|
||||
var result = delegateValue(gpuHandle, displayId, (uint)(enabled ? 1 : 2), 1, 4);
|
||||
if (result != 0)
|
||||
if (preset != null)
|
||||
{
|
||||
Logger.Error($"Could not set dithering because NvAPI_Disp_SetDitherControl returned a non-zero return code: {result}");
|
||||
bits = preset.ditheringBits;
|
||||
mode = preset.ditheringMode;
|
||||
}
|
||||
|
||||
var resultValue = delegateValue(gpuHandle, displayId, (uint)(enabled ? 1 : 2), bits, mode);
|
||||
if (resultValue != 0)
|
||||
{
|
||||
Logger.Error($"Could not set dithering because NvAPI_Disp_SetDitherControl returned a non-zero return code: {resultValue}");
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error($"Could not set dithering because the function NvAPI_Disp_SetDitherControl could not be found");
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool GetDithering()
|
||||
{
|
||||
// Requires elevation, too bad :(
|
||||
//Utils.GetRegistryKeyValue(@"SYSTEM\CurrentControlSet\Services\nvlddmkm\State\DisplayDatabase", "DitherRegistryKey");
|
||||
|
||||
/*
|
||||
var ptr = NvAPI64_QueryInterface(0x932AC8FB);
|
||||
if (ptr != IntPtr.Zero)
|
||||
{
|
||||
@@ -145,7 +313,8 @@ namespace ColorControl
|
||||
|
||||
NV_GPU_DITHER_CONTROL_V1 info = new NV_GPU_DITHER_CONTROL_V1();
|
||||
info.version = 1;
|
||||
IntPtr bla = Marshal.AllocHGlobal(Marshal.SizeOf(info.GetType()));
|
||||
var size = Marshal.SizeOf(info.GetType());
|
||||
IntPtr bla = Marshal.AllocHGlobal(size);
|
||||
Marshal.StructureToPtr(info, bla, false);
|
||||
|
||||
// Does not work yet...What is the exact interface of NvAPI_Disp_GetDitherControl?
|
||||
@@ -158,16 +327,22 @@ namespace ColorControl
|
||||
|
||||
return info.state == 1;
|
||||
}
|
||||
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetRefreshRate(uint refreshRate)
|
||||
{
|
||||
var display = GetCurrentDisplay();
|
||||
var portrait = new[] { Rotate.Degree90, Rotate.Degree270 }.Contains(display.DisplayDevice.ScanOutInformation.SourceToTargetRotation);
|
||||
var timing = display.DisplayDevice.CurrentTiming;
|
||||
|
||||
if (timing.Extra.RefreshRate == refreshRate)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var portrait = new[] { Rotate.Degree90, Rotate.Degree270 }.Contains(display.DisplayDevice.ScanOutInformation.SourceToTargetRotation);
|
||||
|
||||
return SetRefreshRateInternal(display.Name, refreshRate, portrait, timing.HorizontalVisible, timing.VerticalVisible);
|
||||
}
|
||||
|
||||
@@ -197,6 +372,72 @@ namespace ColorControl
|
||||
return Display.GetDisplays();
|
||||
}
|
||||
|
||||
public List<NvDisplayInfo> GetDisplayInfos()
|
||||
{
|
||||
Display[] displays;
|
||||
try
|
||||
{
|
||||
displays = GetDisplays();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error("Error while getting displays: " + e.ToLogString());
|
||||
return null;
|
||||
}
|
||||
|
||||
var list = new List<NvDisplayInfo>();
|
||||
|
||||
foreach (var display in displays)
|
||||
{
|
||||
var values = new List<string>();
|
||||
|
||||
var name = display.Name;
|
||||
|
||||
var screen = Screen.AllScreens.FirstOrDefault(x => x.DeviceName.Equals(name));
|
||||
if (screen != null)
|
||||
{
|
||||
name += " (" + screen.DeviceFriendlyName() + ")";
|
||||
}
|
||||
|
||||
values.Add(name);
|
||||
|
||||
var colorData = display.DisplayDevice.CurrentColorData;
|
||||
var colorSettings = string.Format("{0}, {1}, {2}, {3}", colorData.ColorDepth, colorData.ColorFormat, colorData.DynamicRange, colorData.Colorimetry);
|
||||
|
||||
values.Add(colorSettings);
|
||||
|
||||
var refreshRate = display.DisplayDevice.CurrentTiming.Extra.RefreshRate;
|
||||
|
||||
values.Add($"{refreshRate}Hz");
|
||||
|
||||
var lastPreset = GetLastAppliedPreset();
|
||||
if (lastPreset != null)
|
||||
{
|
||||
values.Add(lastPreset.GetDitheringDescription());
|
||||
}
|
||||
else
|
||||
{
|
||||
values.Add(string.Empty);
|
||||
}
|
||||
|
||||
var hdrEnabled = IsHDREnabled();
|
||||
values.Add(hdrEnabled ? "Yes" : "No");
|
||||
|
||||
var infoLine = string.Format("{0}: {1}, {2}Hz, HDR: {3}", name, colorSettings, refreshRate, hdrEnabled ? "Yes" : "No");
|
||||
|
||||
var displayInfo = new NvDisplayInfo(display, values, infoLine);
|
||||
|
||||
list.Add(displayInfo);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public NvPreset GetLastAppliedPreset()
|
||||
{
|
||||
return _lastAppliedPreset;
|
||||
}
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
NVIDIA.Initialize();
|
||||
|
||||
@@ -45,5 +45,6 @@ namespace ColorControl
|
||||
return id;
|
||||
}
|
||||
|
||||
public abstract List<string> GetDisplayValues(Config config = null);
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Maassoft")]
|
||||
[assembly: AssemblyProduct("ColorControl")]
|
||||
[assembly: AssemblyCopyright("Copyright © Maassoft 2020")]
|
||||
[assembly: AssemblyCopyright("Copyright © Maassoft 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.3.6.0")]
|
||||
[assembly: AssemblyFileVersion("1.3.6.0")]
|
||||
[assembly: AssemblyVersion("2.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("2.0.0.0")]
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
|
||||
namespace ColorControl
|
||||
{
|
||||
partial class RemoteControlForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.flowPanel = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.btnClose = new System.Windows.Forms.Button();
|
||||
this.lblUC = new System.Windows.Forms.Label();
|
||||
this.chkDirectMode = new System.Windows.Forms.CheckBox();
|
||||
this.pnlMouse = new System.Windows.Forms.Panel();
|
||||
this.lblPos = new System.Windows.Forms.Label();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// flowPanel
|
||||
//
|
||||
this.flowPanel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.flowPanel.Location = new System.Drawing.Point(12, 16);
|
||||
this.flowPanel.Name = "flowPanel";
|
||||
this.flowPanel.Size = new System.Drawing.Size(787, 164);
|
||||
this.flowPanel.TabIndex = 0;
|
||||
this.flowPanel.MouseDown += new System.Windows.Forms.MouseEventHandler(this.RemoteControlForm_MouseDown);
|
||||
this.flowPanel.MouseMove += new System.Windows.Forms.MouseEventHandler(this.flowPanel_MouseMove);
|
||||
this.flowPanel.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.flowPanel_PreviewKeyDown);
|
||||
//
|
||||
// btnClose
|
||||
//
|
||||
this.btnClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnClose.FlatAppearance.BorderColor = System.Drawing.Color.DarkGray;
|
||||
this.btnClose.FlatAppearance.BorderSize = 0;
|
||||
this.btnClose.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
|
||||
this.btnClose.ForeColor = System.Drawing.Color.White;
|
||||
this.btnClose.Location = new System.Drawing.Point(796, 0);
|
||||
this.btnClose.Name = "btnClose";
|
||||
this.btnClose.Size = new System.Drawing.Size(14, 23);
|
||||
this.btnClose.TabIndex = 1;
|
||||
this.btnClose.Text = "x";
|
||||
this.btnClose.UseVisualStyleBackColor = true;
|
||||
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
|
||||
//
|
||||
// lblUC
|
||||
//
|
||||
this.lblUC.AutoSize = true;
|
||||
this.lblUC.ForeColor = System.Drawing.Color.Maroon;
|
||||
this.lblUC.Location = new System.Drawing.Point(130, 0);
|
||||
this.lblUC.Name = "lblUC";
|
||||
this.lblUC.Size = new System.Drawing.Size(100, 13);
|
||||
this.lblUC.TabIndex = 0;
|
||||
this.lblUC.Text = "Under construction!";
|
||||
//
|
||||
// chkDirectMode
|
||||
//
|
||||
this.chkDirectMode.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||
this.chkDirectMode.AutoSize = true;
|
||||
this.chkDirectMode.ForeColor = System.Drawing.Color.DarkGray;
|
||||
this.chkDirectMode.Location = new System.Drawing.Point(12, 643);
|
||||
this.chkDirectMode.Name = "chkDirectMode";
|
||||
this.chkDirectMode.Size = new System.Drawing.Size(105, 17);
|
||||
this.chkDirectMode.TabIndex = 2;
|
||||
this.chkDirectMode.Text = "Direct Mode (F1)";
|
||||
this.chkDirectMode.UseVisualStyleBackColor = true;
|
||||
this.chkDirectMode.CheckedChanged += new System.EventHandler(this.chkDirectMode_CheckedChanged);
|
||||
//
|
||||
// pnlMouse
|
||||
//
|
||||
this.pnlMouse.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.pnlMouse.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.pnlMouse.Location = new System.Drawing.Point(12, 191);
|
||||
this.pnlMouse.Name = "pnlMouse";
|
||||
this.pnlMouse.Size = new System.Drawing.Size(787, 446);
|
||||
this.pnlMouse.TabIndex = 3;
|
||||
this.pnlMouse.MouseEnter += new System.EventHandler(this.pnlMouse_MouseEnter);
|
||||
this.pnlMouse.MouseMove += new System.Windows.Forms.MouseEventHandler(this.pnlMouse_MouseMove);
|
||||
this.pnlMouse.MouseUp += new System.Windows.Forms.MouseEventHandler(this.pnlMouse_MouseUp);
|
||||
//
|
||||
// lblPos
|
||||
//
|
||||
this.lblPos.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.lblPos.AutoSize = true;
|
||||
this.lblPos.ForeColor = System.Drawing.Color.Maroon;
|
||||
this.lblPos.Location = new System.Drawing.Point(719, 643);
|
||||
this.lblPos.Name = "lblPos";
|
||||
this.lblPos.Size = new System.Drawing.Size(0, 13);
|
||||
this.lblPos.TabIndex = 1;
|
||||
//
|
||||
// RemoteControlForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.Color.Black;
|
||||
this.ClientSize = new System.Drawing.Size(811, 660);
|
||||
this.Controls.Add(this.lblPos);
|
||||
this.Controls.Add(this.pnlMouse);
|
||||
this.Controls.Add(this.chkDirectMode);
|
||||
this.Controls.Add(this.lblUC);
|
||||
this.Controls.Add(this.btnClose);
|
||||
this.Controls.Add(this.flowPanel);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
|
||||
this.KeyPreview = true;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "RemoteControlForm";
|
||||
this.Opacity = 0.8D;
|
||||
this.Text = "RemoteControlForm";
|
||||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.RemoteControlForm_FormClosed);
|
||||
this.Load += new System.EventHandler(this.RemoteControlForm_Load);
|
||||
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.RemoteControlForm_KeyDown);
|
||||
this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.RemoteControlForm_KeyUp);
|
||||
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.RemoteControlForm_MouseDown);
|
||||
this.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.RemoteControlForm_PreviewKeyDown);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.FlowLayoutPanel flowPanel;
|
||||
private System.Windows.Forms.Button btnClose;
|
||||
private System.Windows.Forms.Label lblUC;
|
||||
private System.Windows.Forms.CheckBox chkDirectMode;
|
||||
private System.Windows.Forms.Panel pnlMouse;
|
||||
private System.Windows.Forms.Label lblPos;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
using LgTv;
|
||||
using NWin32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace ColorControl
|
||||
{
|
||||
partial class RemoteControlForm : Form
|
||||
{
|
||||
private LgService _lgService;
|
||||
private List<LgPreset> _buttons;
|
||||
private LgWebOsMouseService _mouseService;
|
||||
private int _maxX, _maxY;
|
||||
private int _posX, _posY;
|
||||
|
||||
public RemoteControlForm(LgService lgService, List<LgPreset> buttons)
|
||||
{
|
||||
_lgService = lgService;
|
||||
_buttons = buttons;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
pnlMouse.MouseWheel += new MouseEventHandler(pnlMouse_MouseWheel);
|
||||
}
|
||||
|
||||
private void RemoteControlForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
foreach (var preset in _buttons)
|
||||
{
|
||||
var button = new Button();
|
||||
button.ForeColor = Color.White;
|
||||
button.FlatStyle = FlatStyle.Flat;
|
||||
button.FlatAppearance.BorderColor = Color.DarkGray;
|
||||
button.FlatAppearance.MouseOverBackColor = Color.DarkGray;
|
||||
button.Text = preset.name;
|
||||
button.Click += ButtonClick;
|
||||
button.Tag = preset;
|
||||
|
||||
button.Parent = flowPanel;
|
||||
}
|
||||
}
|
||||
|
||||
private void ButtonClick(object sender, EventArgs e)
|
||||
{
|
||||
if (e is MouseEventArgs)
|
||||
{
|
||||
var preset = (LgPreset)(sender as Button).Tag;
|
||||
|
||||
var _ = _lgService.ApplyPreset(preset);
|
||||
}
|
||||
}
|
||||
|
||||
private void btnClose_Click(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void RemoteControlForm_MouseDown(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
NativeMethods.ReleaseCapture();
|
||||
var intPtr = new UIntPtr(2);
|
||||
NativeMethods.SendMessageW(Handle, NativeConstants.WM_NCLBUTTONDOWN, intPtr, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoteControlForm_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
//var key = e.KeyCode;
|
||||
//HandleKey(key);
|
||||
}
|
||||
|
||||
private void flowPanel_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
|
||||
{
|
||||
//HandleKey(e.KeyCode);
|
||||
}
|
||||
|
||||
private void HandleKey(Keys key)
|
||||
{
|
||||
if (!chkDirectMode.Checked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var cvt = new KeysConverter();
|
||||
var shortcut = (string)cvt.ConvertTo(key, typeof(string));
|
||||
|
||||
var preset = _buttons.FirstOrDefault(p => p.shortcut != null && p.shortcut.Equals(shortcut));
|
||||
if (preset != null)
|
||||
{
|
||||
var _ = _lgService.ApplyPreset(preset);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoteControlForm_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
|
||||
{
|
||||
//HandleKey(e.KeyCode);
|
||||
}
|
||||
|
||||
private void RemoteControlForm_KeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.F1)
|
||||
{
|
||||
chkDirectMode.Checked = !chkDirectMode.Checked;
|
||||
return;
|
||||
}
|
||||
|
||||
HandleKey(e.KeyCode);
|
||||
}
|
||||
|
||||
private void chkDirectMode_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (chkDirectMode.Checked)
|
||||
{
|
||||
MessageForms.InfoOk(
|
||||
@"If you enable Direct Mode you will be able to control the TV directly via your keyboard and mouse.
|
||||
Note that your mouse will be captured in a box and that due to pointer accelaration the control will not be perfect.
|
||||
|
||||
Keyboard keys:
|
||||
- arrow keys: navigate the menu
|
||||
- backspace: go back
|
||||
- escape: exit
|
||||
- S: open picture settings
|
||||
- media keys: volume up/down/mute
|
||||
|
||||
Mouse:
|
||||
- left button: activate/open item
|
||||
- right button: go back
|
||||
- wheel: scroll through menus (only vertically)
|
||||
|
||||
Press F1 to stop Direct Mode."
|
||||
);
|
||||
|
||||
if (_mouseService == null)
|
||||
{
|
||||
_lgService.GetMouseAsync().ContinueWith((task) => BeginInvoke(new Action<Task<LgWebOsMouseService>>(SetMouseService), new[] { task }));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Cursor.Clip = Rectangle.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetMouseService(Task<LgWebOsMouseService> mouseServiceTask)
|
||||
{
|
||||
_mouseService = mouseServiceTask.Result;
|
||||
|
||||
_maxX = 1920;
|
||||
_maxY = 1080;
|
||||
_posX = _maxX / 2;
|
||||
_posY = _maxY / 2;
|
||||
}
|
||||
|
||||
private void flowPanel_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
private void pnlMouse_MouseEnter(object sender, EventArgs e)
|
||||
{
|
||||
if (chkDirectMode.Checked)
|
||||
{
|
||||
Cursor.Clip = RectangleToScreen(pnlMouse.Bounds);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoteControlForm_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
Cursor.Clip = Rectangle.Empty;
|
||||
}
|
||||
|
||||
private void pnlMouse_MouseUp(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (chkDirectMode.Checked && _mouseService != null)
|
||||
{
|
||||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
_mouseService.Click();
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleKey(Keys.Back);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleMouse(MouseEventArgs e)
|
||||
{
|
||||
if (chkDirectMode.Checked && _mouseService != null)
|
||||
{
|
||||
var scaleX = (double)e.X / pnlMouse.Width;
|
||||
var scaleY = (double)e.Y / pnlMouse.Height;
|
||||
|
||||
var relX = scaleX * _maxX;
|
||||
var relY = scaleY * _maxY;
|
||||
|
||||
var dx = (int)relX - _posX;
|
||||
var dy = (int)relY - _posY;
|
||||
|
||||
_posX = Math.Min(_posX + dx, _maxX);
|
||||
_posY = Math.Min(_posY + dy, _maxY);
|
||||
|
||||
lblPos.Text = $"Pos: {_posX}, {_posY}";
|
||||
|
||||
//var cx = flowPanel.Width / 2;
|
||||
//var cy = flowPanel.Height / 2;
|
||||
|
||||
//var dx = (e.X - cx) / 10;
|
||||
//var dy = (e.Y - cy) / 10;
|
||||
|
||||
_mouseService.Move(dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
private void pnlMouse_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
HandleMouse(e);
|
||||
}
|
||||
|
||||
private void pnlMouse_MouseWheel(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (chkDirectMode.Checked && _mouseService != null)
|
||||
{
|
||||
var dy = e.Delta * SystemInformation.MouseWheelScrollLines / 120;
|
||||
|
||||
if (dy != 0)
|
||||
{
|
||||
_mouseService.Scroll(0, dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -32,7 +32,7 @@ namespace ColorControl
|
||||
// Activate the subscription
|
||||
watcher.Enabled = true;
|
||||
}
|
||||
catch (EventLogReadingException e)
|
||||
catch (EventLogReadingException)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -81,7 +81,7 @@ namespace ColorControl
|
||||
// }
|
||||
//}
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Web.Script.Serialization;
|
||||
|
||||
namespace ColorControl
|
||||
{
|
||||
class ServiceBase
|
||||
{
|
||||
protected static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
protected string _dataPath;
|
||||
protected string _presetsFilename;
|
||||
protected JavaScriptSerializer _JsonSerializer;
|
||||
protected JavaScriptSerializer _JsonDeserializer;
|
||||
protected bool _initialized = false;
|
||||
|
||||
public ServiceBase(string dataPath)
|
||||
{
|
||||
_dataPath = dataPath;
|
||||
|
||||
_JsonSerializer = new JavaScriptSerializer();
|
||||
_JsonDeserializer = new JavaScriptSerializer();
|
||||
|
||||
Initialize();
|
||||
}
|
||||
|
||||
~ServiceBase()
|
||||
{
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
protected virtual void Initialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected virtual void Uninitialize()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+315
-13
@@ -1,11 +1,19 @@
|
||||
using Microsoft.Win32;
|
||||
using Microsoft.Win32.TaskScheduler;
|
||||
using NStandard;
|
||||
using NvAPIWrapper.Display;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Deployment.Application;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
@@ -14,7 +22,7 @@ using Windows.Devices.Enumeration.Pnp;
|
||||
|
||||
namespace ColorControl
|
||||
{
|
||||
class Utils
|
||||
static class Utils
|
||||
{
|
||||
[Flags]
|
||||
public enum ModKeys : int
|
||||
@@ -25,15 +33,20 @@ namespace ColorControl
|
||||
Win = 8
|
||||
}
|
||||
|
||||
public static string PKEY_PNPX_IpAddress = "{656a3bb3-ecc0-43fd-8477-4ae0404a96cd} 12297";
|
||||
public static string PKEY_PNPX_PhysicalAddress = "{656a3bb3-ecc0-43fd-8477-4ae0404a96cd} 12294";
|
||||
public static string PKEY_PNPX_IpAddress = "{656a3bb3-ecc0-43fd-8477-4ae0404a96cd} 12297";
|
||||
public static string PKEY_PNPX_PhysicalAddress = "{656a3bb3-ecc0-43fd-8477-4ae0404a96cd} 12294";
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
|
||||
[DllImport("user32.dll")]
|
||||
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
|
||||
|
||||
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
private static bool WinKeyDown = false;
|
||||
|
||||
public static Bitmap SubPixelShift(Bitmap bitmap)
|
||||
{
|
||||
Bitmap bitmap2 = (Bitmap) bitmap.Clone();
|
||||
Bitmap bitmap2 = (Bitmap)bitmap.Clone();
|
||||
|
||||
int shift = -1;
|
||||
bool shiftRed = true;
|
||||
@@ -188,6 +201,21 @@ namespace ColorControl
|
||||
return key != null;
|
||||
}
|
||||
|
||||
internal static void GetRegistryKeyValue(string keyname, string valueName, bool deepSearch = false)
|
||||
{
|
||||
var key = Registry.LocalMachine.OpenSubKey(keyname);
|
||||
|
||||
foreach (var subKeyName in key.GetSubKeyNames())
|
||||
{
|
||||
var subKey = key.OpenSubKey(subKeyName);
|
||||
if (subKey.GetValueNames().Contains(valueName))
|
||||
{
|
||||
Thread.Sleep(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal static bool UpdateShortcut(string path, string arguments, bool removeArguments = false)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
@@ -219,10 +247,10 @@ namespace ColorControl
|
||||
object objValue;
|
||||
string value = null;
|
||||
|
||||
foreach (var key in device.Properties.Keys)
|
||||
{
|
||||
Debug.WriteLine(key);
|
||||
}
|
||||
//foreach (var key in device.Properties.Keys)
|
||||
//{
|
||||
// Debug.WriteLine(key);
|
||||
//}
|
||||
|
||||
if (device.Properties.TryGetValue(propertyName, out objValue))
|
||||
{
|
||||
@@ -253,9 +281,11 @@ namespace ColorControl
|
||||
|
||||
var list = await DeviceInformation.FindAllAsync("", new List<string>());
|
||||
|
||||
var reqs = new List<string>();
|
||||
reqs.Add(PKEY_PNPX_IpAddress);
|
||||
reqs.Add(PKEY_PNPX_PhysicalAddress);
|
||||
var reqs = new List<string>
|
||||
{
|
||||
PKEY_PNPX_IpAddress,
|
||||
PKEY_PNPX_PhysicalAddress
|
||||
};
|
||||
|
||||
foreach (var dev in list)
|
||||
{
|
||||
@@ -284,7 +314,7 @@ namespace ColorControl
|
||||
return devices;
|
||||
}
|
||||
|
||||
public static void WaitForTask(Task task)
|
||||
public static void WaitForTask(System.Threading.Tasks.Task task)
|
||||
{
|
||||
while (task != null && (task.Status < TaskStatus.WaitingForChildrenToComplete))
|
||||
{
|
||||
@@ -302,5 +332,277 @@ namespace ColorControl
|
||||
if ((bool)t.GetField("added", hidden).GetValue(ni))
|
||||
t.GetMethod("UpdateIcon", hidden).Invoke(ni, new object[] { true });
|
||||
}
|
||||
|
||||
internal static Image GenerateGradientBitmap(int width, int height)
|
||||
{
|
||||
var bitmap = new Bitmap(512, height);
|
||||
|
||||
for (var i = 0; i < 256; i++)
|
||||
{
|
||||
var pixel = Color.FromArgb(i, i, i);
|
||||
|
||||
for (var h = 0; h < height; h++)
|
||||
{
|
||||
bitmap.SetPixel(i * 2, h, pixel);
|
||||
bitmap.SetPixel(i * 2 + 1, h, pixel);
|
||||
}
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static string GetDescription<T>(this T e) where T : IConvertible
|
||||
{
|
||||
if (e is Enum)
|
||||
{
|
||||
var type = e.GetType();
|
||||
var values = Enum.GetValues(type);
|
||||
|
||||
foreach (int val in values)
|
||||
{
|
||||
if (val == e.ToInt32(CultureInfo.InvariantCulture))
|
||||
{
|
||||
var memInfo = type.GetMember(type.GetEnumName(val));
|
||||
var descriptionAttribute = memInfo[0]
|
||||
.GetCustomAttributes(typeof(DescriptionAttribute), false)
|
||||
.FirstOrDefault() as DescriptionAttribute;
|
||||
|
||||
if (descriptionAttribute != null)
|
||||
{
|
||||
return descriptionAttribute.Description;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null; // could also return string.Empty
|
||||
}
|
||||
|
||||
public static List<string> GetDescriptions<T>() where T : IConvertible
|
||||
{
|
||||
var list = new List<string>();
|
||||
foreach (var enumValue in Enum.GetValues(typeof(T)))
|
||||
{
|
||||
list.Add(((T)enumValue).GetDescription());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static void RegisterTask(string taskName, bool enabled)
|
||||
{
|
||||
var file = Assembly.GetExecutingAssembly().Location;
|
||||
var directory = Path.GetDirectoryName(file);
|
||||
|
||||
try
|
||||
{
|
||||
using (TaskService ts = new TaskService())
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
TaskDefinition td = ts.NewTask();
|
||||
td.RegistrationInfo.Description = "Start ColorControl";
|
||||
|
||||
td.Triggers.Add(new LogonTrigger { UserId = WindowsIdentity.GetCurrent().Name });
|
||||
|
||||
td.Actions.Add(new ExecAction(file, StartUpParams.RunningFromScheduledTaskParam, directory));
|
||||
|
||||
ts.RootFolder.RegisterTaskDefinition(taskName, td);
|
||||
}
|
||||
else
|
||||
{
|
||||
ts.RootFolder.DeleteTask(taskName, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
MessageForms.ErrorOk("Could not create/delete task: " + e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TaskExists(string taskName, bool update)
|
||||
{
|
||||
var file = Assembly.GetExecutingAssembly().Location;
|
||||
using (TaskService ts = new TaskService())
|
||||
{
|
||||
var task = ts.RootFolder.Tasks.FirstOrDefault(x => x.Name.Equals(taskName));
|
||||
|
||||
if (task != null)
|
||||
{
|
||||
if (update && ApplicationDeployment.IsNetworkDeployed)
|
||||
{
|
||||
var action = task.Definition.Actions.FirstOrDefault(x => x.ActionType == TaskActionType.Execute);
|
||||
if (action != null)
|
||||
{
|
||||
var execAction = action as ExecAction;
|
||||
if (!execAction.Path.Equals(file))
|
||||
{
|
||||
RegisterTask(taskName, false);
|
||||
RegisterTask(taskName, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void RegisterShortcut(IntPtr handle, int id, string shortcut, bool clear = false)
|
||||
{
|
||||
if (clear)
|
||||
{
|
||||
UnregisterHotKey(handle, id);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(shortcut))
|
||||
{
|
||||
var (mods, key) = ParseShortcut(shortcut);
|
||||
RegisterHotKey(handle, id, mods, key);
|
||||
}
|
||||
}
|
||||
|
||||
public static void BuildDropDownMenu(ToolStripMenuItem mnuParent, string name, Type enumType, object colorData, string propertyName, EventHandler clickEvent)
|
||||
{
|
||||
PropertyInfo property;
|
||||
var subMenuItems = mnuParent.DropDownItems.Find("miColorSettings_" + name, false);
|
||||
ToolStripMenuItem subMenuItem;
|
||||
if (subMenuItems.Length == 0)
|
||||
{
|
||||
subMenuItem = (ToolStripMenuItem)mnuParent.DropDownItems.Add(name);
|
||||
subMenuItem.Name = "miColorSettings_" + name;
|
||||
|
||||
property = colorData.GetType().GetDeclaredProperty(propertyName);
|
||||
subMenuItem.Tag = property;
|
||||
|
||||
foreach (var enumValue in Enum.GetValues(enumType))
|
||||
{
|
||||
var item = subMenuItem.DropDownItems.Add(enumValue.ToString());
|
||||
item.Tag = enumValue;
|
||||
item.Click += clickEvent;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
subMenuItem = (ToolStripMenuItem)subMenuItems[0];
|
||||
property = (PropertyInfo)subMenuItem.Tag;
|
||||
}
|
||||
|
||||
var value = property.GetValue(colorData);
|
||||
|
||||
foreach (var item in subMenuItem.DropDownItems)
|
||||
{
|
||||
if (item is ToolStripMenuItem)
|
||||
{
|
||||
var menuItem = (ToolStripMenuItem)item;
|
||||
if (menuItem.Tag != null)
|
||||
{
|
||||
menuItem.Checked = menuItem.Tag.Equals(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string FormatKeyboardShortcut(KeyEventArgs keyEvent)
|
||||
{
|
||||
var pressedModifiers = keyEvent.Modifiers;
|
||||
|
||||
//Debug.WriteLine("KD: " + e.Modifiers + ", " + e.KeyCode);
|
||||
|
||||
var shortcutString = (pressedModifiers > 0 ? pressedModifiers.ToString() : "");
|
||||
if (keyEvent.KeyCode == Keys.LWin || WinKeyDown)
|
||||
{
|
||||
WinKeyDown = true;
|
||||
if (!string.IsNullOrEmpty(shortcutString))
|
||||
{
|
||||
shortcutString += ", ";
|
||||
}
|
||||
shortcutString += "Win";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(shortcutString) && keyEvent.KeyCode != Keys.ControlKey && keyEvent.KeyCode != Keys.ShiftKey && keyEvent.KeyCode != Keys.Menu && keyEvent.KeyCode != Keys.LWin)
|
||||
{
|
||||
shortcutString += " + " + keyEvent.KeyCode.ToString();
|
||||
}
|
||||
|
||||
if (pressedModifiers == 0 && !WinKeyDown)
|
||||
{
|
||||
keyEvent.SuppressKeyPress = true;
|
||||
}
|
||||
|
||||
return shortcutString;
|
||||
}
|
||||
|
||||
public static void HandleKeyboardShortcutUp(KeyEventArgs keyEvent)
|
||||
{
|
||||
if (keyEvent.KeyCode == Keys.LWin)
|
||||
{
|
||||
WinKeyDown = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void InitListView(ListView listView, IEnumerable<string> columns)
|
||||
{
|
||||
foreach (var name in columns)
|
||||
{
|
||||
var columnName = name;
|
||||
var parts = name.Split('|');
|
||||
|
||||
var width = 120;
|
||||
if (parts.Length > 1)
|
||||
{
|
||||
width = int.Parse(parts[1]);
|
||||
columnName = parts[0];
|
||||
}
|
||||
|
||||
var header = listView.Columns.Add(columnName);
|
||||
header.Width = width == 120 ? -2 : width;
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddOrUpdateListItem<T>(ListView listView, List<T> presets, Config config, T preset = null, ListViewItem specItem = null) where T : PresetBase
|
||||
{
|
||||
ListViewItem item = null;
|
||||
if (preset == null)
|
||||
{
|
||||
item = listView.SelectedItems[0];
|
||||
preset = (T)item.Tag;
|
||||
}
|
||||
else
|
||||
{
|
||||
item = specItem;
|
||||
}
|
||||
|
||||
if (preset.id == 0)
|
||||
{
|
||||
preset.id = preset.GetHashCode();
|
||||
}
|
||||
|
||||
var values = preset.GetDisplayValues(config);
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
item = listView.Items.Add(values[0]);
|
||||
item.Tag = preset;
|
||||
for (var i = 1; i < values.Count; i++)
|
||||
{
|
||||
item.SubItems.Add(values[i]);
|
||||
}
|
||||
if (!presets.Any(x => x.id == preset.id))
|
||||
{
|
||||
presets.Add(preset);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Text = values[0];
|
||||
for (var i = 1; i < values.Count; i++)
|
||||
{
|
||||
item.SubItems[i].Text = values[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
+120
-7
@@ -1,22 +1,126 @@
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using PacketDotNet;
|
||||
using System.Net.NetworkInformation;
|
||||
using SharpPcap;
|
||||
using System.Diagnostics;
|
||||
using SharpPcap.Npcap;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace ColorControl
|
||||
{
|
||||
class WOL
|
||||
{
|
||||
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
private const string ArgumentExceptionInvalidMacAddressLength = "Invalid MAC address length.";
|
||||
private const string ArgumentExceptionInvalidPasswordLength = "Invalid password length.";
|
||||
private const int DefaultWolPort = 9;
|
||||
|
||||
public static bool WakeFunction(string macAddress, bool usePcap = false)
|
||||
{
|
||||
if (usePcap)
|
||||
{
|
||||
return WakeFunctionPcap(macAddress);
|
||||
}
|
||||
|
||||
return WakeFunctionToAllNics(macAddress);
|
||||
}
|
||||
|
||||
public static bool WakeFunctionToAllNics(string macAddress)
|
||||
{
|
||||
var result = false;
|
||||
|
||||
try
|
||||
{
|
||||
var address = PhysicalAddress.Parse(macAddress);
|
||||
var addressBytes = address.GetAddressBytes();
|
||||
var data = GetWolPacket(addressBytes);
|
||||
|
||||
var interfaces = NetworkInterface.GetAllNetworkInterfaces();
|
||||
|
||||
foreach (var ni in interfaces)
|
||||
{
|
||||
if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback || ni.Name.Contains("VirtualBox"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Logger.Debug($"Found network: {ni.Name} ({ni.Description}), type: {ni.NetworkInterfaceType}");
|
||||
try
|
||||
{
|
||||
if (/*ni.OperationalStatus == OperationalStatus.Up &&*/ ni.SupportsMulticast && ni.GetIPProperties().GetIPv4Properties() != null)
|
||||
{
|
||||
foreach (var uip in ni.GetIPProperties().UnicastAddresses)
|
||||
{
|
||||
if (uip.Address.ToString().StartsWith("169.254"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (uip.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||
{
|
||||
Logger.Debug($"Broadcast WOL in network: {ni.Name} ({ni.Description}), local address: {uip.Address}");
|
||||
var local = new IPEndPoint(uip.Address, 0);
|
||||
var udpc = new UdpClient(local);
|
||||
udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
|
||||
udpc.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);
|
||||
var target = new IPEndPoint(IPAddress.Broadcast, DefaultWolPort);
|
||||
udpc.Send(data, data.Length, target);
|
||||
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error($"WakeFunctionToAllNics: while sending to specific network: {ni.Name} ({ni.Description}): {ex.ToLogString()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error($"WakeFunctionToAllNics: {ex.ToLogString()}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="password"/> is not 0 or 6.</exception>
|
||||
private static byte[] GetWolPacket(byte[] macAddress, byte[] password = null)
|
||||
{
|
||||
if (macAddress == null)
|
||||
throw new ArgumentNullException(nameof(macAddress));
|
||||
if (macAddress.Length != 6)
|
||||
throw new ArgumentException(ArgumentExceptionInvalidMacAddressLength);
|
||||
|
||||
password = password ?? new byte[0];
|
||||
if (password.Length != 0 && password.Length != 6)
|
||||
throw new ArgumentException(ArgumentExceptionInvalidPasswordLength);
|
||||
|
||||
var packet = new byte[17 * 6 + password.Length];
|
||||
|
||||
int offset, i;
|
||||
for (offset = 0; offset < 6; ++offset)
|
||||
packet[offset] = 0xFF;
|
||||
|
||||
for (offset = 6; offset < 17 * 6; offset += 6)
|
||||
for (i = 0; i < 6; ++i)
|
||||
packet[i + offset] = macAddress[i];
|
||||
|
||||
if (password.Length > 0)
|
||||
{
|
||||
for (offset = 16 * 6 + 6; offset < (17 * 6 + password.Length); offset += 6)
|
||||
for (i = 0; i < 6; ++i)
|
||||
packet[i + offset] = password[i];
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
|
||||
//You need SharpPcap for this to work
|
||||
|
||||
public static void WakeFunction(string macAddress)
|
||||
private static bool WakeFunctionPcap(string macAddress)
|
||||
{
|
||||
/* Retrieve the device list */
|
||||
var devices = CaptureDeviceList.Instance;
|
||||
@@ -27,7 +131,7 @@ namespace ColorControl
|
||||
if (devices.Count < 1)
|
||||
{
|
||||
Logger.Debug("No network device found on this machine");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var device in devices)
|
||||
@@ -40,7 +144,14 @@ namespace ColorControl
|
||||
// }
|
||||
//}
|
||||
|
||||
Logger.Debug("Opening network device: " + device.Name);
|
||||
if (device is NpcapDevice npcapDevice)
|
||||
{
|
||||
Logger.Debug($"Opening network device (NpcapDevice): FriendlyName: {npcapDevice.Interface.FriendlyName}, Description: {npcapDevice.Interface.Description}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Debug($"Opening network device (NOT A NpcapDevice!): {device.Name}, Description: {device.Description}");
|
||||
}
|
||||
|
||||
//Open the device
|
||||
device.Open();
|
||||
@@ -68,6 +179,8 @@ namespace ColorControl
|
||||
|
||||
device.Close();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -297,6 +297,15 @@ namespace LgTv
|
||||
return _appList.OrderBy(e => e.Title);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<string>> GetServiceList()
|
||||
{
|
||||
var list = new List<string>();
|
||||
var requestMessage = new RequestMessage("channels", "ssap://api/getServiceList");
|
||||
var command = _connection.SendCommandAsync(requestMessage);
|
||||
var res = await command;
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<LgApp>> GetApps(bool force = false)
|
||||
{
|
||||
var appList = new List<LgApp>();
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace LgTv
|
||||
_messageWriter.WriteString(message);
|
||||
await _messageWriter.StoreAsync();
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Exception)
|
||||
{
|
||||
ConnectionClosed = true;
|
||||
_messageWriter?.Dispose();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using NStandard;
|
||||
using System;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LgTv
|
||||
@@ -28,7 +27,13 @@ namespace LgTv
|
||||
_8,
|
||||
_9,
|
||||
_0,
|
||||
POWER
|
||||
POWER,
|
||||
VOLUMEUP,
|
||||
VOLUMEDOWN,
|
||||
MUTE,
|
||||
MENU,
|
||||
CC,
|
||||
DASH
|
||||
}
|
||||
|
||||
public class LgWebOsMouseService : IDisposable
|
||||
|
||||
@@ -9,6 +9,12 @@ And if you own a recent LG TV, you can control your TV through the app (no NVIDI
|
||||
|
||||

|
||||
|
||||
For this to work correctly:
|
||||
Check if the TV is listed in Windows Device Manager (Win+X -> Device Manager) under Digital Media Devices. If not then add the TV using Settings (Win+I) -> "Devices" -> "Add Bluetooth or other device" -> "Everything Else", then select your TV by name. It should now appear in Device Manager. (If your TV is not shown when adding devices then your PC is unable to see the TV on the network, check your network settings on both the PC & TV)
|
||||
NOTE: You may have to add the TV as a device more than once before it appears in Device Manager, as Windows can detect the TV as multiple devices.
|
||||
|
||||
If you receive WinPcap errors download and install Npcap (https://nmap.org/npcap/#download) in WinPcap compatibility mode. WinPcap is depreciated under windows 10.
|
||||
|
||||
On the Options-tabpage you can finetune some parameters and/or enable some settings:
|
||||
|
||||

|
||||
@@ -0,0 +1,39 @@
|
||||
using System.ComponentModel;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Net
|
||||
{
|
||||
/// <summary>Stellt Methoden für das Senden von Anfragen über das ARP-Protokoll bereit.</summary>
|
||||
public static class ArpRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// Sendet eine Anfrage über das ARP-Protokoll, um eine IP-Adresse in die Physikalische Adresse aufzulösen. Falls sich die physikalische Adresse bereits im Cache des Hosts befindet, wird diese zurückgegeben.
|
||||
/// </summary>
|
||||
/// <param name="destination">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <returns>Eine <see cref="T:System.Net.ArpRequestResult">ArpRequestResult</see>-Instanz, welche die Ergebnisse der Anfrage enthält.</returns>
|
||||
public static ArpRequestResult Send(IPAddress destination)
|
||||
{
|
||||
if (destination == null)
|
||||
throw new ArgumentNullException(nameof(destination));
|
||||
|
||||
int destIp = BitConverter.ToInt32(destination.GetAddressBytes(), 0);
|
||||
|
||||
var addr = new byte[6];
|
||||
var len = addr.Length;
|
||||
|
||||
var res = NativeMethods.SendARP(destIp, 0, addr, ref len);
|
||||
|
||||
if (res == 0)
|
||||
return new ArpRequestResult(new PhysicalAddress(addr));
|
||||
return new ArpRequestResult(new Win32Exception(res));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sendet eine Anfrage über das ARP-Protokoll, um eine IP-Adresse in die Physikalische Adresse aufzulösen. Falls sich die physikalische Adresse bereits im Cache des Hosts befindet, wird diese zurückgegeben.
|
||||
/// </summary>
|
||||
/// <param name="destination">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <returns>Ein asynchroner Task, welcher einen ARP-Request sendet.</returns>
|
||||
public static Task<ArpRequestResult> SendAsync(IPAddress destination) => Task.Run(() => Send(destination));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Net
|
||||
{
|
||||
// TODO: rethink the whole exception thing
|
||||
|
||||
/// <summary>
|
||||
/// Enthält die Rückgabewerte der ArpRequest.Send-Funktion.
|
||||
/// </summary>
|
||||
public class ArpRequestResult
|
||||
{
|
||||
/// <summary>Falls Fehler bei der Protokollanfrage auftreten, werden diese in dieser Eigenschaft abgelegt. Andernfalls null.</summary>
|
||||
public Exception Exception { get; }
|
||||
|
||||
/// <summary>Die aufgelöste physikalische Adresse.</summary>
|
||||
public PhysicalAddress Address { get; }
|
||||
|
||||
/// <summary>Erstellt eine neue ArpRequestResult-Instanz</summary>
|
||||
/// <param name="address">Die physikalische Adresse</param>
|
||||
public ArpRequestResult(PhysicalAddress address)
|
||||
{
|
||||
this.Exception = null;
|
||||
Address = address;
|
||||
}
|
||||
|
||||
/// <summary>Erstellt eine neue ArpRequestResult-Instanz</summary>
|
||||
/// <param name="exception">Der aufgetretene Fehler</param>
|
||||
public ArpRequestResult(Exception exception)
|
||||
{
|
||||
this.Exception = exception;
|
||||
Address = null;
|
||||
}
|
||||
|
||||
/// <summary>Konvertiert ARP-Rückgabewerte in eine Zeichenfolge.</summary>
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
if (Address == null)
|
||||
sb.Append("no address");
|
||||
else
|
||||
{
|
||||
sb.Append("address: ");
|
||||
sb.Append(Address);
|
||||
}
|
||||
sb.Append(", ");
|
||||
if (Exception == null)
|
||||
sb.Append("no exception");
|
||||
else
|
||||
{
|
||||
sb.Append("exception: ");
|
||||
sb.Append(Exception.Message);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
//
|
||||
// To add a suppression to this file, right-click the message in the
|
||||
// Code Analysis results, point to "Suppress Message", and click
|
||||
// "In Suppression File".
|
||||
// You do not need to add suppressions to this file manually.
|
||||
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Int32)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Byte[],System.Int32)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Byte[],System.Int32,System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Byte[])")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Byte[],System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Net.NetworkInformation.PhysicalAddress)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWol(System.Net.IPAddress,System.Net.NetworkInformation.PhysicalAddress,System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Int32)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Byte[],System.Int32)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Byte[],System.Int32,System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Byte[])")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Byte[],System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Net.NetworkInformation.PhysicalAddress)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPAddressExtensions.#SendWolAsync(System.Net.IPAddress,System.Net.NetworkInformation.PhysicalAddress,System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWol(System.Net.IPEndPoint,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWol(System.Net.IPEndPoint,System.Byte[])")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWol(System.Net.IPEndPoint,System.Net.NetworkInformation.PhysicalAddress)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWol(System.Net.IPEndPoint,System.Byte[],System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWol(System.Net.IPEndPoint,System.Net.NetworkInformation.PhysicalAddress,System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWolAsync(System.Net.IPEndPoint,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte,System.Byte)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWolAsync(System.Net.IPEndPoint,System.Byte[])")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWolAsync(System.Net.IPEndPoint,System.Net.NetworkInformation.PhysicalAddress)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWolAsync(System.Net.IPEndPoint,System.Byte[],System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.IPEndPointExtensions.#SendWolAsync(System.Net.IPEndPoint,System.Net.NetworkInformation.PhysicalAddress,System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Lan")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Scope = "member", Target = "System.Net.Topology.INetMask.#GetMaskBytes()")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "n", Scope = "member", Target = "System.Net.Topology.NetMask.#op_Equality(System.Net.Topology.NetMask,System.Net.Topology.NetMask)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "n", Scope = "member", Target = "System.Net.Topology.NetMask.#op_Inequality(System.Net.Topology.NetMask,System.Net.Topology.NetMask)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "n", Scope = "member", Target = "System.Net.Topology.NetMask.#op_BitwiseAnd(System.Net.Topology.NetMask,System.Net.Topology.NetMask)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Scope = "type", Target = "System.Net.Topology.SiblingOptions")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "type", Target = "System.Net.SendWol")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWolAsync(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPEndPoint)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWolAsync(System.Net.NetworkInformation.PhysicalAddress,System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWolAsync(System.Net.NetworkInformation.PhysicalAddress)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWol(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPEndPoint,System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWol(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPEndPoint)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWol(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPAddress,System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWol(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPAddress)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWol(System.Net.NetworkInformation.PhysicalAddress,System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWol(System.Net.NetworkInformation.PhysicalAddress)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "n", Scope = "member", Target = "System.Net.Topology.NetMask.#op_BitwiseOr(System.Net.Topology.NetMask,System.Net.Topology.NetMask)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "n", Scope = "member", Target = "System.Net.Topology.NetMask.#BitwiseOr(System.Net.Topology.NetMask,System.Net.Topology.NetMask)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWolAsync(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPAddress)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWolAsync(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPAddress,System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Wol", Scope = "member", Target = "System.Net.PhysicalAddressExtensions.#SendWolAsync(System.Net.NetworkInformation.PhysicalAddress,System.Net.IPEndPoint,System.Net.SecureOnPassword)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Cidr", Scope = "member", Target = "System.Net.Topology.INetMask.#Cidr")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "m", Scope = "member", Target = "System.Net.Topology.NetMask.#.ctor(System.Byte,System.Byte,System.Byte,System.Byte)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "n", Scope = "member", Target = "System.Net.Topology.NetMask.#BitwiseAnd(System.Net.Topology.NetMask,System.Net.Topology.NetMask)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "cidr", Scope = "member", Target = "System.Net.Topology.NetMask.#.ctor(System.Int32)")]
|
||||
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "cidr", Scope = "member", Target = "System.Net.Topology.NetMask.#.ctor(System.Byte)")]
|
||||
@@ -0,0 +1,166 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace System.Net
|
||||
{
|
||||
/// <summary>Provides extension methods for sending Wake On LAN signals (magic packets) to a specific <see cref="IPAddress"/>.</summary>
|
||||
public static class IPAddressExtensions
|
||||
{
|
||||
private const int DefaultWolPort = 7;
|
||||
#region Wol
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <param name="port">The port to send the packet to.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="SocketException">An error occurred when accessing the socket. See Remarks section of <see cref="UdpClient.Send(byte[], int, IPEndPoint)"/> for more information.</exception>
|
||||
public static void SendWol(this IPAddress target, byte[] macAddress, int port) => target.SendWol(macAddress, port, null);
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <param name="port">The port to send the packet to.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="SocketException">An error occurred when accessing the socket. See Remarks section of <see cref="UdpClient.Send(byte[], int, IPEndPoint)"/> for more information.</exception>
|
||||
public static void SendWol(this IPAddress target, byte[] macAddress, int port, SecureOnPassword password)
|
||||
{
|
||||
Net.MagicPacket.Send(new IPEndPoint(target, port), macAddress, password);
|
||||
}
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="SocketException">An error occurred when accessing the socket. See Remarks section of <see cref="UdpClient.Send(byte[], int, IPEndPoint)"/> for more information.</exception>
|
||||
public static void SendWol(this IPAddress target, byte[] macAddress) => target.SendWol(macAddress, null);
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="SocketException">An error occurred when accessing the socket. See Remarks section of <see cref="UdpClient.Send(byte[], int, IPEndPoint)"/> for more information.</exception>
|
||||
public static void SendWol(this IPAddress target, byte[] macAddress, SecureOnPassword password)
|
||||
{
|
||||
Net.MagicPacket.Send(new IPEndPoint(target, DefaultWolPort), macAddress, password);
|
||||
}
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="PhysicalAddress" /> <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="SocketException">An error occurred when accessing the socket. See Remarks section of <see cref="UdpClient.Send(byte[], int, IPEndPoint)"/> for more information.</exception>
|
||||
public static void SendWol(this IPAddress target, PhysicalAddress macAddress) => target.SendWol(macAddress, null);
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="PhysicalAddress" /> <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="SocketException">An error occurred when accessing the socket. See Remarks section of <see cref="UdpClient.Send(byte[], int, IPEndPoint)"/> for more information.</exception>
|
||||
public static void SendWol(this IPAddress target, PhysicalAddress macAddress, SecureOnPassword password)
|
||||
{
|
||||
Net.MagicPacket.Send(new IPEndPoint(target, DefaultWolPort), macAddress, password);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region ARP
|
||||
|
||||
/// <summary>
|
||||
/// Sendet eine Anfrage über das ARP-Protokoll, um eine IP-Adresse in die Physikalische Adresse aufzulösen. Falls sich die physikalische Adresse bereits im Cache des Hosts befindet, wird diese zurückgegeben.
|
||||
/// </summary>
|
||||
/// <param name="destination">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <returns>Eine <see cref="T:System.Net.ArpRequestResult">ArpRequestResult</see>-Instanz, welche die Ergebnisse der Anfrage enthält.</returns>
|
||||
public static ArpRequestResult SendArpRequest(this IPAddress destination) => ArpRequest.Send(destination);
|
||||
|
||||
#endregion
|
||||
#region TAP
|
||||
|
||||
#region Wol
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <param name="port">The port to send the packet to.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendWolAsync(this IPAddress target, byte[] macAddress, int port) => target.SendWolAsync(macAddress, port, null);
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <param name="port">The port to send the packet to.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendWolAsync(this IPAddress target, byte[] macAddress, int port, SecureOnPassword password)
|
||||
{
|
||||
return Net.MagicPacket.SendAsync(new IPEndPoint(target, port), macAddress, password);
|
||||
}
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendWolAsync(this IPAddress target, byte[] macAddress) => target.SendWolAsync(macAddress, null);
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="password"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendWolAsync(this IPAddress target, byte[] macAddress, SecureOnPassword password)
|
||||
{
|
||||
return Net.MagicPacket.SendAsync(new IPEndPoint(target, DefaultWolPort), macAddress, password);
|
||||
}
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="PhysicalAddress" /> <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendWolAsync(this IPAddress target, PhysicalAddress macAddress) => target.SendWolAsync(macAddress, null);
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="PhysicalAddress" /> <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="password"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendWolAsync(this IPAddress target, PhysicalAddress macAddress, SecureOnPassword password)
|
||||
{
|
||||
return Net.MagicPacket.SendAsync(new IPEndPoint(target, DefaultWolPort), macAddress, password);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ARP
|
||||
|
||||
/// <summary>Sends a request via ARP to resolve an IP address to aphysical address. If the physical address is already cached, it's cached value is returned.</summary>
|
||||
/// <param name="destination">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends an ARP request.</returns>
|
||||
public static Task<ArpRequestResult> SendArpRequestAsync(this IPAddress destination) => ArpRequest.SendAsync(destination);
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace System.Net
|
||||
{
|
||||
/// <summary>Provides extension methods for sending Wake On LAN signals (magic packets) to a specific <see cref="IPEndPoint"/>.</summary>
|
||||
public static class IPEndPointExtensions
|
||||
{
|
||||
#region Wol
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array macAddress is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
public static void SendWol(this IPEndPoint target, byte[] macAddress)
|
||||
{
|
||||
Net.MagicPacket.Send(target, macAddress);
|
||||
}
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
public static void SendWol(this IPEndPoint target, PhysicalAddress macAddress)
|
||||
{
|
||||
Net.MagicPacket.Send(target, macAddress);
|
||||
}
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array macAddress is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
public static void SendWol(this IPEndPoint target, byte[] macAddress, SecureOnPassword password)
|
||||
{
|
||||
Net.MagicPacket.Send(target, macAddress, password);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sendet ein Wake-On-LAN-Signal an einen Client.
|
||||
/// </summary>
|
||||
/// <param name="target">Der Ziel-IPEndPoint.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
public static void SendWol(this IPEndPoint target, PhysicalAddress macAddress, SecureOnPassword password)
|
||||
{
|
||||
Net.MagicPacket.Send(target, macAddress, password);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region TAP
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array macAddress is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendWolAsync(this IPEndPoint target, byte[] macAddress)
|
||||
{
|
||||
return Net.MagicPacket.SendAsync(target, macAddress);
|
||||
}
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendWolAsync(this IPEndPoint target, PhysicalAddress macAddress)
|
||||
{
|
||||
return Net.MagicPacket.SendAsync(target, macAddress);
|
||||
}
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array macAddress is not 6.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendWolAsync(this IPEndPoint target, byte[] macAddress, SecureOnPassword password)
|
||||
{
|
||||
return Net.MagicPacket.SendAsync(target, macAddress, password);
|
||||
}
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the client.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendWolAsync(this IPEndPoint target, PhysicalAddress macAddress, SecureOnPassword password)
|
||||
{
|
||||
return Net.MagicPacket.SendAsync(target, macAddress, password);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#define GERMAN
|
||||
|
||||
namespace System.Net
|
||||
{
|
||||
internal static class Localization
|
||||
{
|
||||
public const string ArgumentExceptionInvalidMacAddressLength = "Invalid MAC address length.";
|
||||
public const string ArgumentExceptionInvalidPasswordLength = "Invalid password length.";
|
||||
|
||||
public const string ArgumentExceptionIsNotAValidMadAddress = " is not a valid MAC address.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace System.Net
|
||||
{
|
||||
/// <summary>Provides methods for sending Wake On LAN signals (magic packets).</summary>
|
||||
public static class MagicPacket
|
||||
{
|
||||
#region Wol
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the designated client.</param>
|
||||
/// <exception cref="ArgumentNullException">target is null.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array macAddress is not 6.</exception>
|
||||
/// <exception cref="SocketException">An error occurred when accessing the socket. See Remarks section of <see cref="UdpClient.Send(byte[], int, IPEndPoint)"/> for more information.</exception>
|
||||
public static void Send(IPEndPoint target, byte[] macAddress) => Send(target, macAddress, null);
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the designated client.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="target"/> is null.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="SocketException">An error occurred when accessing the socket. See Remarks section of <see cref="UdpClient.Send(byte[], int, IPEndPoint)"/> for more information.</exception>
|
||||
public static void Send(IPEndPoint target, byte[] macAddress, SecureOnPassword password)
|
||||
{
|
||||
if (macAddress == null)
|
||||
throw new ArgumentNullException(nameof(macAddress));
|
||||
|
||||
byte[] passwordBuffer = password?.GetPasswordBytes();
|
||||
byte[] packet = GetWolPacket(macAddress, passwordBuffer);
|
||||
SendPacket(target, packet);
|
||||
}
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the designated client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="SocketException">An error occurred when accessing the socket. See Remarks section of <see cref="UdpClient.Send(byte[], int, IPEndPoint)"/> for more information.</exception>
|
||||
public static void Send(IPEndPoint target, PhysicalAddress macAddress) => Send(target, macAddress, null);
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the designated client.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="SocketException">An error occurred when accessing the socket. See Remarks section of <see cref="UdpClient.Send(byte[], int, IPEndPoint)"/> for more information.</exception>
|
||||
public static void Send(IPEndPoint target, PhysicalAddress macAddress, SecureOnPassword password)
|
||||
{
|
||||
if (macAddress == null)
|
||||
throw new ArgumentNullException(nameof(macAddress));
|
||||
|
||||
byte[] passwordBuffer = password?.GetPasswordBytes();
|
||||
byte[] packet = GetWolPacket(macAddress.GetAddressBytes(), passwordBuffer);
|
||||
SendPacket(target, packet);
|
||||
}
|
||||
|
||||
private static void SendPacket(IPEndPoint target, byte[] packet)
|
||||
{
|
||||
using (var cl = new UdpClient())
|
||||
cl.Send(packet, packet.Length, target);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region TAP
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the designated client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="target"/> is null.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendAsync(IPEndPoint target, byte[] macAddress) => SendAsync(target, macAddress);
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the designated client.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="target"/> is null.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="password"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendAsync(IPEndPoint target, byte[] macAddress, SecureOnPassword password)
|
||||
{
|
||||
if (target == null)
|
||||
throw new ArgumentNullException(nameof(target));
|
||||
if (macAddress == null)
|
||||
throw new ArgumentNullException(nameof(macAddress));
|
||||
|
||||
var passwordBuffer = password?.GetPasswordBytes();
|
||||
var packet = GetWolPacket(macAddress, passwordBuffer);
|
||||
return SendPacketAsync(target, packet);
|
||||
}
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the designated client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="target"/> is null.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendAsync(IPEndPoint target, PhysicalAddress macAddress) => SendAsync(target, macAddress, null);
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a client.</summary>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="macAddress">The MAC address of the designated client.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="target"/> is null.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendAsync(IPEndPoint target, PhysicalAddress macAddress, SecureOnPassword password)
|
||||
{
|
||||
if (target == null)
|
||||
throw new ArgumentNullException(nameof(target));
|
||||
if (macAddress == null)
|
||||
throw new ArgumentNullException(nameof(macAddress));
|
||||
|
||||
var passwordBuffer = password?.GetPasswordBytes();
|
||||
var p = GetWolPacket(macAddress.GetAddressBytes(), passwordBuffer);
|
||||
return SendPacketAsync(target, p);
|
||||
}
|
||||
|
||||
private static Task SendPacketAsync(IPEndPoint target, byte[] packet)
|
||||
{
|
||||
var cl = new UdpClient();
|
||||
return cl.SendAsync(packet, packet.Length, target).ContinueWith((Task t) => cl.Close());
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region internal
|
||||
|
||||
/// <exception cref="ArgumentNullException"><paramref name="macAddress"/> is null.</exception>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="macAddress"/> is not 6.</exception>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array <paramref name="password"/> is not 0 or 6.</exception>
|
||||
private static byte[] GetWolPacket(byte[] macAddress, byte[] password)
|
||||
{
|
||||
if (macAddress == null)
|
||||
throw new ArgumentNullException(nameof(macAddress));
|
||||
if (macAddress.Length != 6)
|
||||
throw new ArgumentException(Localization.ArgumentExceptionInvalidMacAddressLength);
|
||||
|
||||
password = password ?? new byte[0];
|
||||
if (password.Length != 0 && password.Length != 6)
|
||||
throw new ArgumentException(Localization.ArgumentExceptionInvalidPasswordLength);
|
||||
|
||||
var packet = new byte[17 * 6 + password.Length];
|
||||
|
||||
int offset, i;
|
||||
for (offset = 0; offset < 6; ++offset)
|
||||
packet[offset] = 0xFF;
|
||||
|
||||
for (offset = 6; offset < 17 * 6; offset += 6)
|
||||
for (i = 0; i < 6; ++i)
|
||||
packet[i + offset] = macAddress[i];
|
||||
|
||||
if (password.Length > 0)
|
||||
{
|
||||
for (offset = 16 * 6 + 6; offset < (17 * 6 + password.Length); offset += 6)
|
||||
for (i = 0; i < 6; ++i)
|
||||
packet[i + offset] = password[i];
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace System.Net
|
||||
{
|
||||
internal static class NativeMethods
|
||||
{
|
||||
private const string IphlpApi = "iphlpapi.dll";
|
||||
|
||||
[DllImport(IphlpApi, ExactSpelling = true)]
|
||||
[SecurityCritical]
|
||||
internal static extern int SendARP(int destinationIp, int sourceIp, byte[] macAddress, ref int physicalAddrLength);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace System.Net
|
||||
{
|
||||
/// <summary>Provides extension methods for sending Wake On LAN signals (magic packets) using a specific <see cref="PhysicalAddress"/>.</summary>
|
||||
public static class PhysicalAddressExtensions
|
||||
{
|
||||
#region Wol
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to the broadcast IP address with the physical address.</summary>
|
||||
/// <param name="address">The instance of the physical address that should be used in the magic packet.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="address"/> is null.</exception>
|
||||
public static void SendWol(this PhysicalAddress address) => address.SendWol(IPAddress.Broadcast, null);
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a specific IP address with the physical address.</summary>
|
||||
/// <param name="address">The instance of the physical address that should be used in the magic packet.</param>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="address"/> is null.</exception>
|
||||
public static void SendWol(this PhysicalAddress address, IPAddress target) => address.SendWol(target, null);
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a specific IP address with the physical address.</summary>
|
||||
/// <param name="address">The instance of the physical address that should be used in the magic packet.</param>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="address"/> is null.</exception>
|
||||
public static void SendWol(this PhysicalAddress address, IPAddress target, SecureOnPassword password)
|
||||
{
|
||||
if (address == null)
|
||||
throw new ArgumentNullException(nameof(address));
|
||||
|
||||
target.SendWol(address.GetAddressBytes(), password);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a specific IP end point with the physical address.</summary>
|
||||
/// <param name="address">The instance of the physical address that should be used in the magic packet.</param>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="address"/> is null.</exception>
|
||||
public static void SendWol(this PhysicalAddress address, IPEndPoint target) => address.SendWol(target, null);
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a specific IP end point with the physical address.</summary>
|
||||
/// <param name="address">The instance of the physical address that should be used in the magic packet.</param>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="address"/> is null.</exception>
|
||||
public static void SendWol(this PhysicalAddress address, IPEndPoint target, SecureOnPassword password)
|
||||
{
|
||||
if (address == null)
|
||||
throw new ArgumentNullException(nameof(address));
|
||||
|
||||
target.SendWol(address.GetAddressBytes(), password);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region TAP
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to the broadcast IP address with the physical address.</summary>
|
||||
/// <param name="address">The instance of the physical address that should be used in the magic packet.</param>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="address"/> is null.</exception>
|
||||
public static Task SendWolAsync(this PhysicalAddress address)
|
||||
{
|
||||
if (address == null)
|
||||
throw new ArgumentNullException(nameof(address));
|
||||
|
||||
return IPAddress.Broadcast.SendWolAsync(address.GetAddressBytes());
|
||||
}
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a specific IP address with the physical address.</summary>
|
||||
/// <param name="address">The instance of the physical address that should be used in the magic packet.</param>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="address"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendWolAsync(this PhysicalAddress address, IPAddress target) => address.SendWolAsync(target, null);
|
||||
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a specific IP address with the physical address.</summary>
|
||||
/// <param name="address">The instance of the physical address that should be used in the magic packet.</param>
|
||||
/// <param name="target">Destination <see cref="IPAddress"/>.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="address"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendWolAsync(this PhysicalAddress address, IPAddress target, SecureOnPassword password)
|
||||
{
|
||||
if (address == null)
|
||||
throw new ArgumentNullException(nameof(address));
|
||||
|
||||
return target.SendWolAsync(address.GetAddressBytes(), password);
|
||||
}
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a specific IP end point with the physical address.</summary>
|
||||
/// <param name="address">The instance of the physical address that should be used in the magic packet.</param>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="address"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendWolAsync(this PhysicalAddress address, IPEndPoint target) => address.SendWolAsync(target, null);
|
||||
|
||||
/// <summary>Sends a Wake On LAN signal (magic packet) to a specific IP end point with the physical address.</summary>
|
||||
/// <param name="address">The instance of the physical address that should be used in the magic packet.</param>
|
||||
/// <param name="target">Destination <see cref="IPEndPoint"/>.</param>
|
||||
/// <param name="password">The SecureOn password of the client.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="address"/> is null.</exception>
|
||||
/// <returns>An asynchronous <see cref="Task"/> which sends a Wake On LAN signal (magic packet) to a client.</returns>
|
||||
public static Task SendWolAsync(this PhysicalAddress address, IPEndPoint target, SecureOnPassword password)
|
||||
{
|
||||
if (address == null)
|
||||
throw new ArgumentNullException(nameof(address));
|
||||
|
||||
return target.SendWolAsync(address.GetAddressBytes(), password);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region common
|
||||
|
||||
/// <summary>Gets the type (<see cref="PhysicalAddressAdministrator"/>) of the <see cref="PhysicalAddress" />.</summary>
|
||||
/// <param name="address">The address.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="address"/> is null.</exception>
|
||||
/// <returns>The <see cref="PhysicalAddressType" /> of the physical addess (MAC address).</returns>
|
||||
public static PhysicalAddressType GetAddressType(this PhysicalAddress address)
|
||||
{
|
||||
if (address == null)
|
||||
throw new ArgumentNullException(nameof(address));
|
||||
|
||||
var bytes = address.GetAddressBytes();
|
||||
if (bytes == null || bytes.Length < 1)
|
||||
throw new ArgumentException($"Invalid {nameof(address)}.");
|
||||
return (bytes[0] & 0x1) == 0 ? PhysicalAddressType.Unicast : PhysicalAddressType.Multicast;
|
||||
}
|
||||
|
||||
/// <summary>Gets the administrator (<see cref="PhysicalAddressAdministrator"/>) of the <see cref="PhysicalAddress" />.</summary>
|
||||
/// <param name="address">The address.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="address"/> is null.</exception>
|
||||
/// <returns>The <see cref="PhysicalAddressAdministrator" /> of the physical addess (MAC address).</returns>
|
||||
public static PhysicalAddressAdministrator GetAddressAdministrator(this PhysicalAddress address)
|
||||
{
|
||||
if (address == null)
|
||||
throw new ArgumentNullException(nameof(address));
|
||||
|
||||
var bytes = address.GetAddressBytes();
|
||||
if (bytes == null || bytes.Length < 1)
|
||||
throw new ArgumentException($"Invalid {nameof(address)}.");
|
||||
return (bytes[0] & 0x2) == 0 ? PhysicalAddressAdministrator.Global : PhysicalAddressAdministrator.Local;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace System.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Der Administrator der physikalischen Adresse gibt an, ob die Adresse globally unique oder local administrated ist.
|
||||
/// </summary>
|
||||
public enum PhysicalAddressAdministrator
|
||||
{
|
||||
/// <summary>
|
||||
/// Die Adresse ist global einzigartig (nach der OUI).
|
||||
/// </summary>
|
||||
Global,
|
||||
|
||||
/// <summary>
|
||||
/// Die Adresse ist lokal administriert.
|
||||
/// </summary>
|
||||
Local
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Der Typ der physikalischen Adresse gibt an, ob es um eine UNicast oder Multicast-Adresse handelt.
|
||||
/// </summary>
|
||||
public enum PhysicalAddressType
|
||||
{
|
||||
/// <summary>
|
||||
/// Bezeichnet eine Unicast-Adresse.
|
||||
/// </summary>
|
||||
Unicast,
|
||||
|
||||
/// <summary>
|
||||
/// Bezeichnet eine Multicast-Adresse
|
||||
/// </summary>
|
||||
Multicast
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System;
|
||||
|
||||
[assembly: InternalsVisibleTo("WakeOnLan.Tests")]
|
||||
@@ -0,0 +1,95 @@
|
||||
namespace System.Net
|
||||
{
|
||||
/// <summary>Provides a SecureOn password.</summary>
|
||||
[Serializable]
|
||||
public sealed class SecureOnPassword
|
||||
{
|
||||
private readonly byte[] _password;
|
||||
|
||||
/// <summary>Initializes a new instance of <see cref="SecureOnPassword"/> with the given password.</summary>
|
||||
/// <param name="password">The password as <see cref="Byte"/> array.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="password"/> is null.</exception>
|
||||
/// <exception cref="ArgumentException">The length of the <see cref="T:System.Byte" /> array password is not 6.</exception>
|
||||
public SecureOnPassword(byte[] password)
|
||||
{
|
||||
if (password == null)
|
||||
throw new ArgumentNullException(nameof(password));
|
||||
if (password.Length != 6)
|
||||
throw new ArgumentException(Localization.ArgumentExceptionInvalidPasswordLength);
|
||||
_password = password;
|
||||
}
|
||||
|
||||
/// <summary>Gets the buffer of the password.</summary>
|
||||
public byte[] GetPasswordBytes()
|
||||
{
|
||||
if (_password == null)
|
||||
return null;
|
||||
var buffer = new byte[_password.Length];
|
||||
Array.Copy(_password, buffer, 0);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of <see cref="SecureOnPassword"/> with the given password.</summary>
|
||||
/// <param name="password">The password as <see cref="String"/>.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="password"/> is null.</exception>
|
||||
/// <remarks>Uses <see cref="Text.Encoding.Default" /> as encoding.</remarks>
|
||||
public SecureOnPassword(string password)
|
||||
: this(password, Text.Encoding.Default)
|
||||
{ }
|
||||
|
||||
|
||||
/// <summary>Initializes a new instance of <see cref="SecureOnPassword"/> with the given password.</summary>
|
||||
/// <param name="password">The password as <see cref="String"/>.</param>
|
||||
/// <param name="encoding">The <see cref="Text.Encoding"/> instance to use for the password.</param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="password"/> is null.</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="encoding"/> is null.</exception>
|
||||
/// <exception cref="ArgumentException">The <see cref="Byte"/> array wich is created using the password has more elements than 6.</exception>
|
||||
public SecureOnPassword(string password, Text.Encoding encoding)
|
||||
{
|
||||
if (password == null)
|
||||
throw new ArgumentNullException(nameof(password));
|
||||
if (encoding == null)
|
||||
throw new ArgumentNullException(nameof(encoding));
|
||||
|
||||
if (string.IsNullOrEmpty(password))
|
||||
_password = new byte[6];
|
||||
|
||||
var bytes = encoding.GetBytes(password);
|
||||
if (bytes.Length > 6)
|
||||
throw new ArgumentException(Localization.ArgumentExceptionInvalidPasswordLength);
|
||||
|
||||
_password = new byte[6];
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
_password[i] = bytes[i];
|
||||
if (bytes.Length < 6)
|
||||
{
|
||||
for (int i = bytes.Length - 1; i < 6; i++)
|
||||
_password[i] = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Converts the <see cref="SecureOnPassword"/> to dash notation.</summary>
|
||||
/// <returns>A <see cref="String"/> representing the <see cref="SecureOnPassword"/> as dash notation.</returns>
|
||||
public override string ToString() => ToString("X2");
|
||||
|
||||
/// <summary>Converts the <see cref="SecureOnPassword"/> to dash notation.</summary>
|
||||
/// <returns>A <see cref="String"/> representing the <see cref="SecureOnPassword"/> as dash notation.</returns>
|
||||
private string ToString(string format)
|
||||
{
|
||||
var f = new string[6];
|
||||
for (int i = 0; i < f.Length; i++)
|
||||
f[i] = _password[i].ToString(format);
|
||||
return string.Join("-", f);
|
||||
}
|
||||
|
||||
/// <summary>Converts the <see cref="SecureOnPassword"/> to dash notation.</summary>
|
||||
/// <returns>A <see cref="String"/> representing the <see cref="SecureOnPassword"/> as dash notation.</returns>
|
||||
public string ToString(IFormatProvider format)
|
||||
{
|
||||
var f = new string[6];
|
||||
for (int i = 0; i < f.Length; i++)
|
||||
f[i] = _password[i].ToString(format);
|
||||
return string.Join("-", f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Net.Topology
|
||||
{
|
||||
internal static class ByteArrayExtensions
|
||||
{
|
||||
internal static IEnumerable<bool> ToBitStream(this byte[] bytes, bool fromLeft)
|
||||
{
|
||||
if (bytes == null)
|
||||
throw new ArgumentNullException(nameof(bytes));
|
||||
|
||||
if (fromLeft)
|
||||
{
|
||||
for (int i = 0; i < bytes.Length; ++i)
|
||||
{
|
||||
byte tmp = bytes[i].ReverseBits();
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
yield return (tmp & 1) == 1;
|
||||
tmp >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = bytes.Length - 1; i >= 0; --i)
|
||||
{
|
||||
byte tmp = bytes[i];
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
yield return (tmp & 1) == 1;
|
||||
tmp >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int CountFromSide(byte[] bits, bool value, bool fromleft)
|
||||
{
|
||||
int counter = 0;
|
||||
var str = bits.ToBitStream(fromleft);
|
||||
foreach (var bit in str)
|
||||
{
|
||||
if (bit == value)
|
||||
++counter;
|
||||
else return counter;
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
internal static int CountFromLeft(this byte[] bits, bool value)
|
||||
{
|
||||
if (bits == null)
|
||||
throw new ArgumentNullException(nameof(bits));
|
||||
return CountFromSide(bits, value, true);
|
||||
}
|
||||
|
||||
internal static int CountFromRight(this byte[] bits, bool value)
|
||||
{
|
||||
if (bits == null)
|
||||
throw new ArgumentNullException(nameof(bits));
|
||||
return CountFromSide(bits, value, false);
|
||||
}
|
||||
|
||||
internal static string ToBinaryString(this byte[] bits, char separator)
|
||||
{
|
||||
if (bits == null)
|
||||
throw new ArgumentNullException(nameof(bits));
|
||||
|
||||
const int radix = 2;
|
||||
const int padding = 8;
|
||||
const char paddingChar = '0';
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(Convert.ToString(bits[0], radix).PadLeft(padding, paddingChar)).Append(separator);
|
||||
sb.Append(Convert.ToString(bits[1], radix).PadLeft(padding, paddingChar)).Append(separator);
|
||||
sb.Append(Convert.ToString(bits[2], radix).PadLeft(padding, paddingChar)).Append(separator);
|
||||
sb.Append(Convert.ToString(bits[3], radix).PadLeft(padding, paddingChar));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
internal static string ToBinaryString(this byte[] bits)
|
||||
{
|
||||
if (bits == null)
|
||||
throw new ArgumentNullException(nameof(bits));
|
||||
|
||||
const int radix = 2;
|
||||
const int padding = 8;
|
||||
const char paddingChar = '0';
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(Convert.ToString(bits[0], radix).PadLeft(padding, paddingChar));
|
||||
sb.Append(Convert.ToString(bits[1], radix).PadLeft(padding, paddingChar));
|
||||
sb.Append(Convert.ToString(bits[2], radix).PadLeft(padding, paddingChar));
|
||||
sb.Append(Convert.ToString(bits[3], radix).PadLeft(padding, paddingChar));
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
internal static bool RepresentsValidNetMask(this byte[] bits)
|
||||
{
|
||||
if (bits == null)
|
||||
throw new ArgumentNullException(nameof(bits));
|
||||
|
||||
int fromLeft = bits.CountFromLeft(true);
|
||||
int fromRight = bits.CountFromRight(false);
|
||||
|
||||
// Sum of all counted indexes schloud be equal the whole length
|
||||
return (fromLeft + fromRight) == (8 * NetMask.MaskLength);
|
||||
}
|
||||
|
||||
internal static byte[] And(this byte[] b1, byte[] b2)
|
||||
{
|
||||
if (b1 == null)
|
||||
throw new ArgumentNullException(nameof(b1));
|
||||
if (b2 == null)
|
||||
throw new ArgumentNullException(nameof(b2));
|
||||
|
||||
if (b1.Length == 1 && b2.Length == 1)
|
||||
{
|
||||
int ib1 = b1[0];
|
||||
int ib2 = b2[0];
|
||||
return new[] { (byte)(ib1 & ib2) };
|
||||
}
|
||||
if (b1.Length == 2 && b2.Length == 2)
|
||||
{
|
||||
var sb1 = BitConverter.ToInt16(b1, 0);
|
||||
var sb2 = BitConverter.ToInt16(b2, 0);
|
||||
return BitConverter.GetBytes((short)(sb1 & sb2));
|
||||
}
|
||||
if (b1.Length == 4 && b2.Length == 4)
|
||||
{
|
||||
var ib1 = BitConverter.ToInt32(b1, 0);
|
||||
var ib2 = BitConverter.ToInt32(b2, 0);
|
||||
return BitConverter.GetBytes(ib1 & ib2);
|
||||
}
|
||||
if (b1.Length != b2.Length)
|
||||
{
|
||||
// Or maybe throw exception?
|
||||
|
||||
int maxIndex = Math.Max(b1.Length, b2.Length);
|
||||
byte[] biggerArray = b1.Length > b2.Length ? b1 : b2;
|
||||
byte[] smallerArray = b1.Length <= b2.Length ? b1 : b2;
|
||||
|
||||
var paddedArray = new byte[maxIndex];
|
||||
|
||||
Buffer.BlockCopy(smallerArray, 0, paddedArray, 0, smallerArray.Length);
|
||||
|
||||
Debug.Assert(biggerArray.Length == paddedArray.Length);
|
||||
|
||||
return And(biggerArray, paddedArray);
|
||||
}
|
||||
|
||||
var targetIndex = b1.Length;
|
||||
var andedArray = new byte[targetIndex];
|
||||
Buffer.BlockCopy(b1, 0, andedArray, 0, andedArray.Length);
|
||||
|
||||
for (int i = 0; i < targetIndex; ++i)
|
||||
andedArray[i] &= b2[i];
|
||||
|
||||
return andedArray;
|
||||
}
|
||||
|
||||
internal static byte[] Or(this byte[] b1, byte[] b2)
|
||||
{
|
||||
if (b1 == null)
|
||||
throw new ArgumentNullException(nameof(b1));
|
||||
if (b2 == null)
|
||||
throw new ArgumentNullException(nameof(b2));
|
||||
|
||||
if (b1.Length == 1 && b2.Length == 1)
|
||||
{
|
||||
int ib1 = b1[0];
|
||||
int ib2 = b2[0];
|
||||
return new[] { (byte)(ib1 | ib2) };
|
||||
}
|
||||
if (b1.Length == 2 && b2.Length == 2)
|
||||
{
|
||||
var sb1 = BitConverter.ToInt16(b1, 0);
|
||||
var sb2 = BitConverter.ToInt16(b2, 0);
|
||||
return BitConverter.GetBytes((short)(sb1 | sb2));
|
||||
}
|
||||
if (b1.Length == 4 && b2.Length == 4)
|
||||
{
|
||||
var ib1 = BitConverter.ToInt32(b1, 0);
|
||||
var ib2 = BitConverter.ToInt32(b2, 0);
|
||||
return BitConverter.GetBytes(ib1 | ib2);
|
||||
}
|
||||
if (b1.Length != b2.Length)
|
||||
{
|
||||
// Or maybe throw exception?
|
||||
|
||||
int maxIndex = Math.Max(b1.Length, b2.Length);
|
||||
byte[] biggerArray = b1.Length > b2.Length ? b1 : b2;
|
||||
byte[] smallerArray = b1.Length <= b2.Length ? b1 : b2;
|
||||
|
||||
var paddedArray = new byte[maxIndex];
|
||||
|
||||
Buffer.BlockCopy(smallerArray, 0, paddedArray, 0, smallerArray.Length);
|
||||
|
||||
Debug.Assert(biggerArray.Length == paddedArray.Length);
|
||||
|
||||
return Or(biggerArray, paddedArray);
|
||||
}
|
||||
|
||||
var targetIndex = b1.Length;
|
||||
var oredArray = new byte[targetIndex];
|
||||
Buffer.BlockCopy(b1, 0, oredArray, 0, oredArray.Length);
|
||||
|
||||
for (int i = 0; i < targetIndex; ++i)
|
||||
oredArray[i] |= b2[i];
|
||||
|
||||
return oredArray;
|
||||
}
|
||||
|
||||
internal static byte[] Xor(this byte[] b1, byte[] b2)
|
||||
{
|
||||
if (b1 == null)
|
||||
throw new ArgumentNullException(nameof(b1));
|
||||
if (b2 == null)
|
||||
throw new ArgumentNullException(nameof(b2));
|
||||
|
||||
// TODO: Testing
|
||||
|
||||
if (b1.Length == 1 && b2.Length == 1)
|
||||
{
|
||||
int ib1 = b1[0];
|
||||
int ib2 = b2[0];
|
||||
return new[] { (byte)(ib1 ^ ib2) };
|
||||
}
|
||||
if (b1.Length == 2 && b2.Length == 2)
|
||||
{
|
||||
var sb1 = BitConverter.ToInt16(b1, 0);
|
||||
var sb2 = BitConverter.ToInt16(b2, 0);
|
||||
return BitConverter.GetBytes((short)(sb1 ^ sb2));
|
||||
}
|
||||
if (b1.Length == 4 && b2.Length == 4)
|
||||
{
|
||||
var ib1 = BitConverter.ToInt32(b1, 0);
|
||||
var ib2 = BitConverter.ToInt32(b2, 0);
|
||||
return BitConverter.GetBytes(ib1 ^ ib2);
|
||||
}
|
||||
if (b1.Length != b2.Length)
|
||||
{
|
||||
// Or maybe throw exception?
|
||||
|
||||
int maxIndex = Math.Max(b1.Length, b2.Length);
|
||||
byte[] biggerArray = b1.Length > b2.Length ? b1 : b2;
|
||||
byte[] smallerArray = b1.Length <= b2.Length ? b1 : b2;
|
||||
|
||||
var paddedArray = new byte[maxIndex];
|
||||
|
||||
Buffer.BlockCopy(smallerArray, 0, paddedArray, 0, smallerArray.Length);
|
||||
|
||||
Debug.Assert(biggerArray.Length == paddedArray.Length);
|
||||
|
||||
return Xor(biggerArray, paddedArray);
|
||||
}
|
||||
|
||||
var targetIndex = b1.Length;
|
||||
var xoredArray = new byte[targetIndex];
|
||||
Buffer.BlockCopy(b1, 0, xoredArray, 0, xoredArray.Length);
|
||||
|
||||
for (int i = 0; i < targetIndex; ++i)
|
||||
xoredArray[i] ^= b2[i];
|
||||
|
||||
return xoredArray;
|
||||
}
|
||||
|
||||
internal static byte[] Not(this byte[] bits)
|
||||
{
|
||||
if (bits == null)
|
||||
throw new ArgumentNullException(nameof(bits));
|
||||
|
||||
if (bits.Length == 4)
|
||||
{
|
||||
var i = BitConverter.ToInt32(bits, 0);
|
||||
return BitConverter.GetBytes(~i);
|
||||
}
|
||||
var newBytes = new byte[bits.Length];
|
||||
for (int i = 0; i < newBytes.Length; ++i)
|
||||
newBytes[i] = unchecked((byte)(~bits[i]));
|
||||
return newBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
namespace System.Net.Topology
|
||||
{
|
||||
internal static class ByteExtensions
|
||||
{
|
||||
public static byte[] BitReverseTable = {
|
||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
||||
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
|
||||
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
|
||||
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
|
||||
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
|
||||
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
|
||||
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
|
||||
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
|
||||
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
|
||||
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
|
||||
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
|
||||
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
|
||||
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
||||
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
|
||||
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
|
||||
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
|
||||
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
|
||||
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
|
||||
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
|
||||
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
|
||||
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
|
||||
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
|
||||
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
|
||||
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
|
||||
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
|
||||
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
|
||||
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
|
||||
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
|
||||
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
|
||||
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
|
||||
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
|
||||
};
|
||||
|
||||
public static byte ReverseBits(this byte toReverse) => BitReverseTable[toReverse];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
namespace System.Net.Topology
|
||||
{
|
||||
/// <summary>Provides an interface for IP net masks.</summary>
|
||||
public interface INetMask
|
||||
{
|
||||
/// <summary>Gets the length of the net mask in bits.</summary>
|
||||
int AddressLength { get; }
|
||||
|
||||
/// <summary>Gets the amount of set bits from the left side (used in CIDR-Notation of net masks).</summary>
|
||||
int Cidr { get; }
|
||||
|
||||
/// <summary>Gets the bits of the net mask instance as an BitArray object instance.</summary>
|
||||
/// <returns>The bits of the net mask instance as an BitArray object instance</returns>
|
||||
byte[] GetMaskBytes();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Net.Topology
|
||||
{
|
||||
/// <summary>Provides extension methods for the <see cref="T:System.Net.IPAddress"/>.</summary>
|
||||
public static class IPAddressExtensions
|
||||
{
|
||||
private const string OnlyIPv4Supported = "Only IPv4 is currently supported";
|
||||
|
||||
/// <summary>Enumerates through the siblings of an <see cref="T:System.Net.IPAddress"/> in a network. Compliant to RFC 950 (2^n-2).</summary>
|
||||
/// <param name="address">The address</param>
|
||||
/// <param name="mask">The net mask of the network</param>
|
||||
public static IEnumerable<IPAddress> GetSiblings(this IPAddress address, NetMask mask)
|
||||
{
|
||||
return GetSiblings(address, mask, SiblingOptions.ExcludeUnusable);
|
||||
}
|
||||
|
||||
/// <summary>Enumerates through the siblings of an <see cref="T:System.Net.IPAddress"/> in a network.</summary>
|
||||
/// <param name="address">The address</param>
|
||||
/// <param name="mask">The net mask of the network</param>
|
||||
/// <param name="options">Options which addresses to include an which not</param>
|
||||
public static IEnumerable<IPAddress> GetSiblings(this IPAddress address, NetMask mask, SiblingOptions options)
|
||||
{
|
||||
if (address == null)
|
||||
throw new ArgumentNullException(nameof(address));
|
||||
if (mask == null)
|
||||
throw new ArgumentNullException(nameof(mask));
|
||||
if (address.AddressFamily != Sockets.AddressFamily.InterNetwork)
|
||||
throw new NotSupportedException(OnlyIPv4Supported);
|
||||
|
||||
bool includeSelf = BitHelper.IsOptionSet(options, SiblingOptions.IncludeSelf);
|
||||
bool includeBroadcast = BitHelper.IsOptionSet(options, SiblingOptions.IncludeBroadcast);
|
||||
bool includeNetworkIdentifier = BitHelper.IsOptionSet(options, SiblingOptions.IncludeNetworkIdentifier);
|
||||
|
||||
bool alreadyReturnedSelf = false;
|
||||
|
||||
var netPrefix = address.GetNetworkPrefix(mask);
|
||||
|
||||
if (includeNetworkIdentifier)
|
||||
{
|
||||
netPrefix = address.GetNetworkPrefix(mask);
|
||||
if (netPrefix.Equals(address))
|
||||
alreadyReturnedSelf = true;
|
||||
yield return netPrefix;
|
||||
}
|
||||
|
||||
var selfAddressBytes = address.GetAddressBytes();
|
||||
|
||||
var netPrefixBytes = netPrefix.GetAddressBytes();
|
||||
|
||||
int cidr = mask.Cidr;
|
||||
uint maxHosts = 0xFFFFFFFF;
|
||||
|
||||
if (cidr > 0)
|
||||
maxHosts = (uint)(1 << (8 * NetMask.MaskLength - cidr)) - 1;
|
||||
|
||||
var hostBytes = new byte[NetMask.MaskLength];
|
||||
for (int hostPart = 1; hostPart < maxHosts; ++hostPart)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
hostBytes[0] = (byte)(hostPart >> 24);
|
||||
hostBytes[1] = (byte)(hostPart >> 16);
|
||||
hostBytes[2] = (byte)(hostPart >> 8);
|
||||
hostBytes[3] = (byte)(hostPart >> 0);
|
||||
}
|
||||
|
||||
Debug.WriteLine("HostPart: " + hostPart.ToString("X2").PadLeft(8, '0') + " (" + BitConverter.ToString(hostBytes) + ")");
|
||||
|
||||
var nextIpBytes = netPrefixBytes.Or(hostBytes);
|
||||
var nextIp = new IPAddress(nextIpBytes);
|
||||
|
||||
if (!alreadyReturnedSelf)
|
||||
{
|
||||
if (includeSelf)
|
||||
{
|
||||
if (nextIpBytes[0] == selfAddressBytes[0]
|
||||
&& nextIpBytes[1] == selfAddressBytes[1]
|
||||
&& nextIpBytes[2] == selfAddressBytes[2]
|
||||
&& nextIpBytes[3] == selfAddressBytes[3])
|
||||
alreadyReturnedSelf = true;
|
||||
yield return nextIp;
|
||||
}
|
||||
else if (nextIpBytes[0] != selfAddressBytes[0]
|
||||
|| nextIpBytes[1] != selfAddressBytes[1]
|
||||
|| nextIpBytes[2] != selfAddressBytes[2]
|
||||
|| nextIpBytes[3] != selfAddressBytes[3])
|
||||
yield return nextIp;
|
||||
}
|
||||
else
|
||||
yield return nextIp;
|
||||
}
|
||||
|
||||
if (includeBroadcast)
|
||||
{
|
||||
var broadcastAddress = address.GetBroadcastAddress(mask);
|
||||
if (!address.Equals(broadcastAddress) || (address.Equals(broadcastAddress) && !alreadyReturnedSelf))
|
||||
yield return broadcastAddress;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Gets the network prefix of an <see cref="T:System.Net.IPAddress"/>.</summary>
|
||||
/// <param name="address">The address</param>
|
||||
/// <param name="mask">The net mask of the network</param>
|
||||
/// <returns>The network prefix of an <see cref="T:System.Net.IPAddress"/></returns>
|
||||
public static IPAddress GetNetworkPrefix(this IPAddress address, NetMask mask)
|
||||
{
|
||||
if (address == null)
|
||||
throw new ArgumentNullException(nameof(address));
|
||||
if (mask == null)
|
||||
throw new ArgumentNullException(nameof(mask));
|
||||
|
||||
if (address.AddressFamily != Sockets.AddressFamily.InterNetwork)
|
||||
throw new NotSupportedException(OnlyIPv4Supported);
|
||||
|
||||
return mask & address;
|
||||
}
|
||||
|
||||
/// <summary>Gets the broadcast address of an <see cref="T:System.Net.IPAddress"/>.</summary>
|
||||
/// <param name="address">The address</param>
|
||||
/// <param name="mask">The net mask of the network</param>
|
||||
/// <returns>The broadcast address of an <see cref="T:System.Net.IPAddress"/></returns>
|
||||
public static IPAddress GetBroadcastAddress(this IPAddress address, NetMask mask)
|
||||
{
|
||||
if (address == null)
|
||||
throw new ArgumentNullException("address");
|
||||
if (mask == null)
|
||||
throw new ArgumentNullException("mask");
|
||||
|
||||
if (address.AddressFamily != Sockets.AddressFamily.InterNetwork)
|
||||
throw new NotSupportedException(OnlyIPv4Supported);
|
||||
|
||||
// TODO: Test
|
||||
|
||||
var ipBytes = address.GetAddressBytes();
|
||||
var notMaskBytes = mask.GetMaskBytes().Not();
|
||||
|
||||
var broadcastAddressBytes = notMaskBytes.Or(ipBytes);
|
||||
return new IPAddress(broadcastAddressBytes);
|
||||
}
|
||||
|
||||
/// <summary>Gets the host identifier (rest) an <see cref="T:System.Net.IPAddress"/>.</summary>
|
||||
/// <param name="address">The address</param>
|
||||
/// <param name="mask">The net mask of the network</param>
|
||||
/// <returns>The host identifier (rest) an <see cref="T:System.Net.IPAddress"/></returns>
|
||||
public static IPAddress GetHostIdentifier(this IPAddress address, NetMask mask)
|
||||
{
|
||||
if (address == null)
|
||||
throw new ArgumentNullException(nameof(address));
|
||||
if (mask == null)
|
||||
throw new ArgumentNullException(nameof(mask));
|
||||
if (address.AddressFamily != Sockets.AddressFamily.InterNetwork)
|
||||
throw new NotSupportedException(OnlyIPv4Supported);
|
||||
|
||||
var maskBits = mask.GetMaskBytes();
|
||||
var ipBits = address.GetAddressBytes();
|
||||
|
||||
// ~Mask & IP
|
||||
var retVal = maskBits.Not().And(ipBits);
|
||||
var bytes = new byte[NetMask.MaskLength];
|
||||
Buffer.BlockCopy(retVal, 0, bytes, 0, bytes.Length);
|
||||
|
||||
return new IPAddress(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Net.Topology
|
||||
{
|
||||
// TODO: Use Span<T> when available (instead of byte arrays)
|
||||
/// <summary>Represents an IPv4 net mask.</summary>
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct NetMask : INetMask, IEquatable<NetMask>
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
private readonly uint _mask;
|
||||
|
||||
#region byte-wise fields
|
||||
|
||||
// We are assuming here, that the byte-ordering is like on a normal x86 system
|
||||
|
||||
[FieldOffset(3)]
|
||||
private readonly byte _maskB0;
|
||||
[FieldOffset(2)]
|
||||
private readonly byte _maskB1;
|
||||
[FieldOffset(1)]
|
||||
private readonly byte _maskB2;
|
||||
[FieldOffset(0)]
|
||||
private readonly byte _maskB3;
|
||||
|
||||
#endregion
|
||||
|
||||
internal const int MaskLength = 4;
|
||||
|
||||
/// <summary>Represents an empty IPv4 NetMask (all bits set to 0).</summary>
|
||||
public static NetMask Empty { get; } = new NetMask();
|
||||
|
||||
/// <summary>Gets the length of the net mask in bits.</summary>
|
||||
public int AddressLength => MaskLength * 8;
|
||||
|
||||
/// <summary>Gets the amount of set bits from the left side (used in CIDR-Notation of net masks).</summary>
|
||||
public int Cidr => GetCidr(_mask);
|
||||
|
||||
#region Ctors
|
||||
|
||||
/// <summary>Creates a new instance of <see cref="T:System.Net.Topology.NetMask"/> cloning an existing instance of <see cref="T:System.Net.Topology.NetMask"/>.</summary>
|
||||
public NetMask(NetMask mask)
|
||||
{
|
||||
if (mask == null)
|
||||
throw new ArgumentNullException(nameof(mask));
|
||||
_maskB0 = _maskB1 = _maskB2 = _maskB3 = 0;
|
||||
_mask = mask._mask;
|
||||
}
|
||||
|
||||
/// <summary>Creates a new instance of <see cref="T:System.Net.Topology.NetMask"/> from an array of <see cref="System.Byte"/>.</summary>
|
||||
public NetMask(byte[] value)
|
||||
{
|
||||
_maskB0 = _maskB1 = _maskB2 = _maskB3 = 0;
|
||||
_mask = 0;
|
||||
if (value == null || value.Length == 0) // maybe throw ArgumentNullException?
|
||||
return;
|
||||
|
||||
if (value.Length != MaskLength)
|
||||
throw new ArgumentException("Invalid mask length.");
|
||||
|
||||
CheckMaskBytes(value); // check if passed mask are a valid mask. if not, throw Exception
|
||||
_maskB0 = value[0];
|
||||
_maskB1 = value[1];
|
||||
_maskB2 = value[2];
|
||||
_maskB3 = value[3];
|
||||
}
|
||||
|
||||
/// <summary>Creates a new instance of <see cref="T:System.Net.Topology.NetMask"/> from a given <see cref="T:System.Net.IPAddress"/>.</summary>
|
||||
/// <param name="address">The IPv4 address.</param>
|
||||
public NetMask(IPAddress address)
|
||||
: this(address == null ? null : address.GetAddressBytes())
|
||||
{ }
|
||||
|
||||
/// <summary>Creates a new instance of <see cref="T:System.Net.Topology.NetMask"/>.</summary>
|
||||
/// <param name="m0">The first byte.</param>
|
||||
/// <param name="m1">The second byte.</param>
|
||||
/// <param name="m2">The third byte.</param>
|
||||
/// <param name="m3">The fourth byte.</param>
|
||||
public NetMask(byte m0, byte m1, byte m2, byte m3)
|
||||
: this(new[] { m0, m1, m2, m3 })
|
||||
{ }
|
||||
|
||||
/// <summary>Creates a new instance of <see cref="T:System.Net.Topology.NetMask"/>.</summary>
|
||||
/// <param name="cidr">The mask represented by the CIDR notation integer.</param>
|
||||
public NetMask(byte cidr)
|
||||
{
|
||||
// maybe change parameter type interpretation to CIDR?
|
||||
if (cidr > MaskLength * 8)
|
||||
throw new ArgumentException("Invalid CIDR length");
|
||||
_maskB0 = _maskB1 = _maskB2 = _maskB3 = 0; // to keep init checks happy
|
||||
_mask = GetUIntFromCidrValue(cidr);
|
||||
}
|
||||
|
||||
private NetMask(uint ipv4Mask)
|
||||
{
|
||||
_maskB0 = _maskB1 = _maskB2 = _maskB3 = 0; // to keep init checks happy
|
||||
_mask = ipv4Mask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static void CheckMaskBytes(byte[] bytes)
|
||||
{
|
||||
if (!bytes.RepresentsValidNetMask())
|
||||
throw new ArgumentException("The passed mask do not represent a valid net mask.");
|
||||
}
|
||||
|
||||
/// <summary>Gets the bits of the net mask instance as an BitArray object instance.</summary>
|
||||
/// <returns>The bits of the net mask instance as an BitArray object instance.</returns>
|
||||
public byte[] GetMaskBytes() => new[] { _maskB0, _maskB1, _maskB2, _maskB3 };
|
||||
|
||||
private static int GetCidr(uint mask)
|
||||
{
|
||||
Debug.Assert(sizeof(uint) == MaskLength);
|
||||
return mask.CountOnesFromLeft();
|
||||
}
|
||||
|
||||
/// <summary>Extends the current <see cref="T:System.Net.Topology.NetMask"/> instance by a given value (CIDR-wise).</summary>
|
||||
/// <param name="mask">The mask to use as a reference.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <remarks>Because <see cref="T:System.Net.Topology.NetMask"/> is a reference type, this method is static. If it were not like this, you could change the value of <see cref="T:System.Net.Topology.NetMask"/>.Empty, for example.</remarks>
|
||||
public static NetMask Extend(NetMask mask, int value)
|
||||
{
|
||||
int currentCidr = mask.Cidr;
|
||||
if (currentCidr >= MaskLength * 8)
|
||||
return new NetMask(mask);
|
||||
if (currentCidr <= 0)
|
||||
currentCidr = 0;
|
||||
|
||||
int newLength = Math.Max(Math.Min(currentCidr + value, 32), 0);
|
||||
|
||||
var m = BytesFromCidrValue(newLength);
|
||||
|
||||
return new NetMask(m);
|
||||
}
|
||||
|
||||
/// <summary>Abbreviates the current <see cref="T:System.Net.Topology.NetMask"/> instance by a given value (CIDR-wise).</summary>
|
||||
/// <param name="mask">The mask to use as a reference.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <remarks>Because <see cref="T:System.Net.Topology.NetMask"/> is a reference type, this method is static. If it were not like this, you could change the value of <see cref="T:System.Net.Topology.NetMask"/>.Empty, for example.</remarks>
|
||||
public static NetMask Abbreviate(NetMask mask, int value)
|
||||
{
|
||||
int currentCidr = mask.Cidr;
|
||||
if (currentCidr < 1)
|
||||
return new NetMask(mask);
|
||||
if (currentCidr >= MaskLength * 8)
|
||||
currentCidr = MaskLength * 8;
|
||||
|
||||
int newLength = Math.Max(Math.Min(currentCidr - value, 32), 0);
|
||||
|
||||
var m = BytesFromCidrValue(newLength);
|
||||
return new NetMask(m);
|
||||
}
|
||||
|
||||
/// <summary>Returns a value indicating whether the given array of <see cref="T:System.Byte"/> represents a valid net mask.</summary>
|
||||
/// <returns>True if the given array of <see cref="T:System.Byte"/> represents a valid net mask, otherwise false.</returns>
|
||||
public static bool GetIsValidNetMask(byte[] mask) => mask.RepresentsValidNetMask();
|
||||
|
||||
// TODO: Testing(!)
|
||||
[Obsolete]
|
||||
private static byte[] BytesFromCidrValue(int cidr)
|
||||
{
|
||||
int target = MaskLength * 8 - cidr;
|
||||
int mask = 0;
|
||||
for (int i = 0; i < target; ++i)
|
||||
{
|
||||
mask >>= 1;
|
||||
mask |= unchecked((int)0x80000000);
|
||||
}
|
||||
var bytes = BitConverter.GetBytes(~mask);
|
||||
return new[] {
|
||||
bytes[0].ReverseBits(),
|
||||
bytes[1].ReverseBits(),
|
||||
bytes[2].ReverseBits(),
|
||||
bytes[3].ReverseBits()
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Testing(!)
|
||||
private static uint GetUIntFromCidrValue(int cidr) => UIntExtensions.CreateWithOnesFromLeft(cidr);
|
||||
|
||||
#region Operators
|
||||
|
||||
#region Equality
|
||||
|
||||
/// <summary>Returns a other indicating whether two instances of <see cref="T:System.Net.Topology.NetMask" /> are equal.</summary>
|
||||
/// <param name="n1">The first other to compare.</param>
|
||||
/// <param name="n2">The second other to compare.</param>
|
||||
/// <returns>true if <paramref name="n1" /> and <paramref name="n2" /> are equal; otherwise, false.</returns>
|
||||
public static bool operator ==(NetMask n1, NetMask n2)
|
||||
{
|
||||
if (ReferenceEquals(n1, n2))
|
||||
return true;
|
||||
if (((object)n1 == null) || ((object)n2 == null))
|
||||
return false;
|
||||
return n1.Equals(n2);
|
||||
}
|
||||
|
||||
/// <summary>Returns a other indicating whether two instances of <see cref="T:System.Net.Topology.NetMask" /> are not equal.</summary>
|
||||
/// <param name="n1">The first other to compare. </param>
|
||||
/// <param name="n2">The second other to compare. </param>
|
||||
/// <returns>true if <paramref name="n1" /> and <paramref name="n2" /> are not equal; otherwise, false.</returns>
|
||||
public static bool operator !=(NetMask n1, NetMask n2) => !(n1 == n2); // Problem solved
|
||||
|
||||
#endregion
|
||||
#region And
|
||||
|
||||
/// <summary>Bitwise combines a <see cref="T:System.Net.Topology.NetMask" /> instance and an <see cref="T:System.Net.IPAddress"/> the AND operation.</summary>
|
||||
/// <param name="mask">The net mask.</param>
|
||||
/// <param name="address">The IPAddress.</param>
|
||||
/// <returns>The bitwised combination using the AND operation.</returns>
|
||||
public static IPAddress operator &(IPAddress address, NetMask mask) => mask & address;
|
||||
|
||||
/// <summary>Bitwise combines a <see cref="T:System.Net.Topology.NetMask" /> instance and an <see cref="T:System.Net.IPAddress"/> the AND operation.</summary>
|
||||
/// <param name="mask">The net mask.</param>
|
||||
/// <param name="address">The IPAddress.</param>
|
||||
/// <returns>The bitwised combination using the AND operation.</returns>
|
||||
public static IPAddress BitwiseAnd(IPAddress address, NetMask mask) => mask & address;
|
||||
|
||||
/// <summary>Bitwise combines a <see cref="T:System.Net.Topology.NetMask" /> instance and an <see cref="T:System.Net.IPAddress"/> the AND operation.</summary>
|
||||
/// <param name="mask">The net mask.</param>
|
||||
/// <param name="address">The IPAddress.</param>
|
||||
/// <returns>The bitwised combination using the AND operation.</returns>
|
||||
public static IPAddress operator &(NetMask mask, IPAddress address)
|
||||
{
|
||||
var ipBytes = address == null
|
||||
? new byte[MaskLength]
|
||||
: address.GetAddressBytes();
|
||||
var maskBytes = mask == null
|
||||
? new byte[MaskLength]
|
||||
: new byte[] { mask._maskB0, mask._maskB1, mask._maskB2, mask._maskB3 };
|
||||
|
||||
byte[] combinedBytes = maskBytes.And(ipBytes);
|
||||
return new IPAddress(combinedBytes);
|
||||
}
|
||||
|
||||
/// <summary>Bitwise combines a <see cref="T:System.Net.Topology.NetMask" /> instance and an <see cref="T:System.Net.IPAddress"/> the AND operation.</summary>
|
||||
/// <param name="mask">The net mask.</param>
|
||||
/// <param name="address">The IPAddress.</param>
|
||||
/// <returns>The bitwised combination using the AND operation.</returns>
|
||||
public static IPAddress BitwiseAnd(NetMask mask, IPAddress address) => mask & address;
|
||||
|
||||
/// <summary>Bitwise combines the two instances of <see cref="T:System.Net.Topology.NetMask" /> using the AND operation.</summary>
|
||||
/// <param name="n1">The first other.</param>
|
||||
/// <param name="n2">The second other.</param>
|
||||
/// <returns>The bitwised combination using the AND operation.</returns>
|
||||
public static NetMask operator &(NetMask n1, NetMask n2) => new NetMask(n1._mask & n2._mask);
|
||||
|
||||
/// <summary>Bitwise combines the two instances of <see cref="T:System.Net.Topology.NetMask" /> using the AND operation.</summary>
|
||||
/// <param name="n1">The first other.</param>
|
||||
/// <param name="n2">The second other.</param>
|
||||
/// <returns>The bitwised combination using the AND operation.</returns>
|
||||
public static NetMask BitwiseAnd(NetMask n1, NetMask n2) => n1 & n2;
|
||||
|
||||
#endregion
|
||||
#region Or
|
||||
|
||||
/// <summary>Bitwise combines the two instances of <see cref="T:System.Net.Topology.NetMask" /> using the OR operation.</summary>
|
||||
/// <param name="n1">The first other.</param>
|
||||
/// <param name="n2">The second other.</param>
|
||||
/// <returns>The bitwised combination using the OR operation.</returns>
|
||||
public static NetMask operator |(NetMask n1, NetMask n2) => new NetMask(n1._mask | n2._mask);
|
||||
|
||||
/// <summary>Bitwise combines the two instances of <see cref="T:System.Net.Topology.NetMask" /> using the OR operation.</summary>
|
||||
/// <param name="n1">The first other.</param>
|
||||
/// <param name="n2">The second other.</param>
|
||||
/// <returns>The bitwised combination using the OR operation.</returns>
|
||||
public static NetMask BitwiseOr(NetMask n1, NetMask n2) => n1 | n2;
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
#region Common overrides
|
||||
|
||||
/// <summary>Converts the other of this instance to its equivalent string representation.</summary>
|
||||
/// <returns>A string that represents the other of this instance.</returns>
|
||||
/// <filterpriority>1</filterpriority>
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder(4 * 3 + 3 * 3 + 32 + 3 + 3); // 255.255.255.255 (11111111111111111111111111111111)
|
||||
|
||||
var arr = new byte[] { _maskB0, _maskB1, _maskB2, _maskB3 };
|
||||
var asString = arr.ToBinaryString('.');
|
||||
|
||||
sb.Append(arr[0]).Append('.').Append(arr[1]).Append('.').Append(arr[2]).Append('.').Append(arr[3]).Append(" (");
|
||||
sb.Append(asString).Append(')');
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>Returns a value indicating whether this instance and a specified <see cref="T:System.Object" /> represent the same type and other.</summary>
|
||||
/// <returns>true if <paramref name="obj" /> is a <see cref="T:System.Net.Topology.NetMask" /> and equal to this instance; otherwise, false.</returns>
|
||||
/// <param name="obj">The object to compare with this instance. </param>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public override bool Equals(object obj) => obj != null && obj is NetMask && Equals((NetMask)obj);
|
||||
|
||||
/// <summary>Returns a value indicating whether this instance and a specified <see cref="T:System.Net.Topology.NetMask" /> object represent the same other.</summary>
|
||||
/// <returns>true if <paramref name="other" /> is equal to this instance; otherwise, false.</returns>
|
||||
/// <param name="other">An object to compare to this instance.</param>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public bool Equals(NetMask other) => other._mask == _mask;
|
||||
|
||||
/// <summary>Returns the hash code for this instance.</summary>
|
||||
/// <returns>A 32-bit signed integer hash code.</returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public override int GetHashCode() => unchecked((int)_mask);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
|
||||
namespace System.Net.Topology
|
||||
{
|
||||
/// <summary>Provides extension methods for the <see cref="T:System.Net.Topology.NetMask"/>.</summary>
|
||||
public static class NetMaskExtensions
|
||||
{
|
||||
/// <summary>Gets the number of siblings an <see cref="T:System.Net.IPAddress"/> can have in a given network. Compliant to RFC 950 (2^n-2).</summary>
|
||||
/// <param name="mask">The net mask of the network</param>
|
||||
/// <returns>The number of siblings an <see cref="T:System.Net.IPAddress"/> can have in the given network.</returns>
|
||||
public static int GetSiblingCount(this NetMask mask) => GetSiblingCount(mask, SiblingOptions.ExcludeUnusable);
|
||||
|
||||
/// <summary>Gets the number of siblings an <see cref="T:System.Net.IPAddress"/> can have in a given network.</summary>
|
||||
/// <param name="mask">The net mask of the network</param>
|
||||
/// <param name="options">Options which addresses to include an which not</param>
|
||||
/// <returns>The number of siblings an <see cref="T:System.Net.IPAddress"/> can have in the given network.</returns>
|
||||
public static int GetSiblingCount(this NetMask mask, SiblingOptions options)
|
||||
{
|
||||
if (mask == null)
|
||||
throw new ArgumentNullException(nameof(mask));
|
||||
|
||||
bool includeSelf = BitHelper.IsOptionSet(options, SiblingOptions.IncludeSelf);
|
||||
bool includeBroadcast = BitHelper.IsOptionSet(options, SiblingOptions.IncludeBroadcast);
|
||||
bool includeNetworkIdentifier = BitHelper.IsOptionSet(options, SiblingOptions.IncludeNetworkIdentifier);
|
||||
|
||||
var hostPartBits = mask.GetMaskBytes().CountFromRight(false);
|
||||
var total = 1 << hostPartBits;
|
||||
total -= includeSelf ? 0 : 1;
|
||||
total -= includeBroadcast ? 0 : 1;
|
||||
total -= includeNetworkIdentifier ? 0 : 1;
|
||||
|
||||
// TODO: Testing
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace System.Net.Topology
|
||||
{
|
||||
/// <summary>Provides options for doing network sibling calculations using a net mask.</summary>
|
||||
[Flags]
|
||||
public enum SiblingOptions
|
||||
{
|
||||
/// <summary>Do not include the broadcast or net address neither the addess passed to the method.</summary>
|
||||
ExcludeAll = 0,
|
||||
/// <summary>Include the addess passed to the method.</summary>
|
||||
IncludeSelf = 1,
|
||||
/// <summary>Include the addess passed to the method. Compliant to RFC 950 (2^n-2).</summary>
|
||||
ExcludeUnusable = IncludeSelf,
|
||||
/// <summary>Include the broadcast address.</summary>
|
||||
IncludeBroadcast = 2,
|
||||
/// <summary>Include the net address.</summary>
|
||||
IncludeNetworkIdentifier = 4,
|
||||
/// <summary>Include all addresses possible. RFC 1878 (2^n).</summary>
|
||||
IncludeAll = IncludeSelf | IncludeBroadcast | IncludeNetworkIdentifier
|
||||
}
|
||||
|
||||
internal static class BitHelper
|
||||
{
|
||||
[Runtime.TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")] // as if NGen will ever compile this assembly ;)
|
||||
[Runtime.CompilerServices.MethodImpl(Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
|
||||
internal static bool IsOptionSet(SiblingOptions value, SiblingOptions testValue) => (value & testValue) == testValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
namespace System.Net.Topology
|
||||
{
|
||||
internal static class StringExtensions
|
||||
{
|
||||
// TODO: The following method uses unsafe stuff. We don't want to pass the /unsafe flag to the compiler, so we use a simple, safe method instead.
|
||||
// As soon as .NET Standard with Span<T> and the new String.Create is available, we can make this faster and safe.
|
||||
/*
|
||||
internal static unsafe string Reverse(this string input)
|
||||
{
|
||||
int len = input.Length;
|
||||
|
||||
// Why allocate a char[] array on the heap when you won't use it
|
||||
// outside of this method? Use the stack.
|
||||
char* reversed = stackalloc char[len];
|
||||
|
||||
// Avoid bounds-checking performance penalties.
|
||||
fixed (char* str = input)
|
||||
{
|
||||
int i = 0;
|
||||
int j = i + len - 1;
|
||||
while (i < len)
|
||||
reversed[i++] = str[j--];
|
||||
}
|
||||
|
||||
// Need to use this overload for the System.String constructor
|
||||
// as providing just the char* pointer could result in garbage
|
||||
// at the end of the string (no guarantee of null terminator).
|
||||
return new string(reversed, 0, len);
|
||||
}
|
||||
*/
|
||||
internal static string Reverse(this string input)
|
||||
{
|
||||
char[] chars = input.ToCharArray();
|
||||
Array.Reverse(chars);
|
||||
return new string(chars);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Net.Topology
|
||||
{
|
||||
internal static class UIntExtensions
|
||||
{
|
||||
// TODO: Tests
|
||||
public static int CountOnesFromLeft(this uint value)
|
||||
{
|
||||
var occurences = 0;
|
||||
for (uint i = 1u << 31; i >= 0; i >>= 1)
|
||||
{
|
||||
if ((i & value) != 0)
|
||||
++occurences;
|
||||
else
|
||||
break;
|
||||
}
|
||||
return occurences;
|
||||
}
|
||||
|
||||
// TODO: Tests
|
||||
public static uint CreateWithOnesFromLeft(int count)
|
||||
{
|
||||
if (count > 32)
|
||||
throw new ArgumentException("Cannot set more than 32 bits to one!");
|
||||
|
||||
var value = 0u;
|
||||
|
||||
var mask = 1u << 31;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
value |= mask;
|
||||
mask >>= 1;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<Authors>Niklas Mollenhauer</Authors>
|
||||
<PackageVersion>2.0.2</PackageVersion>
|
||||
<Description>Library for Sending magic packets and performing IP address operations.</Description>
|
||||
<PackageLicenseExpression>LGPL-3.0-only</PackageLicenseExpression>
|
||||
<PackageProjectUrl>https://github.com/nikeee/wake-on-lan</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/nikeee/wake-on-lan.git</RepositoryUrl>
|
||||
<PackageTags>WakeOnLan, magic packets</PackageTags>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<RootNamespace>System.Net</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.6.0" />
|
||||
<PackageReference Include="System.Runtime.Serialization.Formatters" Version="4.3.0" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in new issue
Block a user