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

Disabled The Division module (broken)

Disabled LightFX module (unfinished)
Added keybind event triggers
Fixed condition dropdown width
Adjusted layer properties window height
Improved GTA V DLL placement
This commit is contained in:
SpoinkyNL 2017-03-18 23:36:51 +01:00
parent 87a30b8936
commit ec490155fd
23 changed files with 475 additions and 437 deletions

View File

@ -1,7 +1,7 @@
using System;
using System.Windows;
using System.Windows.Threading;
using Artemis.Utilities.Keyboard;
using Artemis.Utilities;
using NLog;
using WpfExceptionViewer;
@ -28,7 +28,7 @@ namespace Artemis
private void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
// Get rid of the keyboard hook in case of a crash, otherwise input freezes up system wide until Artemis is gone
KeyboardHook.Stop();
InputHook.Stop();
if (DoHandle)
{

View File

@ -663,7 +663,7 @@
<Compile Include="Utilities\GeneralHelpers.cs" />
<Compile Include="Utilities\GifImage.cs" />
<Compile Include="Utilities\ImageUtilities.cs" />
<Compile Include="Utilities\Keyboard\KeyboardHook.cs" />
<Compile Include="Utilities\InputHook.cs" />
<Compile Include="Utilities\Logging.cs" />
<Compile Include="Utilities\DataReaders\PipeServer.cs" />
<Compile Include="Utilities\Markdown\Markdown.cs" />

View File

@ -12,7 +12,6 @@ using Artemis.Settings;
using Artemis.Utilities;
using Artemis.Utilities.Converters;
using Artemis.Utilities.DataReaders;
using Artemis.Utilities.Keyboard;
using Artemis.ViewModels;
using Caliburn.Micro;
using Newtonsoft.Json;
@ -35,7 +34,7 @@ namespace Artemis
Initialize();
BindSpecialValues();
KeyboardHook.Start();
InputHook.Start();
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
}
@ -43,7 +42,7 @@ namespace Artemis
private void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
{
// Get rid of the keyboard hook in case of a crash, otherwise input freezes up system wide until Artemis is gone
KeyboardHook.Stop();
InputHook.Stop();
}
private void BindSpecialValues()

View File

@ -21,8 +21,7 @@ namespace Artemis.DAL
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public static readonly string ProfileFolder =
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\profiles";
public static readonly string ProfileFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\profiles";
private static bool _installedDefaults;

View File

@ -10,6 +10,9 @@ namespace Artemis.DeviceProviders.Logitech
{
public override bool CanEnable()
{
// Just to be sure, restore the Logitech DLL registry key
DllManager.RestoreLogitechDll();
// Check to see if VC++ 2012 x64 is installed.
if (Registry.LocalMachine.OpenSubKey(
@"SOFTWARE\Classes\Installer\Dependencies\{ca67548a-5ebe-413a-b50c-4b9ceb6d66c6}") == null)
@ -22,17 +25,6 @@ namespace Artemis.DeviceProviders.Logitech
return false;
}
if (DllManager.DllPlaced())
{
CantEnableText =
"Artemis couldn't enable your Logitech keyboard, because the required files are not in place.\n\n" +
"This happens when you run The Division or GTA and shut down Artemis before shutting down The Division\n" +
"Artemis tries to fix this automatically on startup but because the files may have been in use it failed.\n\n" +
"To try again, restart Artemis or check out the FAQ.";
return false;
}
int majorNum = 0, minorNum = 0, buildNum = 0;
LogitechGSDK.LogiLedInit();
@ -73,4 +65,4 @@ namespace Artemis.DeviceProviders.Logitech
LogitechGSDK.LogiLedSetLightingFromBitmap(OrionUtilities.BitmapToByteArray(bitmap));
}
}
}
}

View File

@ -1,10 +1,9 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Input;
using Artemis.Models;
using Artemis.Utilities.Keyboard;
using Artemis.Utilities;
using MahApps.Metro.Controls;
using KeyEventArgs = System.Windows.Forms.KeyEventArgs;
using MouseEventArgs = System.Windows.Forms.MouseEventArgs;
@ -17,12 +16,12 @@ namespace Artemis.Managers
static KeybindManager()
{
KeyboardHook.KeyDownCallback += args => ProcessKey(args, PressType.Down);
KeyboardHook.KeyUpCallback += args => ProcessKey(args, PressType.Up);
KeyboardHook.MouseDownCallback += args => ProcessMouse(args, PressType.Down);
KeyboardHook.MouseUpCallback += args => ProcessMouse(args, PressType.Up);
InputHook.KeyDownCallback += args => ProcessKey(args, PressType.Down);
InputHook.KeyUpCallback += args => ProcessKey(args, PressType.Up);
InputHook.MouseDownCallback += args => ProcessMouse(args, PressType.Down);
InputHook.MouseUpCallback += args => ProcessMouse(args, PressType.Up);
}
private static void ProcessKey(KeyEventArgs keyEventArgs, PressType pressType)
{
// Don't trigger if the key itself is a modifier
@ -38,7 +37,7 @@ namespace Artemis.Managers
var hotKey = new HotKey(KeyInterop.KeyFromVirtualKey(keyEventArgs.KeyValue), modifiers);
foreach (var keybindModel in KeybindModels)
keybindModel.InvokeIfMatched(hotKey, pressType);
keybindModel.InvokeIfMatched(hotKey, pressType);
}
private static void ProcessMouse(MouseEventArgs mouseEventArgs, PressType pressType)
@ -79,15 +78,19 @@ namespace Artemis.Managers
if (alt)
modifiers = ModifierKeys.Alt;
if (control)
{
if (modifiers == ModifierKeys.None)
modifiers = ModifierKeys.Control;
else
modifiers |= ModifierKeys.Control;
}
if (shift)
{
if (modifiers == ModifierKeys.None)
modifiers = ModifierKeys.Shift;
else
modifiers |= ModifierKeys.Shift;
}
return modifiers;
}

