From 35c12e2981950a9dfd2e934b1a5ae9495f5ea69c Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Tue, 21 Feb 2017 18:28:41 +0100 Subject: [PATCH] Field on layer null crash fix Throw render loop exceptions when debugging Add shrink animation for #304 Fix a few beta crashes Added backend logic for keydown/keyup and mouse events --- Artemis/Artemis/Artemis.csproj | 13 ++-- .../Artemis/InjectionModules/BaseModules.cs | 3 +- Artemis/Artemis/Managers/KeybindManager.cs | 36 +++++----- Artemis/Artemis/Managers/LoopManager.cs | 11 +++- Artemis/Artemis/Models/KeybindModel.cs | 40 ++++++++++-- .../Layers/Abstract/LayerCondition.cs | 11 ++++ .../Animations/RotateClockwiseAnimation.cs | 46 +++++++++++++ .../RotateCounterclockwiseAnimation.cs | 46 +++++++++++++ .../Layers/Animations/ShrinkAnimation.cs | 65 +++++++++++++++++++ .../Layers/Conditions/DataModelCondition.cs | 21 ++---- .../Layers/Conditions/EventCondition.cs | 11 ++-- .../Layers/Interfaces/ILayerCondition.cs | 11 ---- .../Profiles/Layers/Models/LayerModel.cs | 3 +- .../Types/ConicalBrush/ConicalBrushType.cs | 2 +- .../Layers/Types/KeyPress/KeyPressType.cs | 3 + .../Profiles/Lua/Modules/LuaKeybindModule.cs | 12 ++-- Artemis/Artemis/Profiles/ProfileModel.cs | 41 ++++++++---- .../Utilities/Keyboard/KeyboardHook.cs | 46 +++++++++---- .../ViewModels/ProfileEditorViewModel.cs | 4 +- Artemis/Artemis/packages.config | 2 +- 20 files changed, 336 insertions(+), 91 deletions(-) create mode 100644 Artemis/Artemis/Profiles/Layers/Abstract/LayerCondition.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Animations/RotateClockwiseAnimation.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Animations/RotateCounterclockwiseAnimation.cs create mode 100644 Artemis/Artemis/Profiles/Layers/Animations/ShrinkAnimation.cs delete mode 100644 Artemis/Artemis/Profiles/Layers/Interfaces/ILayerCondition.cs diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index 698c34680..614e91570 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -183,6 +183,10 @@ ..\packages\DynamicExpresso.Core.1.3.3.5\lib\net40\DynamicExpresso.Core.dll True + + ..\packages\MouseKeyHook.5.4.0\lib\net40\Gma.System.MouseKeyHook.dll + True + ..\packages\gong-wpf-dragdrop.0.1.4.3\lib\net40\GongSolutions.Wpf.DragDrop.dll True @@ -251,10 +255,6 @@ ..\packages\squirrel.windows.1.4.4\lib\Net45\NuGet.Squirrel.dll True - - ..\packages\Open.WinKeyboardHook.1.0.11\lib\net45\Open.WinKeyboardHook.dll - True - ..\packages\Process.NET.1.0.8\lib\Process.NET.dll True @@ -485,6 +485,9 @@ OverlayProfileView.xaml + + + @@ -622,7 +625,7 @@ - + diff --git a/Artemis/Artemis/InjectionModules/BaseModules.cs b/Artemis/Artemis/InjectionModules/BaseModules.cs index 7447fb67d..af74463cf 100644 --- a/Artemis/Artemis/InjectionModules/BaseModules.cs +++ b/Artemis/Artemis/InjectionModules/BaseModules.cs @@ -2,6 +2,7 @@ using Artemis.Managers; using Artemis.Models; using Artemis.Modules.Abstract; +using Artemis.Profiles.Layers.Abstract; using Artemis.Profiles.Layers.Interfaces; using Artemis.Profiles.Layers.Types.Audio.AudioCapturing; using Artemis.Profiles.Lua; @@ -92,7 +93,7 @@ namespace Artemis.InjectionModules Kernel.Bind(x => x.FromThisAssembly() .SelectAllClasses() - .InheritedFrom() + .InheritedFrom() .BindAllInterfaces()); Kernel.Bind(x => x.FromThisAssembly() diff --git a/Artemis/Artemis/Managers/KeybindManager.cs b/Artemis/Artemis/Managers/KeybindManager.cs index 263d299df..84880c46c 100644 --- a/Artemis/Artemis/Managers/KeybindManager.cs +++ b/Artemis/Artemis/Managers/KeybindManager.cs @@ -6,6 +6,7 @@ using Artemis.Models; using Artemis.Utilities.Keyboard; using MahApps.Metro.Controls; using KeyEventArgs = System.Windows.Forms.KeyEventArgs; +using MouseEventArgs = System.Windows.Forms.MouseEventArgs; namespace Artemis.Managers { @@ -15,25 +16,34 @@ namespace Artemis.Managers static KeybindManager() { - KeyboardHook.KeyDownCallback += KeyboardHookOnKeyDownCallback; + KeyboardHook.KeyDownCallback += args => ProcessKey(args, KeyType.KeyDown); + KeyboardHook.KeyUpCallback += args => ProcessKey(args, KeyType.KeyUp); + KeyboardHook.MouseDownCallback += args => ProcessMouse(args, KeyType.MouseDown); + KeyboardHook.MouseUpCallback += args => ProcessMouse(args, KeyType.MouseUp); } - - private static void KeyboardHookOnKeyDownCallback(KeyEventArgs e) + + private static void ProcessKey(KeyEventArgs keyEventArgs, KeyType keyType) { // 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) + if (keyEventArgs.KeyCode == Keys.LShiftKey || keyEventArgs.KeyCode == Keys.RShiftKey || + keyEventArgs.KeyCode == Keys.LControlKey || keyEventArgs.KeyCode == Keys.RControlKey || + keyEventArgs.KeyCode == Keys.LMenu || keyEventArgs.KeyCode == Keys.RMenu) return; // Create a WPF ModifierKeys enum - var modifiers = ModifierKeysFromBooleans(e.Alt, e.Control, e.Shift); + var modifiers = ModifierKeysFromBooleans(keyEventArgs.Alt, keyEventArgs.Control, keyEventArgs.Shift); // Create a HotKey object for comparison - var hotKey = new HotKey(KeyInterop.KeyFromVirtualKey(e.KeyValue), modifiers); + var hotKey = new HotKey(KeyInterop.KeyFromVirtualKey(keyEventArgs.KeyValue), modifiers); foreach (var keybindModel in KeybindModels) - keybindModel.InvokeIfMatched(hotKey); + keybindModel.InvokeIfMatched(hotKey, keyType); + } + + private static void ProcessMouse(MouseEventArgs mouseEventArgs, KeyType keyType) + { + foreach (var keybindModel in KeybindModels) + keybindModel.InvokeIfMatched(mouseEventArgs.Button, keyType); } public static void AddOrUpdate(KeybindModel keybindModel) @@ -58,12 +68,6 @@ namespace Artemis.Managers 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 @@ -84,4 +88,4 @@ namespace Artemis.Managers return modifiers; } } -} \ No newline at end of file +} diff --git a/Artemis/Artemis/Managers/LoopManager.cs b/Artemis/Artemis/Managers/LoopManager.cs index 3b5aca4f4..31b7300c8 100644 --- a/Artemis/Artemis/Managers/LoopManager.cs +++ b/Artemis/Artemis/Managers/LoopManager.cs @@ -56,12 +56,15 @@ namespace Artemis.Managers Render(); - int sleep = (int)(40f - (DateTime.Now.Ticks - preUpdateTicks) / 10000f); + int sleep = (int) (40f - (DateTime.Now.Ticks - preUpdateTicks) / 10000f); if (sleep > 0) Thread.Sleep(sleep); } catch (Exception e) { +#if DEBUG + throw e; +#endif _logger.Warn(e, "Exception in render loop"); } } @@ -155,11 +158,13 @@ namespace Artemis.Managers var headsets = _deviceManager.HeadsetProviders.Where(m => m.CanUse).ToList(); var generics = _deviceManager.GenericProviders.Where(m => m.CanUse).ToList(); var mousemats = _deviceManager.MousematProviders.Where(m => m.CanUse).ToList(); - + var keyboardOnly = !mice.Any() && !headsets.Any() && !generics.Any() && !mousemats.Any(); // Setup the frame for this tick - using (var frame = new FrameModel(_deviceManager.ActiveKeyboard, mice.Any(), headsets.Any(), generics.Any(), mousemats.Any())) + using ( + var frame = new FrameModel(_deviceManager.ActiveKeyboard, mice.Any(), headsets.Any(), generics.Any(), + mousemats.Any())) { if (renderModule.IsInitialized) renderModule.Render(frame, keyboardOnly); diff --git a/Artemis/Artemis/Models/KeybindModel.cs b/Artemis/Artemis/Models/KeybindModel.cs index 685894c0c..e1d71ab56 100644 --- a/Artemis/Artemis/Models/KeybindModel.cs +++ b/Artemis/Artemis/Models/KeybindModel.cs @@ -1,25 +1,57 @@ using System; +using System.Windows.Forms; using MahApps.Metro.Controls; namespace Artemis.Models { public class KeybindModel { - public KeybindModel(string name, HotKey hotKey, Action action) + public KeybindModel(string name, HotKey hotKey, KeyType keyType, Action action) { Name = name; HotKey = hotKey; + KeyType = keyType; + Action = action; + } + + public KeybindModel(string name, MouseButtons mouseButtons, KeyType keyType, Action action) + { + Name = name; + MouseButtons = mouseButtons; + KeyType = keyType; Action = action; } public string Name { get; set; } + public MouseButtons MouseButtons { get; } public HotKey HotKey { get; set; } public Action Action { get; set; } + public KeyType KeyType { get; set; } - public void InvokeIfMatched(HotKey hotKey) + public void InvokeIfMatched(HotKey hotKey, KeyType keyType) { + if (HotKey == null || hotKey == null || KeyType != keyType) + return; + if (hotKey.Equals(HotKey)) - Action.Invoke(); + Action?.Invoke(); + } + + public void InvokeIfMatched(MouseButtons mouseButtons, KeyType keyType) + { + if (KeyType != keyType) + return; + + if (mouseButtons.Equals(MouseButtons)) + Action?.Invoke(); } } -} \ No newline at end of file + + public enum KeyType + { + KeyDown, + KeyUp, + MouseDown, + MouseUp + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Abstract/LayerCondition.cs b/Artemis/Artemis/Profiles/Layers/Abstract/LayerCondition.cs new file mode 100644 index 000000000..06503f7e5 --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Abstract/LayerCondition.cs @@ -0,0 +1,11 @@ +using Artemis.Modules.Abstract; +using Artemis.Profiles.Layers.Models; + +namespace Artemis.Profiles.Layers.Abstract +{ + public abstract class LayerCondition + { + public abstract bool ConditionsMet(LayerModel layerModel, ModuleDataModel dataModel); + public abstract void KeybindTask(LayerConditionModel condition); + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Profiles/Layers/Animations/RotateClockwiseAnimation.cs b/Artemis/Artemis/Profiles/Layers/Animations/RotateClockwiseAnimation.cs new file mode 100644 index 000000000..2fd32a8d4 --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Animations/RotateClockwiseAnimation.cs @@ -0,0 +1,46 @@ +using System; +using System.Windows.Media; +using Artemis.Profiles.Layers.Interfaces; +using Artemis.Profiles.Layers.Models; + +namespace Artemis.Profiles.Layers.Animations +{ + public class RotateClockwiseAnimation : ILayerAnimation + { + public string Name => "Rotate clockwise"; + + public void Update(LayerModel layerModel, bool updateAnimations) + { + var progress = layerModel.AnimationProgress; + + if (MustExpire(layerModel)) + progress = 0; + progress = progress + layerModel.Properties.AnimationSpeed / 2.5; + + // If not previewing, store the animation progress in the actual model for the next frame + if (updateAnimations) + layerModel.AnimationProgress = progress; + } + + public void Draw(LayerModel layerModel, DrawingContext c, int drawScale) + { + if (layerModel.Brush == null) + return; + + // Set up variables for this frame + var fillRect = layerModel.Properties.PropertiesRect(drawScale); + var fillSize = Math.Sqrt(fillRect.Width * fillRect.Width + fillRect.Height * fillRect.Height); + fillRect.Inflate(fillSize - fillRect.Width, fillSize - fillRect.Height); + + var clip = layerModel.LayerRect(drawScale); + + c.PushClip(new RectangleGeometry(clip)); + c.PushTransform(new RotateTransform(36 * layerModel.AnimationProgress, fillRect.X + fillRect.Width / 2, fillRect.Y + fillRect.Height / 2)); + c.DrawRectangle(layerModel.Brush, null, fillRect); + c.Pop(); + c.Pop(); + } + + public bool MustExpire(LayerModel layer) => layer.AnimationProgress >= 10; + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Animations/RotateCounterclockwiseAnimation.cs b/Artemis/Artemis/Profiles/Layers/Animations/RotateCounterclockwiseAnimation.cs new file mode 100644 index 000000000..b79f2c2dc --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Animations/RotateCounterclockwiseAnimation.cs @@ -0,0 +1,46 @@ +using System; +using System.Windows.Media; +using Artemis.Profiles.Layers.Interfaces; +using Artemis.Profiles.Layers.Models; + +namespace Artemis.Profiles.Layers.Animations +{ + public class RotateCounterclockwiseAnimation : ILayerAnimation + { + public string Name => "Rotate counterclockwise"; + + public void Update(LayerModel layerModel, bool updateAnimations) + { + var progress = layerModel.AnimationProgress; + + if (MustExpire(layerModel)) + progress = 0; + progress = progress + layerModel.Properties.AnimationSpeed / 2.5; + + // If not previewing, store the animation progress in the actual model for the next frame + if (updateAnimations) + layerModel.AnimationProgress = progress; + } + + public void Draw(LayerModel layerModel, DrawingContext c, int drawScale) + { + if (layerModel.Brush == null) + return; + + // Set up variables for this frame + var fillRect = layerModel.Properties.PropertiesRect(drawScale); + var fillSize = Math.Sqrt(fillRect.Width * fillRect.Width + fillRect.Height * fillRect.Height); + fillRect.Inflate(fillSize - fillRect.Width, fillSize - fillRect.Height); + + var clip = layerModel.LayerRect(drawScale); + + c.PushClip(new RectangleGeometry(clip)); + c.PushTransform(new RotateTransform(36 * layerModel.AnimationProgress*-1, fillRect.X + fillRect.Width / 2, fillRect.Y + fillRect.Height / 2)); + c.DrawRectangle(layerModel.Brush, null, fillRect); + c.Pop(); + c.Pop(); + } + + public bool MustExpire(LayerModel layer) => layer.AnimationProgress >= 10; + } +} diff --git a/Artemis/Artemis/Profiles/Layers/Animations/ShrinkAnimation.cs b/Artemis/Artemis/Profiles/Layers/Animations/ShrinkAnimation.cs new file mode 100644 index 000000000..185821f0b --- /dev/null +++ b/Artemis/Artemis/Profiles/Layers/Animations/ShrinkAnimation.cs @@ -0,0 +1,65 @@ +using System; +using System.Windows.Media; +using Artemis.Profiles.Layers.Interfaces; +using Artemis.Profiles.Layers.Models; + +namespace Artemis.Profiles.Layers.Animations +{ + public class ShrinkAnimation : ILayerAnimation + { + public string Name => "Shrink"; + + 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; + + var progress = layerModel.AnimationProgress; + + if (MustExpire(layerModel)) + progress = 10; + progress = progress - layerModel.Properties.AnimationSpeed/2.5; + + // If not previewing, store the animation progress in the actual model for the next frame + if (updateAnimations) + layerModel.AnimationProgress = progress; + } + + public void Draw(LayerModel layerModel, DrawingContext c, int drawScale) + { + if (layerModel.Brush == null) + return; + + // Set up variables for this frame + var rect = layerModel.Properties.Contain + ? layerModel.LayerRect(drawScale) + : layerModel.Properties.PropertiesRect(drawScale); + + var clip = layerModel.LayerRect(drawScale); + + // Take an offset of 4 to allow layers to slightly leave their bounds + var progress = (6.0 - layerModel.AnimationProgress)*10.0; + if (progress < 0) + { + // Can't meddle with the original brush because it's frozen. + var brush = layerModel.Brush.Clone(); + brush.Opacity = 1 + 0.025*progress; + if (brush.Opacity < 0) + brush.Opacity = 0; + if (brush.Opacity > 1) + brush.Opacity = 1; + layerModel.Brush = brush; + } + rect.Inflate(-rect.Width/100.0*progress, -rect.Height/100.0*progress); + clip.Inflate(-clip.Width/100.0*progress, -clip.Height/100.0*progress); + + c.PushClip(new RectangleGeometry(clip)); + c.DrawRectangle(layerModel.Brush, null, rect); + c.Pop(); + } + + public bool MustExpire(LayerModel layer) => layer.AnimationProgress <= 0; + } +} \ 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 797b0f1a5..8f5560da4 100644 --- a/Artemis/Artemis/Profiles/Layers/Conditions/DataModelCondition.cs +++ b/Artemis/Artemis/Profiles/Layers/Conditions/DataModelCondition.cs @@ -3,22 +3,23 @@ using System.Collections.Generic; using System.Linq; using System.Windows; using Artemis.Modules.Abstract; +using Artemis.Profiles.Layers.Abstract; using Artemis.Profiles.Layers.Interfaces; using Artemis.Profiles.Layers.Models; namespace Artemis.Profiles.Layers.Conditions { - public class DataModelCondition : ILayerCondition + public class DataModelCondition : LayerCondition { - private static readonly TimeSpan Delay = TimeSpan.FromMilliseconds((SystemParameters.KeyboardDelay + 1) * 250); - private DateTime _lastKeypress; public bool HotKeyMet { get; set; } - public bool ConditionsMet(LayerModel layerModel, ModuleDataModel dataModel) + public override bool ConditionsMet(LayerModel layerModel, ModuleDataModel dataModel) { lock (layerModel.Properties.Conditions) { - var checkConditions = layerModel.Properties.Conditions.Where(c => !c.Field.Contains("hotkey")).ToList(); + var checkConditions = layerModel.Properties.Conditions + .Where(c => c.Field != null && !c.Field.Contains("hotkey")).ToList(); + if (checkConditions.Count == layerModel.Properties.Conditions.Count) return SimpleConditionsMet(layerModel, dataModel, checkConditions); @@ -36,20 +37,12 @@ namespace Artemis.Profiles.Layers.Conditions 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) + public override void KeybindTask(LayerConditionModel condition) { - _lastKeypress = DateTime.Now; switch (condition.Field) { case "hotkeyEnable": diff --git a/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs b/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs index 1700c6b5e..bcc1c3f01 100644 --- a/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs +++ b/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs @@ -1,22 +1,25 @@ using System.Collections.Generic; using System.Linq; using Artemis.Modules.Abstract; +using Artemis.Profiles.Layers.Abstract; using Artemis.Profiles.Layers.Interfaces; using Artemis.Profiles.Layers.Models; using Newtonsoft.Json; namespace Artemis.Profiles.Layers.Conditions { - public class EventCondition : ILayerCondition + public class EventCondition : LayerCondition { [JsonIgnore] public bool HotKeyMet { get; set; } - public bool ConditionsMet(LayerModel layerModel, ModuleDataModel dataModel) + public override bool ConditionsMet(LayerModel layerModel, ModuleDataModel dataModel) { lock (layerModel.Properties.Conditions) { - var checkConditions = layerModel.Properties.Conditions.Where(c => !c.Field.Contains("hotkey")).ToList(); + var checkConditions = layerModel.Properties.Conditions + .Where(c => c.Field != null && !c.Field.Contains("hotkey")).ToList(); + if (checkConditions.Count == layerModel.Properties.Conditions.Count) return SimpleConditionsMet(layerModel, dataModel, checkConditions); @@ -45,7 +48,7 @@ namespace Artemis.Profiles.Layers.Conditions } } - public void KeybindTask(LayerConditionModel condition) + public override void KeybindTask(LayerConditionModel condition) { switch (condition.Field) { diff --git a/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerCondition.cs b/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerCondition.cs deleted file mode 100644 index ab19a5dcc..000000000 --- a/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerCondition.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Artemis.Modules.Abstract; -using Artemis.Profiles.Layers.Models; - -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/LayerModel.cs b/Artemis/Artemis/Profiles/Layers/Models/LayerModel.cs index e04354364..90a61584b 100644 --- a/Artemis/Artemis/Profiles/Layers/Models/LayerModel.cs +++ b/Artemis/Artemis/Profiles/Layers/Models/LayerModel.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Windows; using System.Windows.Media; using Artemis.Modules.Abstract; +using Artemis.Profiles.Layers.Abstract; using Artemis.Profiles.Layers.Animations; using Artemis.Profiles.Layers.Conditions; using Artemis.Profiles.Layers.Interfaces; @@ -291,7 +292,7 @@ namespace Artemis.Profiles.Layers.Models #region Layer type properties public ILayerType LayerType { get; set; } - public ILayerCondition LayerCondition { get; set; } + public LayerCondition LayerCondition { get; set; } public ILayerAnimation LayerAnimation { get; set; } #endregion diff --git a/Artemis/Artemis/Profiles/Layers/Types/ConicalBrush/ConicalBrushType.cs b/Artemis/Artemis/Profiles/Layers/Types/ConicalBrush/ConicalBrushType.cs index cb2e4cff2..f96b597ee 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/ConicalBrush/ConicalBrushType.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/ConicalBrush/ConicalBrushType.cs @@ -36,7 +36,7 @@ namespace Artemis.Profiles.Layers.Types.ConicalBrush public ImageSource DrawThumbnail(LayerModel layer) { - _conicalGradientDrawerThumbnail.GradientStops = GetGradientStops(layer.Brush).Select(x => new Tuple(x.Offset, x.Color)).ToList(); + _conicalGradientDrawerThumbnail.GradientStops = GetGradientStops(layer.Properties.Brush).Select(x => new Tuple(x.Offset, x.Color)).ToList(); _conicalGradientDrawerThumbnail.Update(); Rect thumbnailRect = new Rect(0, 0, 18, 18); diff --git a/Artemis/Artemis/Profiles/Layers/Types/KeyPress/KeyPressType.cs b/Artemis/Artemis/Profiles/Layers/Types/KeyPress/KeyPressType.cs index f0b463067..eebd4d68f 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/KeyPress/KeyPressType.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/KeyPress/KeyPressType.cs @@ -140,6 +140,9 @@ namespace Artemis.Profiles.Layers.Types.KeyPress lock (_keyPressLayers) { + // Ensure the layer has keypress properties + SetupProperties(_layerModel); + var properties = (KeyPressPropertiesModel) _layerModel.Properties; var layer = LayerModel.CreateLayer(); layer.Properties.X = keyMatch.Value.X - properties.Scale/2; diff --git a/Artemis/Artemis/Profiles/Lua/Modules/LuaKeybindModule.cs b/Artemis/Artemis/Profiles/Lua/Modules/LuaKeybindModule.cs index 54c9a3ab8..ab608690a 100644 --- a/Artemis/Artemis/Profiles/Lua/Modules/LuaKeybindModule.cs +++ b/Artemis/Artemis/Profiles/Lua/Modules/LuaKeybindModule.cs @@ -33,10 +33,14 @@ namespace Artemis.Profiles.Lua.Modules /// /// Name of the keybind /// Hotkey in string format, per example: ALT+CTRL+SHIFT+D + /// The key type, either key up or key down /// LUA function to call /// Optional arguments for the passed function - public void SetKeybind(string name, string hotKey, DynValue function, params DynValue[] args) + public void SetKeybind(string name, string hotKey, KeyType keyType, DynValue function, params DynValue[] args) { + if (keyType != KeyType.KeyDown && keyType != KeyType.KeyUp) + throw new ScriptRuntimeException("Key type must either be KeyDown or KeyUp."); + var modifierKeys = ModifierKeys.None; var key = Key.System; var hotKeyParts = hotKey.Split('+').Select(p => p.Trim()); @@ -55,8 +59,8 @@ namespace Artemis.Profiles.Lua.Modules var hk = new HotKey(key, modifierKeys); var model = args != null - ? new KeybindModel("LUA-" + name, hk, () => LuaManager.Call(function, args)) - : new KeybindModel("LUA-" + name, hk, () => LuaManager.Call(function)); + ? new KeybindModel("LUA-" + name, hk, keyType, () => LuaManager.Call(function, args)) + : new KeybindModel("LUA-" + name, hk, keyType, () => LuaManager.Call(function)); KeybindManager.AddOrUpdate(model); @@ -88,4 +92,4 @@ namespace Artemis.Profiles.Lua.Modules LuaManager.ProfileModel.OnProfileUpdatedEvent -= ProfileModelOnOnProfileUpdatedEvent; } } -} \ No newline at end of file +} diff --git a/Artemis/Artemis/Profiles/ProfileModel.cs b/Artemis/Artemis/Profiles/ProfileModel.cs index 91de4d6b3..42f92a303 100644 --- a/Artemis/Artemis/Profiles/ProfileModel.cs +++ b/Artemis/Artemis/Profiles/ProfileModel.cs @@ -41,6 +41,7 @@ namespace Artemis.Profiles private void OnOnProfileUpdatedEvent(object sender, EventArgs e) { + ClearKeybinds(); ApplyKeybinds(); } @@ -194,13 +195,8 @@ namespace Artemis.Profiles } public void Deactivate(LuaManager luaManager) - { - foreach (var layerModel in Layers) - { - for (var index = 0; index < layerModel.Properties.Conditions.Count; index++) - KeybindManager.Remove($"{GameName}-{Name}-{layerModel.Name}-{index}"); - } - + { + ClearKeybinds(); luaManager.ClearLua(); } @@ -224,7 +220,7 @@ namespace Artemis.Profiles public void ApplyKeybinds() { - foreach (var layerModel in Layers) + foreach (var layerModel in GetLayers()) { for (var index = 0; index < layerModel.Properties.Conditions.Count; index++) { @@ -233,13 +229,34 @@ namespace Artemis.Profiles 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); + if (condition.Operator == "held") + { + var downAction = new Action(() => layerModel.LayerCondition.KeybindTask(condition)); + var downKb = new KeybindModel($"{GameName}-{Name}-{layerModel.Name}-{index}", condition.HotKey, KeyType.KeyDown, downAction); + var upAction = new Action(() => layerModel.LayerCondition.KeybindTask(condition)); + var upKb = new KeybindModel($"{GameName}-{Name}-{layerModel.Name}-{index}", condition.HotKey, KeyType.KeyUp, upAction); + KeybindManager.AddOrUpdate(downKb); + KeybindManager.AddOrUpdate(upKb); + } + else + { + var action = new Action(() => layerModel.LayerCondition.KeybindTask(condition)); + var kb = new KeybindModel($"{GameName}-{Name}-{layerModel.Name}-{index}", condition.HotKey, KeyType.KeyDown, action); + KeybindManager.AddOrUpdate(kb); + } } } } + public void ClearKeybinds() + { + foreach (var layerModel in GetLayers()) + { + for (var index = 0; index < layerModel.Properties.Conditions.Count; index++) + KeybindManager.Remove($"{GameName}-{Name}-{layerModel.Name}-{index}"); + } + } + #region Compare protected bool Equals(ProfileModel other) @@ -270,4 +287,4 @@ namespace Artemis.Profiles #endregion } -} \ No newline at end of file +} diff --git a/Artemis/Artemis/Utilities/Keyboard/KeyboardHook.cs b/Artemis/Artemis/Utilities/Keyboard/KeyboardHook.cs index 7579c942a..3c1d3bf71 100644 --- a/Artemis/Artemis/Utilities/Keyboard/KeyboardHook.cs +++ b/Artemis/Artemis/Utilities/Keyboard/KeyboardHook.cs @@ -1,27 +1,49 @@ using System.Threading.Tasks; using System.Windows.Forms; -using Open.WinKeyboardHook; +using Gma.System.MouseKeyHook; namespace Artemis.Utilities.Keyboard { public static class KeyboardHook { - private static KeyboardInterceptor _interceptor; + public delegate void KeyCallbackHandler(KeyEventArgs e); - public delegate void KeyDownCallbackHandler(KeyEventArgs e); + public delegate void MouseCallbackHandler(MouseEventArgs e); + + private static IKeyboardMouseEvents _globalHook; public static void SetupKeyboardHook() { - _interceptor = new KeyboardInterceptor(); - _interceptor.KeyDown += VirtualKeyboardOnKeyDown; - _interceptor.StartCapturing(); + _globalHook = Hook.GlobalEvents(); + _globalHook.KeyDown += GlobalHookOnKeyDown; + _globalHook.KeyUp += GlobalHookOnKeyUp; + _globalHook.MouseDown += GlobalHookOnMouseDown; + _globalHook.MouseUp += GlobalHookOnMouseUp; } - private static async void VirtualKeyboardOnKeyDown(object sender, KeyEventArgs keyEventArgs) - { - await Task.Factory.StartNew(() => { KeyDownCallback?.Invoke(keyEventArgs); }); + private static async void GlobalHookOnMouseDown(object sender, MouseEventArgs e) + { + await Task.Factory.StartNew(() => { MouseDownCallback?.Invoke(e); }); } - - public static event KeyDownCallbackHandler KeyDownCallback; + + private static async void GlobalHookOnMouseUp(object sender, MouseEventArgs e) + { + await Task.Factory.StartNew(() => { MouseUpCallback?.Invoke(e); }); + } + + private static async void GlobalHookOnKeyDown(object sender, KeyEventArgs e) + { + await Task.Factory.StartNew(() => { KeyDownCallback?.Invoke(e); }); + } + + private static async void GlobalHookOnKeyUp(object sender, KeyEventArgs e) + { + await Task.Factory.StartNew(() => { KeyUpCallback?.Invoke(e); }); + } + + public static event KeyCallbackHandler KeyDownCallback; + public static event KeyCallbackHandler KeyUpCallback; + public static event MouseCallbackHandler MouseDownCallback; + public static event MouseCallbackHandler MouseUpCallback; } -} \ No newline at end of file +} diff --git a/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs b/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs index ade255270..9419a5c1e 100644 --- a/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs +++ b/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs @@ -65,8 +65,8 @@ namespace Artemis.ViewModels _loopManager = loopManager; _moduleModel = moduleModel; _dialogService = dialogService; - _copyKeybind = new KeybindModel("copy", new HotKey(Key.C, ModifierKeys.Control), LayerToClipboard); - _pasteKeybind = new KeybindModel("paste", new HotKey(Key.V, ModifierKeys.Control), ClipboardToLayer); + _copyKeybind = new KeybindModel("copy", new HotKey(Key.C, ModifierKeys.Control), KeyType.KeyDown, LayerToClipboard); + _pasteKeybind = new KeybindModel("paste", new HotKey(Key.V, ModifierKeys.Control), KeyType.KeyDown, ClipboardToLayer); ProfileNames = new ObservableCollection(); Layers = new ObservableCollection(); diff --git a/Artemis/Artemis/packages.config b/Artemis/Artemis/packages.config index d78a83092..df1dd799e 100644 --- a/Artemis/Artemis/packages.config +++ b/Artemis/Artemis/packages.config @@ -16,6 +16,7 @@ + @@ -23,7 +24,6 @@ -