diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj
index 057b9d6a7..6ee49f2d7 100644
--- a/Artemis/Artemis/Artemis.csproj
+++ b/Artemis/Artemis/Artemis.csproj
@@ -518,6 +518,8 @@
+
+
diff --git a/Artemis/Artemis/DeviceProviders/Corsair/CorsairKeyboard.cs b/Artemis/Artemis/DeviceProviders/Corsair/CorsairKeyboard.cs
index 331f02531..0dd0f2f32 100644
--- a/Artemis/Artemis/DeviceProviders/Corsair/CorsairKeyboard.cs
+++ b/Artemis/Artemis/DeviceProviders/Corsair/CorsairKeyboard.cs
@@ -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);
- }
-
- ///
- /// Enables the SDK and sets updatemode to manual as well as the color of the background to black.
- ///
- 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);
+ }
+
+ ///
+ /// Enables the SDK and sets updatemode to manual as well as the color of the background to black.
+ ///
+ 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;
- }
- }
-
- ///
- /// Properly resizes any size bitmap to the keyboard by creating a rectangle whose size is dependent on the bitmap
- /// size.
- ///
- ///
- 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;
+ }
+ }
+
+ ///
+ /// Properly resizes any size bitmap to the keyboard by creating a rectangle whose size is dependent on the bitmap
+ /// size.
+ ///
+ ///
+ 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));
+ }
+ }
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Managers/LuaManager.cs b/Artemis/Artemis/Managers/LuaManager.cs
index 6e8fc166c..3cf15a722 100644
--- a/Artemis/Artemis/Managers/LuaManager.cs
+++ b/Artemis/Artemis/Managers/LuaManager.cs
@@ -21,8 +21,8 @@ namespace Artemis.Managers
private readonly DeviceManager _deviceManager;
private readonly IKernel _kernel;
private readonly ILogger _logger;
- private List _luaModules;
private readonly Script _luaScript;
+ private List _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>();
- 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("");
}
+ }
+
+ ///
+ /// Safely call a function on the active script
+ ///
+ ///
+ ///
+ 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
+ ///
+ /// 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.
+ ///
+ ///
+ 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()
diff --git a/Artemis/Artemis/Profiles/Lua/Modules/LuaTimerModule.cs b/Artemis/Artemis/Profiles/Lua/Modules/LuaTimerModule.cs
new file mode 100644
index 000000000..1045d74fc
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Lua/Modules/LuaTimerModule.cs
@@ -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 _timers;
+
+ public LuaTimerModule(LuaManager luaManager) : base(luaManager)
+ {
+ _timers = new List();
+ }
+
+ 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();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Lua/Modules/Timer/LuaTimer.cs b/Artemis/Artemis/Profiles/Lua/Modules/Timer/LuaTimer.cs
new file mode 100644
index 000000000..fa4fded1f
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Lua/Modules/Timer/LuaTimer.cs
@@ -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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Resources/lua-placeholder.lua b/Artemis/Artemis/Resources/lua-placeholder.lua
index 87b7a962a..68a963307 100644
--- a/Artemis/Artemis/Resources/lua-placeholder.lua
+++ b/Artemis/Artemis/Resources/lua-placeholder.lua
@@ -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