View File

@ -1,4 +1,5 @@
using System.Threading;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media;
using Artemis.DAL;
@ -13,8 +14,7 @@ namespace Artemis.Modules.Games.GtaV
{
private readonly PipeServer _pipeServer;
public GtaVModel(DeviceManager deviceManager, LuaManager luaManager, PipeServer pipeServer)
: base(deviceManager, luaManager)
public GtaVModel(DeviceManager deviceManager, LuaManager luaManager, PipeServer pipeServer) : base(deviceManager, luaManager)
{
_pipeServer = pipeServer;
@ -29,6 +29,7 @@ namespace Artemis.Modules.Games.GtaV
public override void Enable()
{
var process = System.Diagnostics.Process.GetProcessesByName("GTA5").First();
DllManager.PlaceLogitechDll();
_pipeServer.PipeMessage += PipeServerOnPipeMessage;
base.Enable();

View File

@ -1,55 +1,55 @@
using System;
using System.IO;
using Artemis.DAL;
using Artemis.Managers;
using Artemis.Modules.Abstract;
using Artemis.Utilities.DataReaders;
using Newtonsoft.Json;
namespace Artemis.Modules.Games.LightFx
{
public class LightFxModel : ModuleModel
{
public LightFxModel(DeviceManager deviceManager, LuaManager luaManager, PipeServer pipeServer)
: base(deviceManager, luaManager)
{
Settings = SettingsProvider.Load<LightFxSettings>();
DataModel = new LightFxDataModel();
ProcessNames.Add("LoL");
// This model can enable itself by changing its process name to the currently running Light FX game.
pipeServer.PipeMessage += PipeServerOnPipeMessage;
}
public override string Name => "LightFX";
public override bool IsOverlay => false;
public override bool IsBoundToProcess => true;
private void PipeServerOnPipeMessage(string msg)
{
// Ensure it's Light FX JSON
if (!msg.Contains("lightFxState"))
return;
// Deserialize and data
try
{
JsonConvert.PopulateObject(msg, DataModel);
}
catch (Exception ex)
{
Logger?.Error(ex, "Failed to deserialize LightFX JSON");
throw;
}
// Setup process name
var processName = Path.GetFileNameWithoutExtension(((LightFxDataModel) DataModel).LightFxState.game);
if (!ProcessNames.Contains(processName))
ProcessNames.Add(processName);
}
public override void Update()
{
}
}
}
//using System;
//using System.IO;
//using Artemis.DAL;
//using Artemis.Managers;
//using Artemis.Modules.Abstract;
//using Artemis.Utilities.DataReaders;
//using Newtonsoft.Json;
//
//namespace Artemis.Modules.Games.LightFx
//{
// public class LightFxModel : ModuleModel
// {
// public LightFxModel(DeviceManager deviceManager, LuaManager luaManager, PipeServer pipeServer)
// : base(deviceManager, luaManager)
// {
// Settings = SettingsProvider.Load<LightFxSettings>();
// DataModel = new LightFxDataModel();
// ProcessNames.Add("LoL");
//
// // This model can enable itself by changing its process name to the currently running Light FX game.
// pipeServer.PipeMessage += PipeServerOnPipeMessage;
// }
//
// public override string Name => "LightFX";
// public override bool IsOverlay => false;
// public override bool IsBoundToProcess => true;
//
// private void PipeServerOnPipeMessage(string msg)
// {
// // Ensure it's Light FX JSON
// if (!msg.Contains("lightFxState"))
// return;
//
// // Deserialize and data
// try
// {
// JsonConvert.PopulateObject(msg, DataModel);
// }
// catch (Exception ex)
// {
// Logger?.Error(ex, "Failed to deserialize LightFX JSON");
// throw;
// }
//
// // Setup process name
// var processName = Path.GetFileNameWithoutExtension(((LightFxDataModel) DataModel).LightFxState.game);
// if (!ProcessNames.Contains(processName))
// ProcessNames.Add(processName);
// }
//
// public override void Update()
// {
// }
// }
//}

View File

@ -1,17 +1,17 @@
using Artemis.Managers;
using Artemis.Modules.Abstract;
using Ninject;
namespace Artemis.Modules.Games.LightFx
{
public sealed class LightFxViewModel : ModuleViewModel
{
public LightFxViewModel(MainManager mainManager, [Named(nameof(LightFxModel))] ModuleModel moduleModel,
IKernel kernel) : base(mainManager, moduleModel, kernel)
{
DisplayName = "Light FX";
}
public override bool UsesProfileEditor => true;
}
}
//using Artemis.Managers;
//using Artemis.Modules.Abstract;
//using Ninject;
//
//namespace Artemis.Modules.Games.LightFx
//{
// public sealed class LightFxViewModel : ModuleViewModel
// {
// public LightFxViewModel(MainManager mainManager, [Named(nameof(LightFxModel))] ModuleModel moduleModel,
// IKernel kernel) : base(mainManager, moduleModel, kernel)
// {
// DisplayName = "Light FX";
// }
//
// public override bool UsesProfileEditor => true;
// }
//}

View File

@ -1,138 +1,143 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Artemis.DAL;
using Artemis.Managers;
using Artemis.Modules.Abstract;
using Artemis.Utilities;
using Artemis.Utilities.DataReaders;
namespace Artemis.Modules.Games.TheDivision
{
public class TheDivisionModel : ModuleModel
{
private readonly PipeServer _pipeServer;
private StickyValue<bool> _stickyAmmo;
private StickyValue<bool> _stickyHp;
public TheDivisionModel(DeviceManager deviceManager, LuaManager luaManager, PipeServer pipeServer)
: base(deviceManager, luaManager)
{
_pipeServer = pipeServer;
Settings = SettingsProvider.Load<TheDivisionSettings>();
DataModel = new TheDivisionDataModel();
ProcessNames.Add("TheDivision");
}
public override string Name => "TheDivision";
public override bool IsOverlay => false;
public override bool IsBoundToProcess => true;
public override void Dispose()
{
base.Dispose();
// Delay restoring the DLL to allow The Division to release it
Task.Factory.StartNew(() =>
{
Thread.Sleep(2000);
DllManager.RestoreLogitechDll();
});
_stickyAmmo?.Dispose();
_stickyHp?.Dispose();
_pipeServer.PipeMessage -= PipeServerOnPipeMessage;
}
public override void Enable()
{
_stickyAmmo = new StickyValue<bool>(200);
_stickyHp = new StickyValue<bool>(200);
DllManager.PlaceLogitechDll();
_pipeServer.PipeMessage += PipeServerOnPipeMessage;
base.Enable();
}
private void PipeServerOnPipeMessage(string reply)
{
if (!IsInitialized)
return;
// Convert the given string to a list of ints
var stringParts = reply.Split(' ');
if (stringParts[0] != "1")
return;
// Parse into a list of ints and interpertrate
var parts = new int[stringParts.Length];
for (var i = 0; i < stringParts.Length; i++)
parts[i] = int.Parse(stringParts[i]);
InterpertrateDivisionKey(parts);
}
// Parses Division key data to game data
private void InterpertrateDivisionKey(IReadOnlyList<int> parts)
{
var gameDataModel = (TheDivisionDataModel) DataModel;
var keyCode = parts[1];
var rPer = parts[2];
var gPer = parts[3];
var bPer = parts[4];
// F1 to F4 indicate the player and his party. Blinks red on damage taken
if (keyCode >= 59 && keyCode <= 62)
{
var playerId = keyCode - 58;
PlayerState newState;
if (gPer > 10)
newState = PlayerState.Online;
else if (rPer > 10)
newState = PlayerState.Hit;
else
newState = PlayerState.Offline;
if (playerId == 1)
gameDataModel.LowHp = newState == PlayerState.Hit;
else if (playerId == 2)
gameDataModel.PartyMember1 = newState;
else if (playerId == 3)
gameDataModel.PartyMember2 = newState;
else if (playerId == 4)
gameDataModel.PartyMember3 = newState;
}
// R blinks white when low on ammo
else if (keyCode == 19)
{
_stickyAmmo.Value = rPer == 100 && gPer > 1 && bPer > 1;
gameDataModel.LowAmmo = _stickyAmmo.Value;
}
// G turns white when holding a grenade, turns off when out of grenades
else if (keyCode == 34)
{
if (rPer == 100 && gPer < 10 && bPer < 10)
gameDataModel.GrenadeState = GrenadeState.HasGrenade;
else if (rPer == 100 && gPer > 10 && bPer > 10)
gameDataModel.GrenadeState = GrenadeState.GrenadeEquipped;
else
gameDataModel.GrenadeState = GrenadeState.HasNoGrenade;
}
// V blinks on low HP
else if (keyCode == 47)
{
_stickyHp.Value = rPer == 100 && gPer > 1 && bPer > 1;
gameDataModel.LowHp = _stickyHp.Value;
}
}
public override void Update()
{
// DataModel updating is done whenever a pipe message is received
}
}
}
//using System.Collections.Generic;
//using System.Linq;
//using System.Threading;
//using System.Threading.Tasks;
//using Artemis.DAL;
//using Artemis.DeviceProviders.Logitech.Utilities;
//using Artemis.Managers;
//using Artemis.Modules.Abstract;
//using Artemis.Utilities;
//using Artemis.Utilities.DataReaders;
//
//namespace Artemis.Modules.Games.TheDivision
//{
// public class TheDivisionModel : ModuleModel
// {
// private readonly PipeServer _pipeServer;
// private StickyValue<bool> _stickyAmmo;
// private StickyValue<bool> _stickyHp;
//
// public TheDivisionModel(DeviceManager deviceManager, LuaManager luaManager, PipeServer pipeServer)
// : base(deviceManager, luaManager)
// {
// _pipeServer = pipeServer;
//
// Settings = SettingsProvider.Load<TheDivisionSettings>();
// DataModel = new TheDivisionDataModel();
// ProcessNames.Add("TheDivision");
// }
//
// public override string Name => "TheDivision";
// public override bool IsOverlay => false;
// public override bool IsBoundToProcess => true;
//
// public override void Dispose()
// {
// base.Dispose();
//
// // Delay restoring the DLL to allow The Division to release it
// Task.Factory.StartNew(() =>
// {
// Thread.Sleep(2000);
// DllManager.RestoreLogitechDll();
// });
//
// _stickyAmmo?.Dispose();
// _stickyHp?.Dispose();
// _pipeServer.PipeMessage -= PipeServerOnPipeMessage;
// }
//
// public override void Enable()
// {
// _stickyAmmo = new StickyValue<bool>(200);
// _stickyHp = new StickyValue<bool>(200);
//
// var process = System.Diagnostics.Process.GetProcessesByName("TheDivision").First();
// DllManager.PlaceLogitechDll();
//
// _pipeServer.PipeMessage += PipeServerOnPipeMessage;
//
// base.Enable();
// }
//
// private void PipeServerOnPipeMessage(string reply)
// {
// if (!IsInitialized)
// return;
//
// // Convert the given string to a list of ints
// var stringParts = reply.Split(' ');
// if (stringParts[0] != "1")
// return;
//
// // Parse into a list of ints and interpertrate
// var parts = new int[stringParts.Length];
// for (var i = 0; i < stringParts.Length; i++)
// parts[i] = int.Parse(stringParts[i]);
//
// InterpertrateDivisionKey(parts);
// }
//
// // Parses Division key data to game data
// private void InterpertrateDivisionKey(IReadOnlyList<int> parts)
// {
// var gameDataModel = (TheDivisionDataModel) DataModel;
// var keyCode = parts[1];
// var rPer = parts[2];
// var gPer = parts[3];
// var bPer = parts[4];
//
// var keyEnum = (KeyboardNames) keyCode;
//
// // F1 to F4 indicate the player and his party. Blinks red on damage taken
// if (keyCode >= 59 && keyCode <= 62)
// {
// var playerId = keyCode - 58;
//
// PlayerState newState;
// if (gPer > 10)
// newState = PlayerState.Online;
// else if (rPer > 10)
// newState = PlayerState.Hit;
// else
// newState = PlayerState.Offline;
//
// if (playerId == 1)
// gameDataModel.LowHp = newState == PlayerState.Hit;
// else if (playerId == 2)
// gameDataModel.PartyMember1 = newState;
// else if (playerId == 3)
// gameDataModel.PartyMember2 = newState;
// else if (playerId == 4)
// gameDataModel.PartyMember3 = newState;
// }
// // R blinks white when low on ammo
// else if (keyCode == 19)
// {
// _stickyAmmo.Value = rPer == 100 && gPer > 1 && bPer > 1;
// gameDataModel.LowAmmo = _stickyAmmo.Value;
// }
// // G turns white when holding a grenade, turns off when out of grenades
// else if (keyCode == 34)
// {
// if (rPer == 100 && gPer < 10 && bPer < 10)
// gameDataModel.GrenadeState = GrenadeState.HasGrenade;
// else if (rPer == 100 && gPer > 10 && bPer > 10)
// gameDataModel.GrenadeState = GrenadeState.GrenadeEquipped;
// else
// gameDataModel.GrenadeState = GrenadeState.HasNoGrenade;
// }
// // V blinks on low HP
// else if (keyCode == 47)
// {
// _stickyHp.Value = rPer == 100 && gPer > 1 && bPer > 1;
// gameDataModel.LowHp = _stickyHp.Value;
// }
// }
//
// public override void Update()
// {
// // DataModel updating is done whenever a pipe message is received
// }
// }
//}

View File

@ -1,17 +1,17 @@
using Artemis.Managers;
using Artemis.Modules.Abstract;
using Ninject;
namespace Artemis.Modules.Games.TheDivision
{
public sealed class TheDivisionViewModel : ModuleViewModel
{
public TheDivisionViewModel(MainManager mainManager, [Named(nameof(TheDivisionModel))] ModuleModel moduleModel,
IKernel kernel) : base(mainManager, moduleModel, kernel)
{
DisplayName = "The Division";
}
public override bool UsesProfileEditor => true;
}
}
//using Artemis.Managers;
//using Artemis.Modules.Abstract;
//using Ninject;
//
//namespace Artemis.Modules.Games.TheDivision
//{
// public sealed class TheDivisionViewModel : ModuleViewModel
// {
// public TheDivisionViewModel(MainManager mainManager, [Named(nameof(TheDivisionModel))] ModuleModel moduleModel,
// IKernel kernel) : base(mainManager, moduleModel, kernel)
// {
// DisplayName = "The Division";
// }
//
// public override bool UsesProfileEditor => true;
// }
//}

View File

@ -2,34 +2,48 @@
using System.Windows.Media;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
using Betwixt;
namespace Artemis.Profiles.Layers.Animations
{
public class PulseAnimation : ILayerAnimation
{
private bool _increase = true;
private Tweener<float> _opacityTweener = new Tweener<float>(0, 1000, 1000, Ease.Quad.InOut, LerpFuncFloat);
public string Name => "Pulse";
public void Update(LayerModel layerModel, bool updateAnimations)
{
// TODO: Generic implementation
// Reset animation progress if layer wasn't drawn for 100ms
if ((new TimeSpan(0, 0, 0, 0, 100) < DateTime.Now - layerModel.LastRender) && updateAnimations)
layerModel.AnimationProgress = 0;
if (new TimeSpan(0, 0, 0, 0, 100) < DateTime.Now - layerModel.LastRender && updateAnimations || MustExpire(layerModel))
{
_opacityTweener = new Tweener<float>(0, 1000, 1000, Ease.Quad.InOut, LerpFuncFloat);
_increase = true;
}
var progress = layerModel.AnimationProgress;
// Update animation progress
if (!updateAnimations)
return;
if (MustExpire(layerModel))
progress = 0;
progress = progress + layerModel.Properties.AnimationSpeed/2;
if (!_opacityTweener.Running && _increase)
{
_opacityTweener = new Tweener<float>(1000, 0, 1000, Ease.Quad.InOut, LerpFuncFloat);
_increase = false;
}
// If not previewing, store the animation progress in the actual model for the next frame
if (updateAnimations)
layerModel.AnimationProgress = progress;
_opacityTweener.Update(40);
if (_increase)
layerModel.AnimationProgress = _opacityTweener.Value / 1000;
else
layerModel.AnimationProgress = 1 + (1 - _opacityTweener.Value / 1000);
}
public void Draw(LayerModel layerModel, DrawingContext c, int drawScale)
{
if (layerModel.Brush == null)
if (layerModel.Brush == null || _opacityTweener == null)
return;
// Set up variables for this frame
@ -41,7 +55,7 @@ namespace Artemis.Profiles.Layers.Animations
// Can't meddle with the original brush because it's frozen.
var brush = layerModel.Brush.Clone();
brush.Opacity = (Math.Sin(layerModel.AnimationProgress*Math.PI) + 1)*(layerModel.Opacity/2);
brush.Opacity = _opacityTweener.Value / 1000;
layerModel.Brush = brush;
c.PushClip(new RectangleGeometry(clip));
@ -49,6 +63,11 @@ namespace Artemis.Profiles.Layers.Animations
c.Pop();
}
public bool MustExpire(LayerModel layer) => layer.AnimationProgress > 2;
public bool MustExpire(LayerModel layer) => layer.AnimationProgress >= 2;
private static float LerpFuncFloat(float start, float end, float percent)
{
return start + (end - start) * percent;
}
}
}
}

View File

@ -12,6 +12,15 @@ namespace Artemis.Profiles.Layers.Conditions
lock (layerModel.Properties.Conditions)
{
var checkConditions = layerModel.Properties.Conditions.Where(c => c.Field != null).ToList();
// Don't trigger constantly when there are no conditions
if (!checkConditions.Any())
{
layerModel.EventProperties.Update(layerModel, false);
return layerModel.EventProperties.MustDraw;
}
// Determine whether conditions are met
var conditionsMet = false;
switch (layerModel.Properties.ConditionType)
{
@ -26,11 +35,14 @@ namespace Artemis.Profiles.Layers.Conditions
break;
}
// Update the event properties
layerModel.EventProperties.Update(layerModel, conditionsMet);
// If conditions are met trigger the event, this won't do anything if the event isn't ready to be triggered yet
if (conditionsMet)
layerModel.EventProperties.TriggerEvent(layerModel);
// Return the event's MustDraw
return layerModel.EventProperties.MustDraw;
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Timers;
using Newtonsoft.Json;
namespace Artemis.Profiles.Layers.Models
@ -10,7 +11,7 @@ namespace Artemis.Profiles.Layers.Models
public TimeSpan TriggerDelay { get; set; }
[JsonIgnore]
public bool CanTrigger { get; set; }
public bool CanTrigger { get; set; } = true;
[JsonIgnore]
public DateTime EventTriggerTime { get; set; }
@ -18,30 +19,46 @@ namespace Artemis.Profiles.Layers.Models
[JsonIgnore]
public bool MustDraw { get; set; }
public DateTime EventCanTriggerTime { get; set; }
/// <summary>
/// Resets the event's properties and triggers it
/// If possible, triggers the event
/// </summary>
public virtual void TriggerEvent(LayerModel layer)
{
if (!CanTrigger)
return;
// Don't allow any more triggering regardless of what happens next
CanTrigger = false;
// If there is a trigger delay, stop here and await that delay
if (TriggerDelay > TimeSpan.Zero)
{
if (EventCanTriggerTime == DateTime.MinValue)
EventCanTriggerTime = DateTime.Now;
var timer = new Timer(TriggerDelay.TotalMilliseconds) {AutoReset = false};
timer.Elapsed += (sender, args) =>
{
HardTrigger(layer);
timer.Dispose();
};
timer.Start();
if (DateTime.Now - EventCanTriggerTime < TriggerDelay)
return;
EventCanTriggerTime = DateTime.MinValue;
return;
}
CanTrigger = false;
// Trigger the event
HardTrigger(layer);
}
/// <summary>
/// Instantly trigger the event regardless of current state
/// </summary>
/// <param name="layer"></param>
public void HardTrigger(LayerModel layer)
{
MustDraw = true;
CanTrigger = false;
EventTriggerTime = DateTime.Now;
// Reset the animation in case it didn't finish before
layer.AnimationProgress = 0.0;
}
@ -60,7 +77,7 @@ namespace Artemis.Profiles.Layers.Models
return DateTime.Now - EventTriggerTime > Length;
}
if (ExpirationType == ExpirationType.Animation)
return (layer.LayerAnimation == null) || layer.LayerAnimation.MustExpire(layer);
return layer.LayerAnimation == null || layer.LayerAnimation.MustExpire(layer);
return true;
}
@ -68,24 +85,17 @@ namespace Artemis.Profiles.Layers.Models
// Called every frame, if parent conditions met.
public void Update(LayerModel layerModel, bool conditionsMet)
{
if (EventCanTriggerTime > DateTime.MinValue && (DateTime.Now - EventCanTriggerTime > TriggerDelay))
{
CanTrigger = true;
TriggerEvent(layerModel);
// If the event isn't finished yet just keep going
if (MustDraw && !MustStop(layerModel))
return;
}
if (MustDraw && MustStop(layerModel))
MustDraw = false;
// Otherwise make sure MustDraw is false
MustDraw = false;
// If the conditions aren't met and the event has finished it can be triggered again
if (!conditionsMet)
CanTrigger = true;
}
protected bool DelayExpired()
{
return EventCanTriggerTime > DateTime.MinValue && DateTime.Now - EventCanTriggerTime >= TriggerDelay;
}
}
public enum ExpirationType
@ -93,4 +103,4 @@ namespace Artemis.Profiles.Layers.Models
Time,
Animation
}
}
}

