1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Added LUA timer module

This commit is contained in:
SpoinkyNL 2016-12-27 12:58:02 +01:00
parent 094b7abfc4
commit b91ad6fcdd
6 changed files with 321 additions and 167 deletions

View File

@ -518,6 +518,8 @@
<Compile Include="Profiles\Lua\Modules\LuaLayerModule.cs" />
<Compile Include="Profiles\Lua\Modules\LuaMouseModule.cs" />
<Compile Include="Profiles\Lua\Modules\LuaProfileModule.cs" />
<Compile Include="Profiles\Lua\Modules\Timer\LuaTimer.cs" />
<Compile Include="Profiles\Lua\Modules\LuaTimerModule.cs" />
<Compile Include="Profiles\Lua\Wrappers\LuaDrawWrapper.cs" />
<Compile Include="Profiles\Lua\Wrappers\LuaLayerWrapper.cs" />
<Compile Include="Profiles\ProfileModel.cs" />

View File

@ -1,160 +1,160 @@
using System;
using System.Drawing;
using System.Linq;
using System.Windows;
using System.Windows.Forms;
using Artemis.DeviceProviders.Corsair.Utilities;
using Artemis.Properties;
using Artemis.Utilities;
using CUE.NET;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Generic.Enums;
using CUE.NET.Exceptions;
using CUE.NET.Helper;
using Ninject.Extensions.Logging;
using Point = System.Drawing.Point;
namespace Artemis.DeviceProviders.Corsair
{
public class CorsairKeyboard : KeyboardProvider
{
private CUE.NET.Devices.Keyboard.CorsairKeyboard _keyboard;
private ImageBrush _keyboardBrush;
public CorsairKeyboard(ILogger logger)
{
Logger = logger;
Name = "Corsair RGB Keyboard";
CantEnableText = "Couldn't connect to your Corsair keyboard.\n" +
"Please check your cables and/or drivers (could be outdated) and that Corsair Utility Engine is running.\n" +
"In CUE, make sure \"Enable SDK\" is checked under Global Settings.\n\n" +
"If needed, you can select a different keyboard in Artemis under settings.";
}
public ILogger Logger { get; set; }
public override bool CanEnable()
{
return CueSDK.IsSDKAvailable(CorsairDeviceType.Keyboard);
}
/// <summary>
/// Enables the SDK and sets updatemode to manual as well as the color of the background to black.
/// </summary>
public override void Enable()
{
if (!CueSDK.IsInitialized)
CueSDK.Initialize();
CueSDK.UpdateMode = UpdateMode.Manual;
_keyboard = CueSDK.KeyboardSDK;
switch (_keyboard.DeviceInfo.Model)
{
case "K95 RGB":
Height = 7;
Width = 25;
Slug = "corsair-k95-rgb";
PreviewSettings = new PreviewSettings(676, 190, new Thickness(0, -15, 0, 0), Resources.k95);
break;
case "K70 RGB":
case "K70 RGB RAPIDFIRE":
case "K70 LUX RGB":
Height = 7;
Width = 21;
Slug = "corsair-k70-rgb";
PreviewSettings = new PreviewSettings(676, 210, new Thickness(0, -25, 0, 0), Resources.k70);
break;
case "K65 RGB":
case "CGK65 RGB":
case "K65 LUX RGB":
case "K65 RGB RAPIDFIRE":
Height = 7;
Width = 18;
Slug = "corsair-k65-rgb";
PreviewSettings = new PreviewSettings(610, 240, new Thickness(0, -30, 0, 0), Resources.k65);
break;
case "STRAFE RGB":
Height = 7;
Width = 22;
Slug = "corsair-strafe-rgb";
PreviewSettings = new PreviewSettings(665, 215, new Thickness(0, -5, 0, 0), Resources.strafe);
break;
}
Logger.Debug("Corsair SDK reported device as: {0}", _keyboard.DeviceInfo.Model);
_keyboard.Brush = _keyboardBrush ?? (_keyboardBrush = new ImageBrush());
}
public override void Disable()
{
try
using System;
using System.Drawing;
using System.Linq;
using System.Windows;
using System.Windows.Forms;
using Artemis.DeviceProviders.Corsair.Utilities;
using Artemis.Properties;
using Artemis.Utilities;
using CUE.NET;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Generic.Enums;
using CUE.NET.Exceptions;
using CUE.NET.Helper;
using Ninject.Extensions.Logging;
using Point = System.Drawing.Point;
namespace Artemis.DeviceProviders.Corsair
{
public class CorsairKeyboard : KeyboardProvider
{
private CUE.NET.Devices.Keyboard.CorsairKeyboard _keyboard;
private ImageBrush _keyboardBrush;
public CorsairKeyboard(ILogger logger)
{
Logger = logger;
Name = "Corsair RGB Keyboard";
CantEnableText = "Couldn't connect to your Corsair keyboard.\n" +
"Please check your cables and/or drivers (could be outdated) and that Corsair Utility Engine is running.\n" +
"In CUE, make sure \"Enable SDK\" is checked under Global Settings.\n\n" +
"If needed, you can select a different keyboard in Artemis under settings.";
}
public ILogger Logger { get; set; }
public override bool CanEnable()
{
return CueSDK.IsSDKAvailable(CorsairDeviceType.Keyboard);
}
/// <summary>
/// Enables the SDK and sets updatemode to manual as well as the color of the background to black.
/// </summary>
public override void Enable()
{
if (!CueSDK.IsInitialized)
CueSDK.Initialize();
CueSDK.UpdateMode = UpdateMode.Manual;
_keyboard = CueSDK.KeyboardSDK;
switch (_keyboard.DeviceInfo.Model)
{
case "K95 RGB":
Height = 7;
Width = 25;
Slug = "corsair-k95-rgb";
PreviewSettings = new PreviewSettings(676, 190, new Thickness(0, -15, 0, 0), Resources.k95);
break;
case "K70 RGB":
case "K70 RGB RAPIDFIRE":
case "K70 LUX RGB":
Height = 7;
Width = 21;
Slug = "corsair-k70-rgb";
PreviewSettings = new PreviewSettings(676, 210, new Thickness(0, -25, 0, 0), Resources.k70);
break;
case "K65 RGB":
case "CGK65 RGB":
case "K65 LUX RGB":
case "K65 RGB RAPIDFIRE":
Height = 7;
Width = 18;
Slug = "corsair-k65-rgb";
PreviewSettings = new PreviewSettings(610, 240, new Thickness(0, -30, 0, 0), Resources.k65);
break;
case "STRAFE RGB":
Height = 7;
Width = 22;
Slug = "corsair-strafe-rgb";
PreviewSettings = new PreviewSettings(665, 215, new Thickness(0, -5, 0, 0), Resources.strafe);
break;
}
Logger.Debug("Corsair SDK reported device as: {0}", _keyboard.DeviceInfo.Model);
_keyboard.Brush = _keyboardBrush ?? (_keyboardBrush = new ImageBrush());
}
public override void Disable()
{
try
{
if (CueSDK.IsInitialized)
CueSDK.Reinitialize();
}
catch (WrapperException e)
{
// This occurs when releasing the SDK after sleep, ignore it
if (e.Message != "The previously loaded Keyboard got disconnected.")
throw;
}
}
/// <summary>
/// Properly resizes any size bitmap to the keyboard by creating a rectangle whose size is dependent on the bitmap
/// size.
/// </summary>
/// <param name="bitmap"></param>
public override void DrawBitmap(Bitmap bitmap)
{
using (var image = ImageUtilities.ResizeImage(bitmap, Width, Height))
{
// For STRAFE, stretch the image on row 2.
if (_keyboard.DeviceInfo.Model == "STRAFE RGB")
{
using (var strafeBitmap = new Bitmap(22, 8))
{
using (var g = Graphics.FromImage(strafeBitmap))
{
g.DrawImage(image, new Point(0, 0));
g.DrawImage(image, new Rectangle(0, 3, 22, 7), new Rectangle(0, 2, 22, 7),
GraphicsUnit.Pixel);
_keyboardBrush.Image = strafeBitmap;
_keyboard.Update();
}
}
}
else
{
_keyboardBrush.Image = image;
_keyboard.Update();
}
}
}
public override KeyMatch? GetKeyPosition(Keys keyCode)
{
var widthMultiplier = Width/_keyboard.Brush.RenderedRectangle.Width;
var heightMultiplier = Height/_keyboard.Brush.RenderedRectangle.Height;
CorsairLed cueLed = null;
try
{
cueLed = _keyboard.Leds.FirstOrDefault(k => k.Id.ToString() == keyCode.ToString()) ??
_keyboard.Leds.FirstOrDefault(k => k.Id == KeyMap.FormsKeys[keyCode]);
}
catch (Exception)
{
// ignored
}
if (cueLed == null)
return null;
var center = cueLed.LedRectangle.GetCenter();
return new KeyMatch(keyCode, (int) (center.X*widthMultiplier), (int) (center.Y*heightMultiplier));
}
}
CueSDK.Reinitialize();
}
catch (WrapperException e)
{
// This occurs when releasing the SDK after sleep, ignore it
if (e.Message != "The previously loaded Keyboard got disconnected.")
throw;
}
}
/// <summary>
/// Properly resizes any size bitmap to the keyboard by creating a rectangle whose size is dependent on the bitmap
/// size.
/// </summary>
/// <param name="bitmap"></param>
public override void DrawBitmap(Bitmap bitmap)
{
using (var image = ImageUtilities.ResizeImage(bitmap, Width, Height))
{
// For STRAFE, stretch the image on row 2.
if (_keyboard.DeviceInfo.Model == "STRAFE RGB")
{
using (var strafeBitmap = new Bitmap(22, 8))
{
using (var g = Graphics.FromImage(strafeBitmap))
{
g.DrawImage(image, new Point(0, 0));
g.DrawImage(image, new Rectangle(0, 3, 22, 7), new Rectangle(0, 2, 22, 7),
GraphicsUnit.Pixel);
_keyboardBrush.Image = strafeBitmap;
_keyboard.Update();
}
}
}
else
{
_keyboardBrush.Image = image;
_keyboard.Update();
}
}
}
public override KeyMatch? GetKeyPosition(Keys keyCode)
{
var widthMultiplier = Width/_keyboard.Brush.RenderedRectangle.Width;
var heightMultiplier = Height/_keyboard.Brush.RenderedRectangle.Height;
CorsairLed cueLed = null;
try
{
cueLed = _keyboard.Leds.FirstOrDefault(k => k.Id.ToString() == keyCode.ToString()) ??
_keyboard.Leds.FirstOrDefault(k => k.Id == KeyMap.FormsKeys[keyCode]);
}
catch (Exception)
{
// ignored
}
if (cueLed == null)
return null;
var center = cueLed.LedRectangle.GetCenter();
return new KeyMatch(keyCode, (int) (center.X*widthMultiplier), (int) (center.Y*heightMultiplier));
}
}
}

