diff --git a/src/Artemis.Core/Plugins/ScriptingProviders/Scripts/ProfileScript.cs b/src/Artemis.Core/Plugins/ScriptingProviders/Scripts/ProfileScript.cs index 5822e1884..8b5f18ce4 100644 --- a/src/Artemis.Core/Plugins/ScriptingProviders/Scripts/ProfileScript.cs +++ b/src/Artemis.Core/Plugins/ScriptingProviders/Scripts/ProfileScript.cs @@ -11,10 +11,6 @@ namespace Artemis.Core.ScriptingProviders protected ProfileScript(Profile profile, ScriptConfiguration configuration) : base(configuration) { Profile = profile; - lock (Profile.Scripts) - { - Profile.Scripts.Add(this); - } } /// diff --git a/src/Artemis.Core/Plugins/ScriptingProviders/Scripts/Script.cs b/src/Artemis.Core/Plugins/ScriptingProviders/Scripts/Script.cs index 1ddd8e5ac..279c18252 100644 --- a/src/Artemis.Core/Plugins/ScriptingProviders/Scripts/Script.cs +++ b/src/Artemis.Core/Plugins/ScriptingProviders/Scripts/Script.cs @@ -20,8 +20,6 @@ namespace Artemis.Core.ScriptingProviders throw new ArtemisCoreException("The provided script configuration already has an active script"); ScriptConfiguration = configuration; - ScriptConfiguration.Script = this; - ScriptConfiguration.PropertyChanged += ScriptConfigurationOnPropertyChanged; } diff --git a/src/Artemis.Core/Services/Input/InputService.cs b/src/Artemis.Core/Services/Input/InputService.cs index abb7ef643..9b42bc54f 100644 --- a/src/Artemis.Core/Services/Input/InputService.cs +++ b/src/Artemis.Core/Services/Input/InputService.cs @@ -305,10 +305,17 @@ namespace Artemis.Core.Services } } + public bool IsKeyDown(KeyboardKey key) + { + return _pressedKeys.Any(p => p.Value.Contains(key)); + } + #endregion #region Mouse + private readonly HashSet _pressedButtons = new(); + private void InputProviderOnMouseButtonDataReceived(object? sender, InputProviderMouseButtonEventArgs e) { bool foundLedId = InputKeyUtilities.MouseButtonLedIdMap.TryGetValue(e.Button, out LedId ledId); @@ -320,9 +327,17 @@ namespace Artemis.Core.Services ArtemisMouseButtonUpDownEventArgs eventArgs = new(e.Device, led, e.Button, e.IsDown); OnMouseButtonUpDown(eventArgs); if (e.IsDown) + { + if (!_pressedButtons.Contains(e.Button)) + _pressedButtons.Add(e.Button); OnMouseButtonDown(eventArgs); + } else + { + if (_pressedButtons.Contains(e.Button)) + _pressedButtons.Remove(e.Button); OnMouseButtonUp(eventArgs); + } // _logger.Verbose("Mouse button data: LED ID: {ledId}, button: {button}, is down: {isDown}, device: {device} ", ledId, e.Button, e.IsDown, e.Device); } @@ -339,6 +354,11 @@ namespace Artemis.Core.Services // _logger.Verbose("Mouse move data: XY: {X},{Y} - delta XY: {deltaX},{deltaY} - device: {device} ", e.CursorX, e.CursorY, e.DeltaX, e.DeltaY, e.Device); } + public bool IsButtonDown(MouseButton button) + { + return _pressedButtons.Contains(button); + } + #endregion #region Events diff --git a/src/Artemis.Core/Services/Input/Interfaces/IInputService.cs b/src/Artemis.Core/Services/Input/Interfaces/IInputService.cs index 3c2936354..19985f2de 100644 --- a/src/Artemis.Core/Services/Input/Interfaces/IInputService.cs +++ b/src/Artemis.Core/Services/Input/Interfaces/IInputService.cs @@ -40,7 +40,19 @@ namespace Artemis.Core.Services /// void ReleaseAll(); - #region Events + /// + /// Determines whether the provided key is pressed by any device + /// + /// The key to check + /// if the key is pressed; otherwise + bool IsKeyDown(KeyboardKey key); + + /// + /// Determines whether the button key is pressed by any device + /// + /// The button to check + /// if the button is pressed; otherwise + bool IsButtonDown(MouseButton button); /// /// Occurs whenever a key on a keyboard was pressed or released @@ -92,8 +104,6 @@ namespace Artemis.Core.Services /// public event EventHandler DeviceIdentified; - #endregion - #region Identification /// diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs index 5e4841829..6c528bcfe 100644 --- a/src/Artemis.Core/Services/PluginManagementService.cs +++ b/src/Artemis.Core/Services/PluginManagementService.cs @@ -199,6 +199,12 @@ namespace Artemis.Core.Services public void LoadPlugins(List startupArguments, bool isElevated) { + if (startupArguments.Contains("--no-plugins")) + { + _logger.Warning("Artemis launched with --no-plugins, skipping the loading of plugins"); + return; + } + bool ignorePluginLock = startupArguments.Contains("--ignore-plugin-lock"); bool stayElevated = startupArguments.Contains("--force-elevation"); bool droppedAdmin = startupArguments.Contains("--dropped-admin"); diff --git a/src/Artemis.Core/Services/ScriptingService.cs b/src/Artemis.Core/Services/ScriptingService.cs index 38db76e16..36b030d1f 100644 --- a/src/Artemis.Core/Services/ScriptingService.cs +++ b/src/Artemis.Core/Services/ScriptingService.cs @@ -6,17 +6,20 @@ using System.Reflection; using Artemis.Core.ScriptingProviders; using Ninject; using Ninject.Parameters; +using Serilog; namespace Artemis.Core.Services { internal class ScriptingService : IScriptingService { + private readonly ILogger _logger; private readonly IPluginManagementService _pluginManagementService; private readonly IProfileService _profileService; private List _scriptingProviders; - public ScriptingService(IPluginManagementService pluginManagementService, IProfileService profileService) + public ScriptingService(ILogger logger, IPluginManagementService pluginManagementService, IProfileService profileService) { + _logger = logger; _pluginManagementService = pluginManagementService; _profileService = profileService; @@ -81,43 +84,71 @@ namespace Artemis.Core.Services public GlobalScript? CreateScriptInstance(ScriptConfiguration scriptConfiguration) { - if (scriptConfiguration.Script != null) - throw new ArtemisCoreException("The provided script configuration already has an active script"); + GlobalScript? script = null; + try + { + if (scriptConfiguration.Script != null) + throw new ArtemisCoreException("The provided script configuration already has an active script"); - ScriptingProvider? provider = _scriptingProviders.FirstOrDefault(p => p.Id == scriptConfiguration.ScriptingProviderId); - if (provider == null) + ScriptingProvider? provider = _scriptingProviders.FirstOrDefault(p => p.Id == scriptConfiguration.ScriptingProviderId); + if (provider == null) + return null; + + script = (GlobalScript) provider.Plugin.Kernel!.Get( + provider.GlobalScriptType, + CreateScriptConstructorArgument(provider.GlobalScriptType, scriptConfiguration) + ); + + script.ScriptingProvider = provider; + script.ScriptingService = this; + provider.InternalScripts.Add(script); + InternalGlobalScripts.Add(script); + + scriptConfiguration.Script = script; + return script; + } + catch (Exception e) + { + _logger.Warning(e, "Failed to initialize global script"); + script?.Dispose(); return null; - - GlobalScript script = (GlobalScript) provider.Plugin.Kernel!.Get( - provider.GlobalScriptType, - CreateScriptConstructorArgument(provider.GlobalScriptType, scriptConfiguration) - ); - - script.ScriptingProvider = provider; - script.ScriptingService = this; - provider.InternalScripts.Add(script); - InternalGlobalScripts.Add(script); - return script; + } } public ProfileScript? CreateScriptInstance(Profile profile, ScriptConfiguration scriptConfiguration) { - if (scriptConfiguration.Script != null) - throw new ArtemisCoreException("The provided script configuration already has an active script"); + ProfileScript? script = null; + try + { + if (scriptConfiguration.Script != null) + throw new ArtemisCoreException("The provided script configuration already has an active script"); - ScriptingProvider? provider = _scriptingProviders.FirstOrDefault(p => p.Id == scriptConfiguration.ScriptingProviderId); - if (provider == null) + ScriptingProvider? provider = _scriptingProviders.FirstOrDefault(p => p.Id == scriptConfiguration.ScriptingProviderId); + if (provider == null) + return null; + + script = (ProfileScript) provider.Plugin.Kernel!.Get( + provider.ProfileScriptType, + CreateScriptConstructorArgument(provider.ProfileScriptType, profile), + CreateScriptConstructorArgument(provider.ProfileScriptType, scriptConfiguration) + ); + + script.ScriptingProvider = provider; + provider.InternalScripts.Add(script); + lock (profile) + { + scriptConfiguration.Script = script; + profile.Scripts.Add(script); + } + + return script; + } + catch (Exception e) + { + _logger.Warning(e, "Failed to initialize profile script"); + script?.Dispose(); return null; - - ProfileScript script = (ProfileScript) provider.Plugin.Kernel!.Get( - provider.ProfileScriptType, - CreateScriptConstructorArgument(provider.ProfileScriptType, profile), - CreateScriptConstructorArgument(provider.ProfileScriptType, scriptConfiguration) - ); - - script.ScriptingProvider = provider; - provider.InternalScripts.Add(script); - return script; + } } /// diff --git a/src/Artemis.UI/Providers/NativeWindowInputProvider.cs b/src/Artemis.UI/Providers/NativeWindowInputProvider.cs index a6aa38e96..25e8f0471 100644 --- a/src/Artemis.UI/Providers/NativeWindowInputProvider.cs +++ b/src/Artemis.UI/Providers/NativeWindowInputProvider.cs @@ -21,6 +21,7 @@ namespace Artemis.UI.Providers private readonly IInputService _inputService; private readonly ILogger _logger; private DateTime _lastMouseUpdate; + private int _lastProcessId; private SpongeWindow _sponge; private System.Timers.Timer _taskManagerTimer; @@ -88,9 +89,15 @@ namespace Artemis.UI.Providers private void TaskManagerTimerOnElapsed(object sender, ElapsedEventArgs e) { + int processId = WindowUtilities.GetActiveProcessId(); + if (processId == _lastProcessId) + return; + + _lastProcessId = processId; + // If task manager has focus then we can't track keys properly, release everything to avoid them getting stuck // Same goes for Idle which is what you get when you press Ctrl+Alt+Del - Process active = Process.GetProcessById(WindowUtilities.GetActiveProcessId()); + Process active = Process.GetProcessById(processId); if (active?.ProcessName == "Taskmgr" || active?.ProcessName == "Idle") _inputService.ReleaseAll(); } @@ -164,7 +171,7 @@ namespace Artemis.UI.Providers private int _mouseDeltaX; private int _mouseDeltaY; - + private void HandleMouseData(RawInputData data, RawInputMouseData mouseData) { // Only submit mouse movement 25 times per second but increment the delta diff --git a/src/Artemis.UI/Screens/Home/HomeView.xaml b/src/Artemis.UI/Screens/Home/HomeView.xaml index 142cd5d14..1f6d99cc9 100644 --- a/src/Artemis.UI/Screens/Home/HomeView.xaml +++ b/src/Artemis.UI/Screens/Home/HomeView.xaml @@ -62,7 +62,7 @@ VerticalAlignment="Bottom" Margin="0 0 0 32"> - + @@ -86,23 +86,15 @@ - - - - Want more plugins? You can find them on our wiki. - - + diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/Dialogs/TimelineSegmentDialogViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/Dialogs/TimelineSegmentDialogViewModel.cs index 4267951b9..8f2b0585a 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/Dialogs/TimelineSegmentDialogViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/Dialogs/TimelineSegmentDialogViewModel.cs @@ -3,7 +3,6 @@ using System.Globalization; using System.Text.RegularExpressions; using System.Threading.Tasks; using Artemis.UI.Shared.Services; -using Castle.Core.Internal; using FluentValidation; using Stylet; @@ -70,7 +69,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline.Dialogs if (parts.Length == 1) return TimeSpan.FromSeconds(double.Parse(parts[0])); // Only milliseconds provided with a leading . - if (parts[0].IsNullOrEmpty()) + if (string.IsNullOrEmpty(parts[0])) { // Add trailing zeros so 2.5 becomes 2.500, can't seem to make double.Parse do that while (parts[0].Length < 3) parts[0] += "0"; diff --git a/src/Artemis.UI/Screens/RootView.xaml b/src/Artemis.UI/Screens/RootView.xaml index 50eebd295..4ad50b41c 100644 --- a/src/Artemis.UI/Screens/RootView.xaml +++ b/src/Artemis.UI/Screens/RootView.xaml @@ -61,6 +61,19 @@ VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" /> + + + + + + + + + Activating profile... + + + + - Robert 'Spoinky' Beekman + Robert Beekman + CommandParameter="https://github.com/RobertWasTaken/"> diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarView.xaml b/src/Artemis.UI/Screens/Sidebar/SidebarView.xaml index 209f1b250..62e0cf176 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarView.xaml +++ b/src/Artemis.UI/Screens/Sidebar/SidebarView.xaml @@ -18,6 +18,7 @@ + @@ -74,7 +75,8 @@ Margin="0 2" ItemContainerStyle="{StaticResource SidebarListBoxItem}" ItemsSource="{Binding SidebarScreens}" - SelectedItem="{Binding SelectedSidebarScreen}"> + SelectedItem="{Binding SelectedSidebarScreen}" + IsEnabled="{Binding ActivatingProfile, Converter={StaticResource InverseBooleanConverter}}"> @@ -105,7 +107,11 @@ dd:DragDrop.DropHandler="{Binding}"> - + diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs index 9b484250d..5ac1bf54e 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs +++ b/src/Artemis.UI/Screens/Sidebar/SidebarViewModel.cs @@ -35,6 +35,7 @@ namespace Artemis.UI.Screens.Sidebar private MainScreenViewModel _selectedScreen; private readonly SidebarScreenViewModel _profileEditor; private readonly DefaultDropHandler _defaultDropHandler; + private bool _activatingProfile; public SidebarViewModel(IKernel kernel, IEventAggregator eventAggregator, @@ -96,6 +97,12 @@ namespace Artemis.UI.Screens.Sidebar } } + public bool ActivatingProfile + { + get => _activatingProfile; + set => SetAndNotify(ref _activatingProfile, value); + } + private void ActivateScreenViewModel(SidebarScreenViewModel screenViewModel) { SelectedScreen = screenViewModel.CreateInstance(_kernel); @@ -155,18 +162,34 @@ namespace Artemis.UI.Screens.Sidebar if (_profileEditorService.SuspendEditing) _profileEditorService.SuspendEditing = false; - _profileEditorService.ChangeSelectedProfileConfiguration(profileConfiguration); - if (profileConfiguration != null) + + Task.Run(() => { - // Little workaround to clear the selected item in the menu, ugly but oh well - if (_selectedSidebarScreen != _profileEditor) + try { - _selectedSidebarScreen = null; - NotifyOfPropertyChange(nameof(SelectedSidebarScreen)); + ActivatingProfile = true; + _profileEditorService.ChangeSelectedProfileConfiguration(profileConfiguration); + } + finally + { + ActivatingProfile = false; } - SelectedSidebarScreen = _profileEditor; - } + if (profileConfiguration == null) + return; + + Execute.PostToUIThread(() => + { + // Little workaround to clear the selected item in the menu, ugly but oh well + if (_selectedSidebarScreen != _profileEditor) + { + _selectedSidebarScreen = null; + NotifyOfPropertyChange(nameof(SelectedSidebarScreen)); + } + + SelectedSidebarScreen = _profileEditor; + }); + }); } #region Overrides of Screen @@ -212,7 +235,7 @@ namespace Artemis.UI.Screens.Sidebar Items[index].ProfileCategory.Order = index; // Bit dumb but gets the job done - foreach (SidebarCategoryViewModel viewModel in Items) + foreach (SidebarCategoryViewModel viewModel in Items) _profileService.SaveProfileCategory(viewModel.ProfileCategory); } diff --git a/src/Artemis.UI/Utilities/WindowUtilities.cs b/src/Artemis.UI/Utilities/WindowUtilities.cs index 99409febd..62dd3d4e2 100644 --- a/src/Artemis.UI/Utilities/WindowUtilities.cs +++ b/src/Artemis.UI/Utilities/WindowUtilities.cs @@ -1,6 +1,5 @@ using System; using System.Runtime.InteropServices; -using System.Text; namespace Artemis.UI.Utilities {