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

Implemented keybinds on layers

This commit is contained in:
SpoinkyNL 2017-02-06 15:01:58 +01:00
parent e051918486
commit 992d79a43f
11 changed files with 220 additions and 92 deletions

View File

@ -364,6 +364,7 @@
<Compile Include="Managers\LuaManager.cs" />
<Compile Include="Managers\MainManager.cs" />
<Compile Include="Managers\PreviewManager.cs" />
<Compile Include="Models\KeybindModel.cs" />
<Compile Include="Models\LayerEditorModel.cs" />
<Compile Include="Models\ProfileEditorModel.cs" />
<Compile Include="Modules\Abstract\ModuleDataModel.cs" />

View File

@ -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<HotKey, Action> HotKeys;
private static readonly List<KeybindModel> KeybindModels = new List<KeybindModel>();
static KeybindManager()
{
KeyboardHook.KeyDownCallback += KeyboardHookOnKeyDownCallback;
HotKeys = new Dictionary<HotKey, Action>();
}
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();
}
/// <summary>
/// Registers a hotkey and executes the provided action when the hotkey is pressed
/// </summary>
/// <param name="hotKey">The hotkey to register</param>
/// <param name="action">The action to invoke on press</param>
/// <returns>Returns true if key registed, false if already in use</returns>
public static bool RegisterHotkey(HotKey hotKey, Action action)
{
if (HotKeys.ContainsKey(hotKey))
return false;
HotKeys.Add(hotKey, action);
return true;
}
/// <summary>
/// Unregister the given hotkey
/// </summary>
/// <param name="hotKey">The hotkey to unregister</param>
/// <returns>Returns true if unregistered, false if not found</returns>
public static bool UnregisterHotkey(HotKey hotKey)
{
if (!HotKeys.ContainsKey(hotKey))
return false;
HotKeys.Remove(hotKey);
return true;
return modifiers;
}
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -6,5 +6,6 @@ namespace Artemis.Profiles.Layers.Interfaces
public interface ILayerCondition
{
bool ConditionsMet(LayerModel layerModel, ModuleDataModel dataModel);
void KeybindTask(LayerConditionModel condition);
}
}

View File

@ -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)
{

View File

@ -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)

View File

@ -319,6 +319,9 @@ namespace Artemis.ViewModels
{
Thread.Sleep(100);
SelectedLayer = selectModel;
// Let the profile reapply keybinds after messing with layers
SelectedProfile.ApplyKeybinds();
});
}

View File

@ -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<NamedOperator>();
Enums = new BindableCollection<string>();
DropdownValues = new BindableCollection<string>();
DataModelProps = new BindableCollection<GeneralHelpers.PropertyCollection>(_hotkeyProperties);
DataModelProps.AddRange(editorViewModel.DataModelProps);
@ -80,7 +84,7 @@ namespace Artemis.ViewModels.Profiles
public BindableCollection<GeneralHelpers.PropertyCollection> DataModelProps { get; set; }
public BindableCollection<NamedOperator> Operators { get; set; }
public BindableCollection<string> Enums { get; set; }
public BindableCollection<string> 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
{

View File

@ -52,13 +52,13 @@
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" x:Name="KeybindIsVisible" HorizontalAlignment="Left" VerticalAlignment="Top">
<controls:HotKeyBox x:Name="Keybind" VerticalAlignment="Center" HorizontalAlignment="Left" Width="110" Watermark="Enter keybind" AreModifierKeysRequired="True" />
<controls:HotKeyBox HotKey="{Binding Path=HotKey}" VerticalAlignment="Center" HorizontalAlignment="Left" Width="110" Watermark="Enter keybind" />
</StackPanel>
<StackPanel Grid.Column="0" x:Name="UserValueIsVisible" HorizontalAlignment="Left" VerticalAlignment="Top">
<TextBox x:Name="UserValue" VerticalAlignment="Center" HorizontalAlignment="Left" Width="110" controls:TextBoxHelper.Watermark="Enter value" />
</StackPanel>
<StackPanel Grid.Column="0" x:Name="EnumValueIsVisible" HorizontalAlignment="Left" VerticalAlignment="Top">
<ComboBox x:Name="Enums" Width="110" MaxDropDownHeight="125" HorizontalAlignment="Center"
<StackPanel Grid.Column="0" x:Name="UserDropdownValueIsVisible" HorizontalAlignment="Left" VerticalAlignment="Top">
<ComboBox x:Name="DropdownValues" Width="110" MaxDropDownHeight="125" HorizontalAlignment="Center"
VerticalAlignment="Top" />
</StackPanel>
<Button Grid.Column="1" x:Name="Delete" Width="26" Height="26" Style="{DynamicResource SquareButtonStyle}"