View File

@ -21,8 +21,8 @@ namespace Artemis.Managers
private readonly DeviceManager _deviceManager;
private readonly IKernel _kernel;
private readonly ILogger _logger;
private List<LuaModule> _luaModules;
private readonly Script _luaScript;
private List<LuaModule> _luaModules;
private FileSystemWatcher _watcher;
public LuaManager(IKernel kernel, ILogger logger, DeviceManager deviceManager)
@ -52,17 +52,15 @@ namespace Artemis.Managers
// Get new instances of all modules
_luaModules = _kernel.Get<List<LuaModule>>();
ProfileModule = (LuaProfileModule)_luaModules.First(m => m.ModuleName == "Profile");
EventsModule = (LuaEventsModule)_luaModules.First(m => m.ModuleName == "Events");
ProfileModule = (LuaProfileModule) _luaModules.First(m => m.ModuleName == "Profile");
EventsModule = (LuaEventsModule) _luaModules.First(m => m.ModuleName == "Events");
// Setup new state
_luaScript.Options.DebugPrint = LuaPrint;
// Insert each module into the script's globals
foreach (var luaModule in _luaModules)
{
_luaScript.Globals[luaModule.ModuleName] = luaModule;
}
// If there is no LUA script, don't bother executing the string
if (ProfileModel.LuaScript.IsNullOrEmpty())
@ -74,6 +72,7 @@ namespace Artemis.Managers
{
lock (_luaScript)
{
UpdateLuaSource(ProfileModel);
_luaScript.DoString(ProfileModel.LuaScript);
}
}
@ -116,7 +115,6 @@ namespace Artemis.Managers
}
if (EventsModule != null)
{
lock (EventsModule.InvokeLock)
{
lock (_luaScript)
@ -124,13 +122,51 @@ namespace Artemis.Managers
_luaScript.DoString("");
}
}
}
else
{
lock (_luaScript)
{
_luaScript.DoString("");
}
}
/// <summary>
/// Safely call a function on the active script
/// </summary>
/// <param name="function"></param>
/// <param name="args"></param>
public void Call(DynValue function, DynValue[] args = null)
{
if (EventsModule == null)
return;
try
{
lock (EventsModule.InvokeLock)
{
lock (_luaScript)
{
if (args != null)
_luaScript.Call(function, args);
else
_luaScript.Call(function);
}
}
}
catch (ArgumentException e)
{
_logger.Error("[{0}-LUA]: Error: {1}", ProfileModel.Name, e.Message);
}
catch (InternalErrorException e)
{
_logger.Error("[{0}-LUA]: Error: {1}", ProfileModel.Name, e.DecoratedMessage);
}
catch (SyntaxErrorException e)
{
_logger.Error("[{0}-LUA]: Error: {1}", ProfileModel.Name, e.DecoratedMessage);
}
catch (ScriptRuntimeException e)
{
_logger.Error("[{0}-LUA]: Error: {1}", ProfileModel.Name, e.DecoratedMessage);
}
}
@ -143,6 +179,20 @@ namespace Artemis.Managers
#endregion
/// <summary>
/// Updates a profile's LUA script to be compatible with the latest version of Artemis, if needed.
/// This function obviously won't fix completely custom profiles but it'll fix copied LUA.
/// </summary>
/// <param name="profileModel"></param>
private static void UpdateLuaSource(ProfileModel profileModel)
{
// 1.7.1.0 - Events cleanup
profileModel.LuaScript = profileModel.LuaScript.Replace("function updateHandler(profile, eventArgs)",
"function updateHandler(eventArgs)");
profileModel.LuaScript = profileModel.LuaScript.Replace("function drawHandler(profile, eventArgs)",
"function drawHandler(eventArgs)");
}
#region Editor
public void OpenEditor()