View File

@ -7,7 +7,7 @@ namespace Artemis.Profiles.Layers.Models
{
public override void TriggerEvent(LayerModel layer)
{
if (CanTrigger && DelayExpired())
if (CanTrigger)
{
if (layer.GifImage != null)
layer.GifImage.CurrentFrame = 0;
@ -18,12 +18,10 @@ namespace Artemis.Profiles.Layers.Models
public override bool MustStop(LayerModel layer)
{
if (ExpirationType != ExpirationType.Animation)
return base.MustStop(layer);
if (layer.LayerType is KeyboardGifType)
if (layer.LayerType is KeyboardGifType && ExpirationType == ExpirationType.Animation)
return layer.GifImage?.CurrentFrame >= layer.GifImage?.FrameCount - 1;
return (layer.LayerAnimation == null) || layer.LayerAnimation.MustExpire(layer);
return base.MustStop(layer);
}
}
}
}

View File

@ -2,6 +2,7 @@
using System.Windows.Forms;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Profiles.Layers.Conditions;
using MahApps.Metro.Controls;
namespace Artemis.Profiles.Layers.Models
@ -33,39 +34,30 @@ namespace Artemis.Profiles.Layers.Models
{
Unregister();
// Bind EnableHeldDown or DisableHeldDOwn
if (ToggleType == ToggleType.EnableHeldDown || ToggleType == ToggleType.DisableHeldDown)
if (layerModel.IsEvent)
RegisterEvent(layerModel, index);
else if (ToggleType == ToggleType.EnableHeldDown || ToggleType == ToggleType.DisableHeldDown)
RegisterToggle(layerModel, index);
else
RegisterRegular(layerModel, index);
}
private void RegisterEvent(LayerModel layerModel, int index)
{
Action action = () =>
{
Action downAction = null;
Action upAction = null;
switch (ToggleType)
{
case ToggleType.EnableHeldDown:
downAction = () => layerModel.RenderAllowed = true;
upAction = () => layerModel.RenderAllowed = false;
break;
case ToggleType.DisableHeldDown:
downAction = () => layerModel.RenderAllowed = false;
upAction = () => layerModel.RenderAllowed = true;
break;
}
// Either bind HotKey or mouse buttons depending on what isn't null
if (HotKey != null)
{
_downKeybind = new KeybindModel($"{layerModel.GetHashCode()}-{layerModel.Name}-{index}-down", HotKey, PressType.Down, downAction);
_upKeybind = new KeybindModel($"{layerModel.GetHashCode()}-{layerModel.Name}-{index}-up", HotKey, PressType.Up, upAction);
}
else if (MouseButtons != null)
{
_downKeybind = new KeybindModel($"{layerModel.GetHashCode()}-{layerModel.Name}-{index}-down", MouseButtons.Value, PressType.Down, downAction);
_upKeybind = new KeybindModel($"{layerModel.GetHashCode()}-{layerModel.Name}-{index}-up", MouseButtons.Value, PressType.Up, upAction);
}
KeybindManager.AddOrUpdate(_downKeybind);
KeybindManager.AddOrUpdate(_upKeybind);
return;
}
layerModel.EventProperties.TriggerEvent(layerModel);
};
// Either bind HotKey or mouse buttons depending on what isn't null
if (HotKey != null)
_downKeybind = new KeybindModel($"{layerModel.GetHashCode()}-{layerModel.Name}-{index}-down", HotKey, PressType.Down, action);
else if (MouseButtons != null)
_downKeybind = new KeybindModel($"{layerModel.GetHashCode()}-{layerModel.Name}-{index}-down", MouseButtons.Value, PressType.Down, action);
KeybindManager.AddOrUpdate(_downKeybind);
}
private void RegisterRegular(LayerModel layerModel, int index)
{
// Bind Enable, Disable or Toggle
Action action = null;
switch (ToggleType)
@ -88,6 +80,38 @@ namespace Artemis.Profiles.Layers.Models
_downKeybind = new KeybindModel($"{layerModel.GetHashCode()}-{layerModel.Name}-{index}-down", MouseButtons.Value, PressType.Down, action);
KeybindManager.AddOrUpdate(_downKeybind);
}
private void RegisterToggle(LayerModel layerModel, int index)
{
Action downAction = null;
Action upAction = null;
switch (ToggleType)
{
case ToggleType.EnableHeldDown:
downAction = () => layerModel.RenderAllowed = true;
upAction = () => layerModel.RenderAllowed = false;
break;
case ToggleType.DisableHeldDown:
downAction = () => layerModel.RenderAllowed = false;
upAction = () => layerModel.RenderAllowed = true;
break;
}
// Either bind HotKey or mouse buttons depending on what isn't null
if (HotKey != null)
{
_downKeybind = new KeybindModel($"{layerModel.GetHashCode()}-{layerModel.Name}-{index}-down", HotKey, PressType.Down, downAction);
_upKeybind = new KeybindModel($"{layerModel.GetHashCode()}-{layerModel.Name}-{index}-up", HotKey, PressType.Up, upAction);
}
else if (MouseButtons != null)
{
_downKeybind = new KeybindModel($"{layerModel.GetHashCode()}-{layerModel.Name}-{index}-down", MouseButtons.Value, PressType.Down, downAction);
_upKeybind = new KeybindModel($"{layerModel.GetHashCode()}-{layerModel.Name}-{index}-up", MouseButtons.Value, PressType.Up, upAction);
}
KeybindManager.AddOrUpdate(_downKeybind);
KeybindManager.AddOrUpdate(_upKeybind);
return;
}
}
public enum ToggleType

