mirror of
https://github.com/DarthAffe/RGB.NET.git
synced 2026-03-24 15:58:45 +00:00
Compare commits
No commits in common. "ead342388b5be3ad9e22df29e8b74228e108556f" and "aa67a606a5194882f97ff345e0651668715e7424" have entirely different histories.
ead342388b
...
aa67a606a5
@ -1,179 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace RGB.NET.Core;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Offers some helper methods for timed operations.
|
|
||||||
/// </summary>
|
|
||||||
public static class TimerHelper
|
|
||||||
{
|
|
||||||
#region DLL-Imports
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
|
|
||||||
private static extern void TimeBeginPeriod(int t);
|
|
||||||
|
|
||||||
[DllImport("winmm.dll", EntryPoint = "timeEndPeriod")]
|
|
||||||
private static extern void TimeEndPeriod(int t);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
private static readonly object HIGH_RESOLUTION_TIMER_LOCK = new();
|
|
||||||
|
|
||||||
private static bool _areHighResolutionTimersEnabled = false;
|
|
||||||
|
|
||||||
private static bool _useHighResolutionTimers = true;
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets if High Resolution Timers should be used.
|
|
||||||
/// </summary>
|
|
||||||
public static bool UseHighResolutionTimers
|
|
||||||
{
|
|
||||||
get => _useHighResolutionTimers;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
lock (HIGH_RESOLUTION_TIMER_LOCK)
|
|
||||||
{
|
|
||||||
_useHighResolutionTimers = value;
|
|
||||||
CheckHighResolutionTimerUsage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReSharper disable once InconsistentNaming
|
|
||||||
private static readonly HashSet<HighResolutionTimerDisposable> _timerLeases = new();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Executes the provided action and blocks if needed until the the <see param="targetExecuteTime"/> has passed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">The action to execute.</param>
|
|
||||||
/// <param name="targetExecuteTime">The time in ms this method should block. default: 0</param>
|
|
||||||
/// <returns>The time in ms spent executing the <see param="action"/>.</returns>
|
|
||||||
public static double Execute(Action action, double targetExecuteTime = 0)
|
|
||||||
{
|
|
||||||
long preUpdateTicks = Stopwatch.GetTimestamp();
|
|
||||||
|
|
||||||
action();
|
|
||||||
|
|
||||||
double updateTime = GetElapsedTime(preUpdateTicks);
|
|
||||||
|
|
||||||
if (targetExecuteTime > 0)
|
|
||||||
{
|
|
||||||
int sleep = (int)(targetExecuteTime - updateTime);
|
|
||||||
if (sleep > 0)
|
|
||||||
Thread.Sleep(sleep);
|
|
||||||
}
|
|
||||||
|
|
||||||
return updateTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Calculates the elapsed time in ms from the provided timestamp until now.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="initialTimestamp">The initial timestamp to calculate the time from.</param>
|
|
||||||
/// <returns>The elapsed time in ms.</returns>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public static double GetElapsedTime(long initialTimestamp) => ((Stopwatch.GetTimestamp() - initialTimestamp) / (double)TimeSpan.TicksPerMillisecond);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Requests to use to use High Resolution Timers if enabled.
|
|
||||||
/// IMPORTANT: Always dispose the returned disposable if High Resolution Timers are no longer needed for the caller.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A disposable to remove the request.</returns>
|
|
||||||
public static IDisposable RequestHighResolutionTimer()
|
|
||||||
{
|
|
||||||
HighResolutionTimerDisposable timerLease = new();
|
|
||||||
lock (HIGH_RESOLUTION_TIMER_LOCK)
|
|
||||||
{
|
|
||||||
_timerLeases.Add(timerLease);
|
|
||||||
CheckHighResolutionTimerUsage();
|
|
||||||
}
|
|
||||||
|
|
||||||
return timerLease;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CheckHighResolutionTimerUsage()
|
|
||||||
{
|
|
||||||
if (UseHighResolutionTimers && (_timerLeases.Count > 0))
|
|
||||||
EnableHighResolutionTimers();
|
|
||||||
else
|
|
||||||
DisableHighResolutionTimers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void EnableHighResolutionTimers()
|
|
||||||
{
|
|
||||||
lock (HIGH_RESOLUTION_TIMER_LOCK)
|
|
||||||
{
|
|
||||||
if (_areHighResolutionTimersEnabled) return;
|
|
||||||
|
|
||||||
// DarthAffe 06.05.2022: Linux should use 1ms timers by default
|
|
||||||
if (OperatingSystem.IsWindows())
|
|
||||||
TimeBeginPeriod(1);
|
|
||||||
|
|
||||||
_areHighResolutionTimersEnabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void DisableHighResolutionTimers()
|
|
||||||
{
|
|
||||||
lock (HIGH_RESOLUTION_TIMER_LOCK)
|
|
||||||
{
|
|
||||||
if (!_areHighResolutionTimersEnabled) return;
|
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows())
|
|
||||||
TimeEndPeriod(1);
|
|
||||||
|
|
||||||
_areHighResolutionTimersEnabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Disposes all open High Resolution Timer Requests.
|
|
||||||
/// This should be called once when exiting the application to make sure nothing remains open and the application correctly unregisters itself on OS level.
|
|
||||||
/// Shouldn't be needed if everything is disposed, but better safe then sorry.
|
|
||||||
/// </summary>
|
|
||||||
public static void DisposeAllHighResolutionTimerRequests()
|
|
||||||
{
|
|
||||||
List<HighResolutionTimerDisposable> timerLeases = new(_timerLeases);
|
|
||||||
foreach (HighResolutionTimerDisposable timer in timerLeases)
|
|
||||||
timer.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private class HighResolutionTimerDisposable : IDisposable
|
|
||||||
{
|
|
||||||
#region Properties & Fields
|
|
||||||
|
|
||||||
private bool _isDisposed = false;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (_isDisposed) return;
|
|
||||||
|
|
||||||
_isDisposed = true;
|
|
||||||
|
|
||||||
lock (HIGH_RESOLUTION_TIMER_LOCK)
|
|
||||||
{
|
|
||||||
_timerLeases.Remove(this);
|
|
||||||
CheckHighResolutionTimerUsage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +1,6 @@
|
|||||||
// ReSharper disable MemberCanBePrivate.Global
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -141,10 +142,25 @@ public class DeviceUpdateTrigger : AbstractUpdateTrigger, IDeviceUpdateTrigger
|
|||||||
{
|
{
|
||||||
OnStartup();
|
OnStartup();
|
||||||
|
|
||||||
using (TimerHelper.RequestHighResolutionTimer())
|
|
||||||
while (!UpdateToken.IsCancellationRequested)
|
while (!UpdateToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
if (HasDataEvent.WaitOne(Timeout))
|
if (HasDataEvent.WaitOne(Timeout))
|
||||||
LastUpdateTime = TimerHelper.Execute(() => OnUpdate(), UpdateFrequency * 1000);
|
{
|
||||||
|
long preUpdateTicks = Stopwatch.GetTimestamp();
|
||||||
|
|
||||||
|
OnUpdate();
|
||||||
|
|
||||||
|
double lastUpdateTime = ((Stopwatch.GetTimestamp() - preUpdateTicks) / 10000.0);
|
||||||
|
LastUpdateTime = lastUpdateTime;
|
||||||
|
|
||||||
|
if (UpdateFrequency > 0)
|
||||||
|
{
|
||||||
|
int sleep = (int)((UpdateFrequency * 1000.0) - lastUpdateTime);
|
||||||
|
if (sleep > 0)
|
||||||
|
Thread.Sleep(sleep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
// ReSharper disable MemberCanBePrivate.Global
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -85,7 +86,11 @@ public sealed class ManualUpdateTrigger : AbstractUpdateTrigger
|
|||||||
while (!UpdateToken.IsCancellationRequested)
|
while (!UpdateToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
if (_mutex.WaitOne(100))
|
if (_mutex.WaitOne(100))
|
||||||
LastUpdateTime = TimerHelper.Execute(() => OnUpdate(_customUpdateData));
|
{
|
||||||
|
long preUpdateTicks = Stopwatch.GetTimestamp();
|
||||||
|
OnUpdate(_customUpdateData);
|
||||||
|
LastUpdateTime = ((Stopwatch.GetTimestamp() - preUpdateTicks) / 10000.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
// ReSharper disable MemberCanBePrivate.Global
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -129,10 +130,21 @@ public class TimerUpdateTrigger : AbstractUpdateTrigger
|
|||||||
{
|
{
|
||||||
OnStartup();
|
OnStartup();
|
||||||
|
|
||||||
using (TimerHelper.RequestHighResolutionTimer())
|
|
||||||
while (!UpdateToken.IsCancellationRequested)
|
while (!UpdateToken.IsCancellationRequested)
|
||||||
LastUpdateTime = TimerHelper.Execute(() => OnUpdate(_customUpdateData), UpdateFrequency * 1000);
|
{
|
||||||
|
long preUpdateTicks = Stopwatch.GetTimestamp();
|
||||||
|
|
||||||
|
OnUpdate(_customUpdateData);
|
||||||
|
|
||||||
|
if (UpdateFrequency > 0)
|
||||||
|
{
|
||||||
|
double lastUpdateTime = ((Stopwatch.GetTimestamp() - preUpdateTicks) / 10000.0);
|
||||||
|
LastUpdateTime = lastUpdateTime;
|
||||||
|
int sleep = (int)((UpdateFrequency * 1000.0) - lastUpdateTime);
|
||||||
|
if (sleep > 0)
|
||||||
|
Thread.Sleep(sleep);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@ -165,7 +165,6 @@ public class RazerDeviceProvider : AbstractRGBDeviceProvider
|
|||||||
{ 0x008D, RGBDeviceType.Mouse, "Naga Left Handed Edition", LedMappings.Mouse, RazerEndpointType.Mouse },
|
{ 0x008D, RGBDeviceType.Mouse, "Naga Left Handed Edition", LedMappings.Mouse, RazerEndpointType.Mouse },
|
||||||
{ 0x0091, RGBDeviceType.Mouse, "Viper 8khz", LedMappings.Mouse, RazerEndpointType.Mouse },
|
{ 0x0091, RGBDeviceType.Mouse, "Viper 8khz", LedMappings.Mouse, RazerEndpointType.Mouse },
|
||||||
{ 0x0096, RGBDeviceType.Mouse, "Naga X", LedMappings.Mouse, RazerEndpointType.Mouse },
|
{ 0x0096, RGBDeviceType.Mouse, "Naga X", LedMappings.Mouse, RazerEndpointType.Mouse },
|
||||||
{ 0x0099, RGBDeviceType.Mouse, "Basilisk v3", LedMappings.Mouse, RazerEndpointType.Mouse },
|
|
||||||
|
|
||||||
// Mousepads
|
// Mousepads
|
||||||
{ 0x0068, RGBDeviceType.Mousepad, "Firefly Hyperflux", LedMappings.Mousepad, RazerEndpointType.Mousepad },
|
{ 0x0068, RGBDeviceType.Mousepad, "Firefly Hyperflux", LedMappings.Mousepad, RazerEndpointType.Mousepad },
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user