View File

@ -0,0 +1,43 @@
using System.Collections.Generic;
using Artemis.Managers;
using Artemis.Profiles.Lua.Modules.Timer;
using MoonSharp.Interpreter;
namespace Artemis.Profiles.Lua.Modules
{
[MoonSharpUserData]
public class LuaTimerModule : LuaModule
{
private readonly List<LuaTimer> _timers;
public LuaTimerModule(LuaManager luaManager) : base(luaManager)
{
_timers = new List<LuaTimer>();
}
public override string ModuleName => "Timer";
public override void Dispose()
{
foreach (var luaTimer in _timers)
luaTimer.Dispose();
_timers.Clear();
}
public LuaTimer SetTimer(DynValue function, int interval, int timesToExecute, params DynValue[] args)
{
var luaTimer = new LuaTimer(this, function, interval, timesToExecute, args);
_timers.Add(luaTimer);
return luaTimer;
}
public void RemoveTimer(LuaTimer luaTimer)
{
if (_timers.Contains(luaTimer))
_timers.Remove(luaTimer);
luaTimer.Dispose();
}
}
}

View File

@ -0,0 +1,59 @@
using System;
using System.Timers;
using MoonSharp.Interpreter;
namespace Artemis.Profiles.Lua.Modules.Timer
{
[MoonSharpUserData]
public class LuaTimer : IDisposable
{
private readonly DynValue[] _args;
private readonly DynValue _function;
private readonly System.Timers.Timer _timer;
private readonly LuaTimerModule _timerModule;
private readonly int _timesToExecute;
private int _timesExecuted;
public LuaTimer(LuaTimerModule timerModule, DynValue function, int interval, int timesToExecute,
params DynValue[] args)
{
_timerModule = timerModule;
_function = function;
_timesToExecute = timesToExecute;
_args = args;
_timesExecuted = 0;
// Setup timer
_timer = new System.Timers.Timer(interval);
_timer.Elapsed += TimerOnElapsed;
_timer.Start();
}
public void Dispose()
{
_timer?.Stop();
_timer?.Dispose();
}
public void Stop()
{
_timerModule.RemoveTimer(this);
}
private void TimerOnElapsed(object sender, ElapsedEventArgs e)
{
if (_args != null)
_timerModule.LuaManager.Call(_function, _args);
else
_timerModule.LuaManager.Call(_function);
// Don't keep track of execution if times is set to 0 (infinite)
if (_timesToExecute <= 0)
return;
_timesExecuted++;
if (_timesExecuted >= _timesToExecute)
_timerModule.RemoveTimer(this);
}
}
}

View File

@ -14,7 +14,7 @@
-- changes are applied to the profile and the script is restarted.
-- This event is raised after every profile update, before drawing.
function updateHandler(profile, eventArgs)
function updateHandler(eventArgs)
-- In this example we only want to update once per frame when the keyboard is
-- updated. If you don't do this the updateHandler will trigger on every
-- device's update.
@ -26,7 +26,7 @@ function updateHandler(profile, eventArgs)
end
-- This event is raised after every profile draw, after updating.
function drawHandler(profile, eventArgs)
function drawHandler(eventArgs)
-- In this example we only want to draw to the keyboard. Each device has it's
-- own drawing event
if eventArgs.DeviceType != "keyboard" then