View File

@ -12,7 +12,6 @@ using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
using Artemis.Properties;
using Artemis.Utilities;
using Artemis.Utilities.Keyboard;
using Artemis.ViewModels;
using Artemis.ViewModels.Profiles;
@ -30,7 +29,7 @@ namespace Artemis.Profiles.Layers.Types.KeyPress
_deviceManager = deviceManager;
_keyPressLayers = new List<LayerModel>();
KeyboardHook.KeyDownCallback += KeyboardHookOnKeyDownCallback;
InputHook.KeyDownCallback += KeyboardHookOnKeyDownCallback;
}
public RadialGradientBrush TempBrush { get; set; }

View File

@ -5,7 +5,7 @@ using Artemis.Events;
using Artemis.Managers;
using Artemis.Profiles.Lua.Modules.Events;
using Artemis.Profiles.Lua.Wrappers;
using Artemis.Utilities.Keyboard;
using Artemis.Utilities;
using MoonSharp.Interpreter;
using NLog;
@ -23,7 +23,7 @@ namespace Artemis.Profiles.Lua.Modules
_profileModel = luaManager.ProfileModel;
_profileModel.OnDeviceUpdatedEvent += OnDeviceUpdatedEvent;
_profileModel.OnDeviceDrawnEvent += OnDeviceDrawnEvent;
KeyboardHook.KeyDownCallback += KeyboardHookOnKeyDownCallback;
InputHook.KeyDownCallback += KeyboardHookOnKeyDownCallback;
}
public override string ModuleName => "Events";
@ -118,7 +118,7 @@ namespace Artemis.Profiles.Lua.Modules
{
_profileModel.OnDeviceUpdatedEvent -= OnDeviceUpdatedEvent;
_profileModel.OnDeviceDrawnEvent -= OnDeviceDrawnEvent;
KeyboardHook.KeyDownCallback -= KeyboardHookOnKeyDownCallback;
InputHook.KeyDownCallback -= KeyboardHookOnKeyDownCallback;
}
#endregion

