diff --git a/src/Artemis.Core/Exceptions/ArtemisPluginException.cs b/src/Artemis.Core/Exceptions/ArtemisPluginException.cs index 8e49b0e19..53f9fd30f 100644 --- a/src/Artemis.Core/Exceptions/ArtemisPluginException.cs +++ b/src/Artemis.Core/Exceptions/ArtemisPluginException.cs @@ -10,7 +10,7 @@ public class ArtemisPluginException : Exception /// /// Creates a new instance of the class /// - public ArtemisPluginException(Plugin plugin) + internal ArtemisPluginException(Plugin plugin) { Plugin = plugin; } @@ -18,7 +18,7 @@ public class ArtemisPluginException : Exception /// /// Creates a new instance of the class /// - public ArtemisPluginException(Plugin plugin, string message) : base(message) + internal ArtemisPluginException(Plugin plugin, string message) : base(message) { Plugin = plugin; } @@ -26,7 +26,7 @@ public class ArtemisPluginException : Exception /// /// Creates a new instance of the class /// - public ArtemisPluginException(Plugin plugin, string message, Exception inner) : base(message, inner) + internal ArtemisPluginException(Plugin plugin, string message, Exception inner) : base(message, inner) { Plugin = plugin; } @@ -44,9 +44,31 @@ public class ArtemisPluginException : Exception public ArtemisPluginException(string message, Exception inner) : base(message, inner) { } + + /// + /// Creates a new instance of the class + /// + public ArtemisPluginException(string message, string helpDocument) : base(message) + { + HelpDocument = helpDocument; + } + + /// + /// Creates a new instance of the class + /// + public ArtemisPluginException(string message, Exception inner, string helpDocument) : base(message, inner) + { + HelpDocument = helpDocument; + } /// /// Gets the plugin the error is related to /// public Plugin? Plugin { get; } + + /// + /// Gets or sets the help document related to this exception. + /// + public string? HelpDocument { get; } + } \ No newline at end of file diff --git a/src/Artemis.Core/Services/Interfaces/IPluginManagementService.cs b/src/Artemis.Core/Services/Interfaces/IPluginManagementService.cs index 209158529..8e0faf564 100644 --- a/src/Artemis.Core/Services/Interfaces/IPluginManagementService.cs +++ b/src/Artemis.Core/Services/Interfaces/IPluginManagementService.cs @@ -127,6 +127,13 @@ public interface IPluginManagementService : IArtemisService, IDisposable /// If the current call stack contains a plugin, the plugin. Otherwise null Plugin? GetCallingPlugin(); + /// + /// Returns the plugin that threw the provided exception. + /// + /// + /// If the exception was thrown by a plugin, the plugin. Otherwise null + Plugin? GetPluginFromException(Exception exception); + /// /// Gets the plugin that defined the specified device /// diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs index 06b9b6368..c03aec7bb 100644 --- a/src/Artemis.Core/Services/PluginManagementService.cs +++ b/src/Artemis.Core/Services/PluginManagementService.cs @@ -192,7 +192,19 @@ internal class PluginManagementService : IPluginManagementService public Plugin? GetCallingPlugin() { - StackTrace stackTrace = new(); // get call stack + return GetPluginFromStackTrace(new StackTrace()); + } + + public Plugin? GetPluginFromException(Exception exception) + { + if (exception is ArtemisPluginException pluginException && pluginException.Plugin != null) + return pluginException.Plugin; + + return GetPluginFromStackTrace(new StackTrace(exception)); + } + + private Plugin? GetPluginFromStackTrace(StackTrace stackTrace) + { StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) foreach (StackFrame stackFrame in stackFrames) diff --git a/src/Artemis.UI.Shared/Controls/HotkeyBox.axaml b/src/Artemis.UI.Shared/Controls/HotkeyBox.axaml index 0e53282e1..6b7e0c0c1 100644 --- a/src/Artemis.UI.Shared/Controls/HotkeyBox.axaml +++ b/src/Artemis.UI.Shared/Controls/HotkeyBox.axaml @@ -10,8 +10,16 @@ diff --git a/src/Artemis.UI.Shared/Controls/HotkeyBox.axaml.cs b/src/Artemis.UI.Shared/Controls/HotkeyBox.axaml.cs index d87e02d70..555d21320 100644 --- a/src/Artemis.UI.Shared/Controls/HotkeyBox.axaml.cs +++ b/src/Artemis.UI.Shared/Controls/HotkeyBox.axaml.cs @@ -8,6 +8,8 @@ using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Markup.Xaml; +using Avalonia.Threading; +using DryIoc; using FluentAvalonia.Core; using Humanizer; using Material.Icons; @@ -19,44 +21,62 @@ namespace Artemis.UI.Shared; /// public partial class HotkeyBox : UserControl { + private readonly IInputService _inputService; + /// /// Creates a new instance of the class /// public HotkeyBox() { + _inputService = UI.Locator.Resolve(); + InitializeComponent(); PropertyChanged += OnPropertyChanged; - DisplayTextBox.KeyDown += DisplayTextBoxOnKeyDown; - DisplayTextBox.KeyUp += DisplayTextBoxOnKeyUp; UpdateDisplayTextBox(); } + protected override void OnGotFocus(GotFocusEventArgs e) + { + _inputService.KeyboardKeyDown += InputServiceOnKeyboardKeyDown; + _inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp; + + base.OnGotFocus(e); + } + + protected override void OnLostFocus(RoutedEventArgs e) + { + _inputService.KeyboardKeyDown -= InputServiceOnKeyboardKeyDown; + _inputService.KeyboardKeyUp -= InputServiceOnKeyboardKeyUp; + + base.OnLostFocus(e); + } + private void OnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) { if (e.Property == HotkeyProperty) UpdateDisplayTextBox(); } - private void DisplayTextBoxOnKeyDown(object? sender, KeyEventArgs e) + private void InputServiceOnKeyboardKeyDown(object? sender, ArtemisKeyboardKeyEventArgs e) { - if (e.Key >= Key.LeftShift && e.Key <= Key.RightAlt) + if (e.Key >= KeyboardKey.LeftShift && e.Key <= KeyboardKey.RightAlt) return; Hotkey ??= new Hotkey(); - Hotkey.Key = (KeyboardKey?) e.Key; - Hotkey.Modifiers = (KeyboardModifierKey?) e.KeyModifiers; - UpdateDisplayTextBox(); - HotkeyChanged?.Invoke(this, EventArgs.Empty); - - e.Handled = true; + Hotkey.Key = e.Key; + Hotkey.Modifiers = e.Modifiers; + + Dispatcher.UIThread.Post(() => + { + UpdateDisplayTextBox(); + HotkeyChanged?.Invoke(this, EventArgs.Empty); + }); } - private void DisplayTextBoxOnKeyUp(object? sender, KeyEventArgs e) + private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEventArgs e) { - if (e.KeyModifiers == KeyModifiers.None) - FocusManager.Instance?.Focus(null); - - e.Handled = true; + if (e.Modifiers == KeyboardModifierKey.None) + Dispatcher.UIThread.Post(() => FocusManager.Instance?.Focus(null)); } private void UpdateDisplayTextBox() diff --git a/src/Artemis.UI.Shared/DryIoc/ContainerExtensions.cs b/src/Artemis.UI.Shared/DryIoc/ContainerExtensions.cs index 4c4711b02..1c86ecf84 100644 --- a/src/Artemis.UI.Shared/DryIoc/ContainerExtensions.cs +++ b/src/Artemis.UI.Shared/DryIoc/ContainerExtensions.cs @@ -17,5 +17,7 @@ public static class ContainerExtensions { Assembly artemisShared = typeof(IArtemisSharedUIService).GetAssembly(); container.RegisterMany(new[] { artemisShared }, type => type.IsAssignableTo(), Reuse.Singleton); + + UI.Locator = container; } } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Utilities.cs b/src/Artemis.UI.Shared/Utilities.cs new file mode 100644 index 000000000..35abef7db --- /dev/null +++ b/src/Artemis.UI.Shared/Utilities.cs @@ -0,0 +1,8 @@ +using DryIoc; + +namespace Artemis.UI.Shared; + +internal static class UI +{ + public static IContainer Locator { get; set; } = null!; +} \ No newline at end of file