diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj
index 8baeec089..fa1c89fff 100644
--- a/Artemis/Artemis/Artemis.csproj
+++ b/Artemis/Artemis/Artemis.csproj
@@ -364,6 +364,7 @@
+
diff --git a/Artemis/Artemis/Managers/KeybindManager.cs b/Artemis/Artemis/Managers/KeybindManager.cs
index 65c7e37dc..263d299df 100644
--- a/Artemis/Artemis/Managers/KeybindManager.cs
+++ b/Artemis/Artemis/Managers/KeybindManager.cs
@@ -1,7 +1,8 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
+using System.Linq;
using System.Windows.Forms;
using System.Windows.Input;
+using Artemis.Models;
using Artemis.Utilities.Keyboard;
using MahApps.Metro.Controls;
using KeyEventArgs = System.Windows.Forms.KeyEventArgs;
@@ -10,76 +11,77 @@ namespace Artemis.Managers
{
public static class KeybindManager
{
- private static readonly Dictionary HotKeys;
+ private static readonly List KeybindModels = new List();
static KeybindManager()
{
KeyboardHook.KeyDownCallback += KeyboardHookOnKeyDownCallback;
- HotKeys = new Dictionary();
}
private static void KeyboardHookOnKeyDownCallback(KeyEventArgs e)
{
- // Don't trigger if none of the modifiers are held down
- if (!e.Alt && !e.Control && !e.Shift)
- return;
-
// Don't trigger if the key itself is a modifier
if (e.KeyCode == Keys.LShiftKey || e.KeyCode == Keys.RShiftKey ||
e.KeyCode == Keys.LControlKey || e.KeyCode == Keys.RControlKey ||
e.KeyCode == Keys.LMenu || e.KeyCode == Keys.RMenu)
return;
+ // Create a WPF ModifierKeys enum
+ var modifiers = ModifierKeysFromBooleans(e.Alt, e.Control, e.Shift);
+
+ // Create a HotKey object for comparison
+ var hotKey = new HotKey(KeyInterop.KeyFromVirtualKey(e.KeyValue), modifiers);
+
+ foreach (var keybindModel in KeybindModels)
+ keybindModel.InvokeIfMatched(hotKey);
+ }
+
+ public static void AddOrUpdate(KeybindModel keybindModel)
+ {
+ var existing = KeybindModels.FirstOrDefault(k => k.Name == keybindModel.Name);
+ if (existing != null)
+ KeybindModels.Remove(existing);
+
+ KeybindModels.Add(keybindModel);
+ }
+
+ public static void Remove(KeybindModel keybindModel)
+ {
+ if (KeybindModels.Contains(keybindModel))
+ KeybindModels.Remove(keybindModel);
+ }
+
+ public static void Remove(string name)
+ {
+ var existing = KeybindModels.FirstOrDefault(k => k.Name == name);
+ if (existing != null)
+ KeybindModels.Remove(existing);
+ }
+
+ public static void Clear()
+ {
+ // TODO: Re-add future global keybinds here or just exclude them from the clear
+ KeybindModels.Clear();
+ }
+
+ public static ModifierKeys ModifierKeysFromBooleans(bool alt, bool control, bool shift)
+ {
// Create a WPF ModifierKeys enum
var modifiers = ModifierKeys.None;
- if (e.Alt)
+ if (alt)
modifiers = ModifierKeys.Alt;
- if (e.Control)
+ if (control)
if (modifiers == ModifierKeys.None)
modifiers = ModifierKeys.Control;
else
modifiers |= ModifierKeys.Control;
- if (e.Shift)
+ if (shift)
if (modifiers == ModifierKeys.None)
modifiers = ModifierKeys.Shift;
else
modifiers |= ModifierKeys.Shift;
- // Create a HotKey object for comparison
- var hotKey = new HotKey(KeyInterop.KeyFromVirtualKey(e.KeyValue), modifiers);
-
- // If the hotkey is present, invoke the action related to it
- if (HotKeys.ContainsKey(hotKey))
- HotKeys[hotKey].Invoke();
- }
-
- ///
- /// Registers a hotkey and executes the provided action when the hotkey is pressed
- ///
- /// The hotkey to register
- /// The action to invoke on press
- /// Returns true if key registed, false if already in use
- public static bool RegisterHotkey(HotKey hotKey, Action action)
- {
- if (HotKeys.ContainsKey(hotKey))
- return false;
-
- HotKeys.Add(hotKey, action);
- return true;
- }
-
- ///
- /// Unregister the given hotkey
- ///
- /// The hotkey to unregister
- /// Returns true if unregistered, false if not found
- public static bool UnregisterHotkey(HotKey hotKey)
- {
- if (!HotKeys.ContainsKey(hotKey))
- return false;
-
- HotKeys.Remove(hotKey);
- return true;
+ return modifiers;
}
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Models/KeybindModel.cs b/Artemis/Artemis/Models/KeybindModel.cs
new file mode 100644
index 000000000..685894c0c
--- /dev/null
+++ b/Artemis/Artemis/Models/KeybindModel.cs
@@ -0,0 +1,25 @@
+using System;
+using MahApps.Metro.Controls;
+
+namespace Artemis.Models
+{
+ public class KeybindModel
+ {
+ public KeybindModel(string name, HotKey hotKey, Action action)
+ {
+ Name = name;
+ HotKey = hotKey;
+ Action = action;
+ }
+
+ public string Name { get; set; }
+ public HotKey HotKey { get; set; }
+ public Action Action { get; set; }
+
+ public void InvokeIfMatched(HotKey hotKey)
+ {
+ if (hotKey.Equals(HotKey))
+ Action.Invoke();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Conditions/DataModelCondition.cs b/Artemis/Artemis/Profiles/Layers/Conditions/DataModelCondition.cs
index 255b059b8..190d7e1e3 100644
--- a/Artemis/Artemis/Profiles/Layers/Conditions/DataModelCondition.cs
+++ b/Artemis/Artemis/Profiles/Layers/Conditions/DataModelCondition.cs
@@ -1,5 +1,7 @@
using System;
using System.Linq;
+using System.Windows;
+using System.Windows.Forms;
using Artemis.Modules.Abstract;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
@@ -8,21 +10,52 @@ namespace Artemis.Profiles.Layers.Conditions
{
public class DataModelCondition : ILayerCondition
{
+ private DateTime _lastKeypress;
+ public bool HotKeyMet { get; set; }
+ private static readonly TimeSpan Delay = TimeSpan.FromMilliseconds((SystemParameters.KeyboardDelay + 1) * 250);
+
public bool ConditionsMet(LayerModel layerModel, ModuleDataModel dataModel)
{
lock (layerModel.Properties.Conditions)
{
+ var checkConditions = layerModel.Properties.Conditions.Where(c => !c.Field.Contains("hotkey"));
+ var conditionMet = false;
switch (layerModel.Properties.ConditionType)
{
case ConditionType.AnyMet:
- return layerModel.Properties.Conditions.Any(cm => cm.ConditionMet(dataModel));
+ conditionMet = HotKeyMet || checkConditions.Any(cm => cm.ConditionMet(dataModel));
+ break;
case ConditionType.AllMet:
- return layerModel.Properties.Conditions.All(cm => cm.ConditionMet(dataModel));
+ conditionMet = HotKeyMet && checkConditions.All(cm => cm.ConditionMet(dataModel));
+ break;
case ConditionType.NoneMet:
- return !layerModel.Properties.Conditions.Any(cm => cm.ConditionMet(dataModel));
- default:
- return false;
+ conditionMet = !HotKeyMet && !checkConditions.Any(cm => cm.ConditionMet(dataModel));
+ break;
}
+
+ // If there is a held down keybind on it, reset every 2 frames, after 500 ms
+ if (layerModel.Properties.Conditions.Any(c => c.Operator == "held") && DateTime.Now - _lastKeypress > Delay)
+ HotKeyMet = false;
+
+ return conditionMet;
+ }
+ }
+
+
+ public void KeybindTask(LayerConditionModel condition)
+ {
+ _lastKeypress = DateTime.Now;
+ switch (condition.Field)
+ {
+ case "hotkeyEnable":
+ HotKeyMet = true;
+ break;
+ case "hotkeyDisable":
+ HotKeyMet = false;
+ break;
+ case "hotkeyToggle":
+ HotKeyMet = !HotKeyMet;
+ break;
}
}
}
diff --git a/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs b/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs
index 5db52f958..699f9f810 100644
--- a/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs
+++ b/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs
@@ -1,37 +1,60 @@
-using System;
-using System.Linq;
+using System.Linq;
using Artemis.Modules.Abstract;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
+using Newtonsoft.Json;
namespace Artemis.Profiles.Layers.Conditions
{
public class EventCondition : ILayerCondition
{
+ [JsonIgnore]
+ public bool HotKeyMet { get;set; }
+
public bool ConditionsMet(LayerModel layerModel, ModuleDataModel dataModel)
{
lock (layerModel.Properties.Conditions)
{
+ var checkConditions = layerModel.Properties.Conditions.Where(c => !c.Field.Contains("hotkey"));
var conditionsMet = false;
switch (layerModel.Properties.ConditionType)
{
case ConditionType.AnyMet:
- conditionsMet = layerModel.Properties.Conditions.Any(cm => cm.ConditionMet(dataModel));
+ conditionsMet = HotKeyMet || checkConditions.Any(cm => cm.ConditionMet(dataModel));
break;
case ConditionType.AllMet:
- conditionsMet = layerModel.Properties.Conditions.All(cm => cm.ConditionMet(dataModel));
+ conditionsMet = HotKeyMet && checkConditions.All(cm => cm.ConditionMet(dataModel));
break;
case ConditionType.NoneMet:
- conditionsMet = !layerModel.Properties.Conditions.Any(cm => cm.ConditionMet(dataModel));
+ conditionsMet = !HotKeyMet && !checkConditions.Any(cm => cm.ConditionMet(dataModel));
break;
}
+
layerModel.EventProperties.Update(layerModel, conditionsMet);
- if (conditionsMet && layerModel.EventProperties.CanTrigger)
- layerModel.EventProperties.TriggerEvent(layerModel);
+ if (conditionsMet)
+ layerModel.EventProperties.TriggerEvent(layerModel);
+ if (layerModel.EventProperties.MustStop(layerModel))
+ HotKeyMet = false;
return layerModel.EventProperties.MustDraw;
}
}
+
+ public void KeybindTask(LayerConditionModel condition)
+ {
+ switch (condition.Field)
+ {
+ case "hotkeyEnable":
+ HotKeyMet = true;
+ break;
+ case "hotkeyDisable":
+ HotKeyMet = false;
+ break;
+ case "hotkeyToggle":
+ HotKeyMet = !HotKeyMet;
+ break;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerCondition.cs b/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerCondition.cs
index ee2ff364b..ab19a5dcc 100644
--- a/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerCondition.cs
+++ b/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerCondition.cs
@@ -6,5 +6,6 @@ namespace Artemis.Profiles.Layers.Interfaces
public interface ILayerCondition
{
bool ConditionsMet(LayerModel layerModel, ModuleDataModel dataModel);
+ void KeybindTask(LayerConditionModel condition);
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs b/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs
index 71de0a2ce..560d74408 100644
--- a/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs
+++ b/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs
@@ -3,6 +3,7 @@ using System.Globalization;
using Artemis.Modules.Abstract;
using Artemis.Utilities;
using DynamicExpresso;
+using MahApps.Metro.Controls;
namespace Artemis.Profiles.Layers.Models
{
@@ -20,6 +21,7 @@ namespace Artemis.Profiles.Layers.Models
public string Value { get; set; }
public string Operator { get; set; }
public string Type { get; set; }
+ public HotKey HotKey { get; set; }
public bool ConditionMet(ModuleDataModel subject)
{
diff --git a/Artemis/Artemis/Profiles/ProfileModel.cs b/Artemis/Artemis/Profiles/ProfileModel.cs
index 610e44749..9cf4c7fd4 100644
--- a/Artemis/Artemis/Profiles/ProfileModel.cs
+++ b/Artemis/Artemis/Profiles/ProfileModel.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
@@ -184,11 +185,13 @@ namespace Artemis.Profiles
public void Activate(LuaManager luaManager)
{
+ ApplyKeybinds();
luaManager.SetupLua(this);
}
public void Deactivate(LuaManager luaManager)
{
+ KeybindManager.Clear();
luaManager.ClearLua();
}
@@ -210,6 +213,24 @@ namespace Artemis.Profiles
return layer;
}
+ public void ApplyKeybinds()
+ {
+ foreach (var layerModel in Layers)
+ {
+ for (var index = 0; index < layerModel.Properties.Conditions.Count; index++)
+ {
+ var condition = layerModel.Properties.Conditions[index];
+ if (condition.Field == null || !condition.Field.Contains("hotkey"))
+ continue;
+
+ // Create an action for the layer, the layer's specific condition type handles activation
+ var action = new Action(() => layerModel.LayerCondition.KeybindTask(condition));
+ var kb = new KeybindModel($"{GameName}-{Name}-{layerModel.Name}-{index}", condition.HotKey, action);
+ KeybindManager.AddOrUpdate(kb);
+ }
+ }
+ }
+
#region Compare
protected bool Equals(ProfileModel other)
diff --git a/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs b/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs
index 5fbb1bfed..1092c51d9 100644
--- a/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs
+++ b/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs
@@ -319,6 +319,9 @@ namespace Artemis.ViewModels
{
Thread.Sleep(100);
SelectedLayer = selectModel;
+
+ // Let the profile reapply keybinds after messing with layers
+ SelectedProfile.ApplyKeybinds();
});
}
diff --git a/Artemis/Artemis/ViewModels/Profiles/LayerConditionViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/LayerConditionViewModel.cs
index b70d8792c..031447180 100644
--- a/Artemis/Artemis/ViewModels/Profiles/LayerConditionViewModel.cs
+++ b/Artemis/Artemis/ViewModels/Profiles/LayerConditionViewModel.cs
@@ -3,6 +3,7 @@ using System.Linq;
using Artemis.Profiles.Layers.Models;
using Artemis.Utilities;
using Caliburn.Micro;
+using MahApps.Metro.Controls;
namespace Artemis.ViewModels.Profiles
{
@@ -18,14 +19,14 @@ namespace Artemis.ViewModels.Profiles
private readonly NamedOperator[] _hotkeyOperators =
{
new NamedOperator("Pressed", "enable"),
- new NamedOperator("Held down", "disable")
+ new NamedOperator("Held down", "held")
};
private readonly GeneralHelpers.PropertyCollection[] _hotkeyProperties =
{
- new GeneralHelpers.PropertyCollection {Display = "Enable when hotkey", Type = "hotkeyEnable"},
- new GeneralHelpers.PropertyCollection {Display = "Disable when hotkey", Type = "hotkeyDisable"},
- new GeneralHelpers.PropertyCollection {Display = "Toggle when hotkey", Type = "hotkeyToggle"}
+ new GeneralHelpers.PropertyCollection {Display = "Enable when hotkey", Type = "hotkeyEnable", Path = "hotkeyEnable"},
+ new GeneralHelpers.PropertyCollection {Display = "Disable when hotkey", Type = "hotkeyDisable", Path = "hotkeyDisable"},
+ new GeneralHelpers.PropertyCollection {Display = "Toggle when hotkey", Type = "hotkeyToggle", Path = "hotkeyToggle"}
};
private readonly NamedOperator[] _int32Operators =
@@ -53,11 +54,14 @@ namespace Artemis.ViewModels.Profiles
new NamedOperator("Ends with", ".EndsWith")
};
- private bool _enumValueIsVisible;
+ private HotKey _hotKey;
+
private bool _keybindIsVisible;
private GeneralHelpers.PropertyCollection _selectedDataModelProp;
- private string _selectedEnum;
+ private string _selectedDropdownValue;
private NamedOperator _selectedOperator;
+
+ private bool _userDropdownValueIsVisible;
private string _userValue;
private bool _userValueIsVisible;
@@ -67,7 +71,7 @@ namespace Artemis.ViewModels.Profiles
ConditionModel = conditionModel;
Operators = new BindableCollection();
- Enums = new BindableCollection();
+ DropdownValues = new BindableCollection();
DataModelProps = new BindableCollection(_hotkeyProperties);
DataModelProps.AddRange(editorViewModel.DataModelProps);
@@ -80,7 +84,7 @@ namespace Artemis.ViewModels.Profiles
public BindableCollection DataModelProps { get; set; }
public BindableCollection Operators { get; set; }
- public BindableCollection Enums { get; set; }
+ public BindableCollection DropdownValues { get; set; }
public string UserValue
{
@@ -93,6 +97,17 @@ namespace Artemis.ViewModels.Profiles
}
}
+ public HotKey HotKey
+ {
+ get { return _hotKey; }
+ set
+ {
+ if (Equals(value, _hotKey)) return;
+ _hotKey = value;
+ NotifyOfPropertyChange(() => HotKey);
+ }
+ }
+
public GeneralHelpers.PropertyCollection SelectedDataModelProp
{
get { return _selectedDataModelProp; }
@@ -116,14 +131,14 @@ namespace Artemis.ViewModels.Profiles
}
}
- public bool EnumValueIsVisible
+ public bool UserDropdownValueIsVisible
{
- get { return _enumValueIsVisible; }
+ get { return _userDropdownValueIsVisible; }
set
{
- if (value == _enumValueIsVisible) return;
- _enumValueIsVisible = value;
- NotifyOfPropertyChange(() => EnumValueIsVisible);
+ if (value == _userDropdownValueIsVisible) return;
+ _userDropdownValueIsVisible = value;
+ NotifyOfPropertyChange(() => UserDropdownValueIsVisible);
}
}
@@ -149,14 +164,14 @@ namespace Artemis.ViewModels.Profiles
}
}
- public string SelectedEnum
+ public string SelectedDropdownValue
{
- get { return _selectedEnum; }
+ get { return _selectedDropdownValue; }
set
{
- if (value == _selectedEnum) return;
- _selectedEnum = value;
- NotifyOfPropertyChange(() => SelectedEnum);
+ if (value == _selectedDropdownValue) return;
+ _selectedDropdownValue = value;
+ NotifyOfPropertyChange(() => SelectedDropdownValue);
}
}
@@ -168,9 +183,10 @@ namespace Artemis.ViewModels.Profiles
SelectedDataModelProp = DataModelProps.FirstOrDefault(m => m.Path == ConditionModel.Field);
// Select the operator
SelectedOperator = Operators.FirstOrDefault(o => o.Value == ConditionModel.Operator);
+ HotKey = ConditionModel.HotKey;
if (ConditionModel.Type == "Enum" || ConditionModel.Type == "Boolean")
- SelectedEnum = ConditionModel.Value;
+ SelectedDropdownValue = ConditionModel.Value;
else
UserValue = ConditionModel.Value;
@@ -182,9 +198,10 @@ namespace Artemis.ViewModels.Profiles
ConditionModel.Field = SelectedDataModelProp.Path;
ConditionModel.Operator = SelectedOperator.Value;
ConditionModel.Type = SelectedDataModelProp.Type;
+ ConditionModel.HotKey = HotKey;
if (ConditionModel.Type == "Enum" || ConditionModel.Type == "Boolean")
- ConditionModel.Value = SelectedEnum;
+ ConditionModel.Value = SelectedDropdownValue;
else
ConditionModel.Value = UserValue;
}
@@ -197,7 +214,7 @@ namespace Artemis.ViewModels.Profiles
public void SetupPropertyInput()
{
Operators.Clear();
- Enums.Clear();
+ DropdownValues.Clear();
switch (SelectedDataModelProp.Type)
{
@@ -208,9 +225,9 @@ namespace Artemis.ViewModels.Profiles
break;
case "Boolean":
Operators.AddRange(_boolOperators);
- Enums.Add("True");
- Enums.Add("False");
- EnumValueIsVisible = true;
+ DropdownValues.Add("True");
+ DropdownValues.Add("False");
+ UserDropdownValueIsVisible = true;
break;
case "String":
Operators.AddRange(_stringOperators);
@@ -242,14 +259,14 @@ namespace Artemis.ViewModels.Profiles
Operators.Add(new NamedOperator("Increased", "increased"));
}
}
-
+
SetupUserValueInput();
}
private void SetupUserValueInput()
{
UserValueIsVisible = false;
- EnumValueIsVisible = false;
+ UserDropdownValueIsVisible = false;
KeybindIsVisible = false;
// Event operators don't have any form of input
@@ -257,19 +274,19 @@ namespace Artemis.ViewModels.Profiles
SelectedOperator.Value == "increased")
return;
- if (SelectedDataModelProp.Type.Contains("hotkey"))
+ if (SelectedDataModelProp.Type != null && SelectedDataModelProp.Type.Contains("hotkey"))
{
KeybindIsVisible = true;
}
else if (SelectedDataModelProp.Type == "Boolean")
{
- EnumValueIsVisible = true;
+ UserDropdownValueIsVisible = true;
}
else if (SelectedDataModelProp.EnumValues != null)
{
- Enums.Clear();
- Enums.AddRange(SelectedDataModelProp.EnumValues);
- EnumValueIsVisible = true;
+ DropdownValues.Clear();
+ DropdownValues.AddRange(SelectedDataModelProp.EnumValues);
+ UserDropdownValueIsVisible = true;
}
else
{
diff --git a/Artemis/Artemis/Views/Profiles/LayerConditionView.xaml b/Artemis/Artemis/Views/Profiles/LayerConditionView.xaml
index 77ea18a79..a2981b7f6 100644
--- a/Artemis/Artemis/Views/Profiles/LayerConditionView.xaml
+++ b/Artemis/Artemis/Views/Profiles/LayerConditionView.xaml
@@ -52,13 +52,13 @@
-
+
-
-
+