View File

@ -29,59 +29,22 @@ namespace Artemis.Utilities.DataReaders
#region Logitech
private const string LogitechPath = @"C:\Program Files\Logitech Gaming Software\SDK\LED\x64\";
public static bool RestoreLogitechDll()
{
if (!DllPlaced())
return false;
try
{
// Get rid of our own DLL
File.Delete(LogitechPath + @"\LogitechLed.dll");
// Restore the backup
if (File.Exists(LogitechPath + @"\LogitechLed.dll.bak"))
File.Copy(LogitechPath + @"\LogitechLed.dll.bak", LogitechPath + @"\LogitechLed.dll");
File.Delete(LogitechPath + @"\artemis.txt");
return true;
}
catch (Exception)
{
return false;
}
}
private static readonly string LogitechPath = @"C:\Program Files\Logitech Gaming Software\SDK\LED\x64\";
private static readonly string DllPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\dll";
public static void PlaceLogitechDll()
{
if (DllPlaced())
return;
try
{
// Create directory structure, just in case
Directory.CreateDirectory(LogitechPath + @"");
// Backup the existing DLL
if (File.Exists(LogitechPath + @"\LogitechLed.dll"))
{
if (!File.Exists(LogitechPath + @"\LogitechLed.dll.bak"))
File.Move(LogitechPath + @"\LogitechLed.dll", LogitechPath + @"\LogitechLed.dll.bak");
}
// Copy our own DLL in place
File.WriteAllBytes(LogitechPath + @"\LogitechLED.dll", Resources.LogitechLED);
// A token to show the file is placed
File.Create(LogitechPath + @"\artemis.txt");
// If the user doesn't have a Logitech device, the CLSID will be missing
// and we should create it ourselves.
if (!RegistryKeyPlaced())
PlaceRegistryKey();
{
// Change the registry key to point to the fake DLL
var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Classes\CLSID\{a6519e67-7632-4375-afdf-caa889744403}\ServerBinary", true);
key?.SetValue(null, DllPath + @"\LogitechLed.dll");
// Make sure the fake DLL is in place
if (!Directory.Exists(DllPath))
Directory.CreateDirectory(DllPath);
if (!File.Exists(DllPath + @"\LogitechLed.dll"))
File.WriteAllBytes(DllPath + @"\LogitechLED.dll", Resources.LogitechLED);
}
catch (Exception e)
{
@ -89,32 +52,13 @@ namespace Artemis.Utilities.DataReaders
}
}
public static bool DllPlaced()
public static void RestoreLogitechDll()
{
if (!Directory.Exists(LogitechPath + @""))
return false;
if (!RegistryKeyPlaced())
return false;
return File.Exists(LogitechPath + @"\artemis.txt");
}
private static bool RegistryKeyPlaced()
{
var key = Registry
.LocalMachine.OpenSubKey(
@"SOFTWARE\Classes\CLSID\{a6519e67-7632-4375-afdf-caa889744403}\ServerBinary");
return key != null;
}
private static void PlaceRegistryKey()
{
var key = Registry
.LocalMachine.OpenSubKey(
@"SOFTWARE\Classes\CLSID\{a6519e67-7632-4375-afdf-caa889744403}\ServerBinary", true);
// Change the registry key to point to the real DLL
var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Classes\CLSID\{a6519e67-7632-4375-afdf-caa889744403}\ServerBinary", true);
key?.SetValue(null, LogitechPath + @"\LogitechLed.dll");
}
#endregion
}
}
}

View File

@ -4,9 +4,9 @@ using System.Windows.Forms;
using Gma.System.MouseKeyHook;
using NLog;
namespace Artemis.Utilities.Keyboard
namespace Artemis.Utilities
{
public static class KeyboardHook
public static class InputHook
{
public delegate void KeyCallbackHandler(KeyEventArgs e);

View File

@ -9,6 +9,7 @@ namespace Artemis.ViewModels.Profiles
public sealed class LayerKeybindViewModel : Screen
{
private readonly LayerEditorViewModel _editorViewModel;
private bool _canToggleType;
private HotKey _hotKey;
private MouseButtons _mouseButtons;
@ -20,30 +21,20 @@ namespace Artemis.ViewModels.Profiles
LayerKeybindModel = layerKeybindModel;
PropertyChanged += MapViewToModel;
editorViewModel.PropertyChanged += EditorViewModelOnPropertyChanged;
MapModelToView();
}
private void MapViewToModel(object sender, PropertyChangedEventArgs e)
public bool CanToggleType
{
if (e.PropertyName == "MouseButtonsVisible" || e.PropertyName == "HotkeyVisible")
return;
if (MouseButtonsVisible)
SetMouseBind();
else
SetKeyBind();
}
private void MapModelToView()
{
PropertyChanged -= MapViewToModel;
if (LayerKeybindModel.MouseButtons != null)
MouseButtons = LayerKeybindModel.MouseButtons.Value;
HotKey = LayerKeybindModel.HotKey;
ToggleType = LayerKeybindModel.ToggleType;
PropertyChanged += MapViewToModel;
get { return _canToggleType; }
set
{
if (value == _canToggleType)
return;
_canToggleType = value;
NotifyOfPropertyChange(() => CanToggleType);
}
}
public LayerKeybindModel LayerKeybindModel { get; set; }
@ -88,6 +79,48 @@ namespace Artemis.ViewModels.Profiles
}
}
/// <summary>
/// Responds to the EventPropertiesViewModel being changed
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void EditorViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName != "EventPropertiesViewModel")
return;
if (_editorViewModel.ProposedLayer.IsEvent)
{
CanToggleType = false;
ToggleType = ToggleType.Enable;
}
else
CanToggleType = true;
}
private void MapViewToModel(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "MouseButtonsVisible" || e.PropertyName == "HotkeyVisible")
return;
if (MouseButtonsVisible)
SetMouseBind();
else
SetKeyBind();
}
private void MapModelToView()
{
PropertyChanged -= MapViewToModel;
if (LayerKeybindModel.MouseButtons != null)
MouseButtons = LayerKeybindModel.MouseButtons.Value;
HotKey = LayerKeybindModel.HotKey;
ToggleType = LayerKeybindModel.ToggleType;
PropertyChanged += MapViewToModel;
}
public void ToggleBindType()
{
if (MouseButtonsVisible)

View File

@ -6,7 +6,7 @@
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="Artemis | Edit Layer" Height="600" Width="1100"
Title="Artemis | Edit Layer" Height="640" Width="1100"
xmlns:cal="http://www.caliburnproject.org"
xmlns:converters="clr-namespace:Artemis.Utilities.Converters"
xmlns:models="clr-namespace:Artemis.Profiles.Layers.Models"
@ -96,7 +96,7 @@
<ListBox Height="138" x:Name="LayerConditionVms" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.Template>
<ControlTemplate>
<ScrollViewer>
<ScrollViewer HorizontalScrollBarVisibility="Disabled">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>

View File

@ -32,7 +32,7 @@
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Type -->
<ComboBox Grid.Column="0" ItemsSource="{Binding Source={StaticResource ToggleTypeEnumValues}}" SelectedItem="{Binding Path=ToggleType}">
<ComboBox Grid.Column="0" ItemsSource="{Binding Source={StaticResource ToggleTypeEnumValues}}" SelectedItem="{Binding Path=ToggleType}" IsEnabled="{Binding Path=CanToggleType}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource HEnumDescriptionConverter}}" />