diff --git a/Artemis/Artemis/DAL/ProfileProvider.cs b/Artemis/Artemis/DAL/ProfileProvider.cs
index 2b770e74e..5d89fd42c 100644
--- a/Artemis/Artemis/DAL/ProfileProvider.cs
+++ b/Artemis/Artemis/DAL/ProfileProvider.cs
@@ -4,6 +4,7 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
+using Artemis.KeyboardProviders;
using Artemis.Models;
using Artemis.Models.Profiles;
@@ -27,10 +28,16 @@ namespace Artemis.DAL
/// Get all profiles matching the provided game
///
/// The game to match
+ /// The keyboard to match
/// All profiles matching the provided game
- public static List GetAll(GameModel game)
+ public static List GetAll(GameModel game, KeyboardProvider keyboard)
{
- return GetAll().Where(g => g.GameName.Equals(game.Name)).ToList();
+ if (game == null)
+ throw new ArgumentNullException(nameof(game));
+ if (keyboard == null)
+ throw new ArgumentNullException(nameof(keyboard));
+
+ return GetAll().Where(g => g.GameName.Equals(game.Name) && g.KeyboardName.Equals(keyboard.Name)).ToList();
}
///
@@ -40,6 +47,8 @@ namespace Artemis.DAL
/// The profile to add or update
public static void AddOrUpdate(ProfileModel prof)
{
+ if (prof == null)
+ throw new ArgumentNullException(nameof(prof));
if (!(prof.GameName?.Length > 1) || !(prof.KeyboardName?.Length > 1) || !(prof.Name?.Length > 1))
throw new ArgumentException("Profile is invalid. Name, GameName and KeyboardName are required");
diff --git a/Artemis/Artemis/Events/ActiveKeyboardChanged.cs b/Artemis/Artemis/Events/ActiveKeyboardChanged.cs
index fb123dd86..a6656802d 100644
--- a/Artemis/Artemis/Events/ActiveKeyboardChanged.cs
+++ b/Artemis/Artemis/Events/ActiveKeyboardChanged.cs
@@ -1,12 +1,16 @@
-namespace Artemis.Events
+using Artemis.KeyboardProviders;
+
+namespace Artemis.Events
{
public class ActiveKeyboardChanged
{
- public ActiveKeyboardChanged(string activeKeyboard)
+ public ActiveKeyboardChanged(KeyboardProvider oldKeyboard, KeyboardProvider newKeyboard)
{
- ActiveKeyboard = activeKeyboard;
+ OldKeyboard = oldKeyboard;
+ NewKeyboard = newKeyboard;
}
- public string ActiveKeyboard { get; set; }
+ public KeyboardProvider OldKeyboard { get; set; }
+ public KeyboardProvider NewKeyboard { get; set; }
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/InjectionModules/BaseModules.cs b/Artemis/Artemis/InjectionModules/BaseModules.cs
index 8e895bfb1..46c2fcd2a 100644
--- a/Artemis/Artemis/InjectionModules/BaseModules.cs
+++ b/Artemis/Artemis/InjectionModules/BaseModules.cs
@@ -17,6 +17,7 @@ namespace Artemis.InjectionModules
Bind().To().InSingletonScope();
Bind().ToFactory();
+ Bind().To().InSingletonScope();
Bind().To().InSingletonScope();
Bind().To().InSingletonScope();
Bind().To().InSingletonScope();
diff --git a/Artemis/Artemis/KeyboardProviders/Corsair/CorsairRGB.cs b/Artemis/Artemis/KeyboardProviders/Corsair/CorsairRGB.cs
index 93069f2c2..5e0bf0fb8 100644
--- a/Artemis/Artemis/KeyboardProviders/Corsair/CorsairRGB.cs
+++ b/Artemis/Artemis/KeyboardProviders/Corsair/CorsairRGB.cs
@@ -123,17 +123,10 @@ namespace Artemis.KeyboardProviders.Corsair
///
public override void DrawBitmap(Bitmap bitmap)
{
- var fixedBmp = new Bitmap(bitmap.Width, bitmap.Height);
- using (var g = Graphics.FromImage(fixedBmp))
- {
- g.Clear(Color.Black);
- g.DrawImage(bitmap, 0, 0);
- }
-
- var fixedImage = ImageUtilities.ResizeImage(fixedBmp, Width, Height);
+ var image = ImageUtilities.ResizeImage(bitmap, Width, Height);
var brush = new ImageBrush
{
- Image = fixedImage
+ Image = image
};
_keyboard.Brush = brush;
diff --git a/Artemis/Artemis/Managers/EffectManager.cs b/Artemis/Artemis/Managers/EffectManager.cs
index 43329a0c6..654d11d92 100644
--- a/Artemis/Artemis/Managers/EffectManager.cs
+++ b/Artemis/Artemis/Managers/EffectManager.cs
@@ -79,6 +79,9 @@ namespace Artemis.Managers
///
private void SetupProfilePreview(object sender, ElapsedEventArgs e)
{
+ if (_keyboardManager.ChangingKeyboard)
+ return;
+
// Make sure the preview model should still be active
if (ActiveEffect is ProfilePreviewModel)
{
@@ -133,41 +136,39 @@ namespace Artemis.Managers
if (effectModel is OverlayModel)
throw new ArgumentException("Can't set an Overlay effect as the active effect");
- lock (_keyboardManager)
+ if (_keyboardManager.ActiveKeyboard == null)
+ _keyboardManager.EnableLastKeyboard();
+ // If still null, no last keyboard, so stop.
+ if (_keyboardManager.ActiveKeyboard == null)
+ return;
+
+ // Game models are only used if they are enabled
+ var gameModel = effectModel as GameModel;
+ if (gameModel != null)
+ if (!gameModel.Enabled)
+ return;
+
+ var wasNull = false;
+ if (ActiveEffect == null)
{
- lock (this)
- {
- if (_keyboardManager.ActiveKeyboard == null)
- _keyboardManager.EnableLastKeyboard();
- // If still null, no last keyboard, so stop.
- if (_keyboardManager.ActiveKeyboard == null)
- return;
+ wasNull = true;
+ ActiveEffect = effectModel;
+ }
- // Game models are only used if they are enabled
- var gameModel = effectModel as GameModel;
- if (gameModel != null)
- if (!gameModel.Enabled)
- return;
+ lock (ActiveEffect)
+ {
+ if (!wasNull)
+ ActiveEffect.Dispose();
- var wasNull = false;
- if (ActiveEffect == null)
- {
- wasNull = true;
- ActiveEffect = effectModel;
- }
- if (!wasNull)
- ActiveEffect.Dispose();
+ ActiveEffect = effectModel;
+ ActiveEffect.Enable();
- ActiveEffect = effectModel;
- ActiveEffect.Enable();
+ if (ActiveEffect is GameModel || ActiveEffect is ProfilePreviewModel)
+ return;
- if (ActiveEffect is GameModel || ActiveEffect is ProfilePreviewModel)
- return;
-
- // Non-game effects are stored as the new LastEffect.
- General.Default.LastEffect = ActiveEffect?.Name;
- General.Default.Save();
- }
+ // Non-game effects are stored as the new LastEffect.
+ General.Default.LastEffect = ActiveEffect?.Name;
+ General.Default.Save();
}
if (loopManager != null && !loopManager.Running)
@@ -185,18 +186,19 @@ namespace Artemis.Managers
///
public void ClearEffect()
{
- lock (_keyboardManager)
- {
- lock (this)
- {
- ActiveEffect.Dispose();
- ActiveEffect = null;
+ if (ActiveEffect == null)
+ return;
- General.Default.LastEffect = null;
- General.Default.Save();
- }
+ lock (ActiveEffect)
+ {
+ ActiveEffect.Dispose();
+ ActiveEffect = null;
+
+ General.Default.LastEffect = null;
+ General.Default.Save();
}
+
_logger.Debug("Cleared active effect");
}
diff --git a/Artemis/Artemis/Managers/KeyboardManager.cs b/Artemis/Artemis/Managers/KeyboardManager.cs
index 5d0e72ad1..bceff508b 100644
--- a/Artemis/Artemis/Managers/KeyboardManager.cs
+++ b/Artemis/Artemis/Managers/KeyboardManager.cs
@@ -18,7 +18,6 @@ namespace Artemis.Managers
{
private readonly IEventAggregator _events;
private readonly ILogger _logger;
- private KeyboardProvider _activeKeyboard;
public KeyboardManager(IEventAggregator events, ILogger logger, List keyboardProviders)
{
@@ -36,16 +35,9 @@ namespace Artemis.Managers
public List KeyboardProviders { get; set; }
- public KeyboardProvider ActiveKeyboard
- {
- get { return _activeKeyboard; }
- set
- {
- _activeKeyboard = value;
- // Let the ViewModels know
- _events.PublishOnUIThread(new ActiveKeyboardChanged(value?.Name));
- }
- }
+ public KeyboardProvider ActiveKeyboard { get; set; }
+
+ public bool ChangingKeyboard { get; private set; }
///
/// Enables the last keyboard according to the settings file
@@ -68,11 +60,19 @@ namespace Artemis.Managers
{
lock (this)
{
+ ChangingKeyboard = true;
+
if (keyboardProvider == null)
throw new ArgumentNullException(nameof(keyboardProvider));
if (ActiveKeyboard?.Name == keyboardProvider.Name)
+ {
+ ChangingKeyboard = false;
return;
+ }
+
+ // Store the old keyboard so it can be used in the event we're raising later
+ var oldKeyboard = ActiveKeyboard;
var wasNull = false;
if (ActiveKeyboard == null)
@@ -94,6 +94,7 @@ namespace Artemis.Managers
General.Default.LastKeyboard = null;
General.Default.Save();
_logger.Warn("Failed enabling keyboard: {0}", keyboardProvider.Name);
+ ChangingKeyboard = false;
return;
}
@@ -102,6 +103,9 @@ namespace Artemis.Managers
General.Default.LastKeyboard = ActiveKeyboard.Name;
General.Default.Save();
+
+ ChangingKeyboard = false;
+ _events.PublishOnUIThread(new ActiveKeyboardChanged(oldKeyboard, ActiveKeyboard));
_logger.Debug("Enabled keyboard: {0}", keyboardProvider.Name);
}
}
@@ -116,9 +120,17 @@ namespace Artemis.Managers
if (ActiveKeyboard == null)
return;
+ // Store the old keyboard so it can be used in the event we're raising later
+ var oldKeyboard = ActiveKeyboard;
+
var releaseName = ActiveKeyboard.Name;
ActiveKeyboard.Disable();
ActiveKeyboard = null;
+
+ General.Default.LastKeyboard = null;
+ General.Default.Save();
+
+ _events.PublishOnUIThread(new ActiveKeyboardChanged(oldKeyboard, null));
_logger.Debug("Released keyboard: {0}", releaseName);
}
}
diff --git a/Artemis/Artemis/Managers/LoopManager.cs b/Artemis/Artemis/Managers/LoopManager.cs
index 7d855ecd7..1e8d21312 100644
--- a/Artemis/Artemis/Managers/LoopManager.cs
+++ b/Artemis/Artemis/Managers/LoopManager.cs
@@ -1,4 +1,5 @@
using System;
+using System.Drawing;
using System.Timers;
using Artemis.Events;
using Caliburn.Micro;
@@ -57,7 +58,6 @@ namespace Artemis.Managers
return;
}
- // TODO: Deadlock maybe? I don't know what Resharper is on about
if (_effectManager.ActiveEffect == null)
{
var lastEffect = _effectManager.GetLastEffect();
@@ -88,6 +88,18 @@ namespace Artemis.Managers
if (!Running)
return;
+ // Stop if no active effect
+ if (_effectManager.ActiveEffect == null)
+ {
+ _logger.Debug("No active effect, stopping");
+ Stop();
+ return;
+ }
+ var renderEffect = _effectManager.ActiveEffect;
+
+ if (_keyboardManager.ChangingKeyboard)
+ return;
+
// Stop if no active keyboard
if (_keyboardManager.ActiveKeyboard == null)
{
@@ -95,50 +107,47 @@ namespace Artemis.Managers
Stop();
return;
}
- // Lock both the active keyboard and active effect so they will not change while rendering.
- lock (_keyboardManager)
+
+ lock (_keyboardManager.ActiveKeyboard)
{
- lock (_effectManager)
+ // Skip frame if effect is still initializing
+ if (renderEffect.Initialized == false)
+ return;
+
+ // Update the current effect
+ if (renderEffect.Initialized)
+ renderEffect.Update();
+
+ // Get ActiveEffect's bitmap
+ var bitmap = renderEffect.Initialized
+ ? renderEffect.GenerateBitmap()
+ : null;
+
+ // Draw enabled overlays on top
+ foreach (var overlayModel in _effectManager.EnabledOverlays)
{
- // Stop if no active effect
- if (_effectManager.ActiveEffect == null)
- {
- _logger.Debug("No active effect, stopping");
- Stop();
- return;
- }
-
- // Skip frame if effect is still initializing
- if (_effectManager.ActiveEffect.Initialized == false)
- return;
-
- // Update the current effect
- if (_effectManager.ActiveEffect.Initialized)
- _effectManager.ActiveEffect.Update();
-
- // Get ActiveEffect's bitmap
- var bitmap = _effectManager.ActiveEffect.Initialized
- ? _effectManager.ActiveEffect.GenerateBitmap()
- : null;
-
- // Draw enabled overlays on top
- foreach (var overlayModel in _effectManager.EnabledOverlays)
- {
- overlayModel.Update();
- bitmap = bitmap != null
- ? overlayModel.GenerateBitmap(bitmap)
- : overlayModel.GenerateBitmap();
- }
-
- if (bitmap == null)
- return;
-
- // If it exists, send bitmap to the device
- _keyboardManager.ActiveKeyboard.DrawBitmap(bitmap);
-
- // debugging TODO: Disable when window isn't shown (in Debug VM, or get rid of it, w/e)
- _events.PublishOnUIThread(new ChangeBitmap(bitmap));
+ overlayModel.Update();
+ bitmap = bitmap != null
+ ? overlayModel.GenerateBitmap(bitmap)
+ : overlayModel.GenerateBitmap();
}
+
+ if (bitmap == null)
+ return;
+
+ // Fill the bitmap's background with blackness to avoid trailing colors on some keyboards
+ using (var g = Graphics.FromImage(bitmap))
+ {
+ var preFix = (Bitmap)bitmap.Clone();
+ g.Clear(Color.Black);
+ g.DrawImage(preFix, 0, 0);
+ }
+
+ // If it exists, send bitmap to the device
+ _keyboardManager.ActiveKeyboard?.DrawBitmap(bitmap);
+
+ // debugging TODO: Disable when window isn't shown (in Debug VM, or get rid of it, w/e)
+ _events.PublishOnUIThread(new ChangeBitmap(bitmap));
}
}
}
diff --git a/Artemis/Artemis/Modules/Effects/Debug/DebugEffectModel.cs b/Artemis/Artemis/Modules/Effects/Debug/DebugEffectModel.cs
index d8e6fc79f..317b99b53 100644
--- a/Artemis/Artemis/Modules/Effects/Debug/DebugEffectModel.cs
+++ b/Artemis/Artemis/Modules/Effects/Debug/DebugEffectModel.cs
@@ -35,13 +35,8 @@ namespace Artemis.Modules.Effects.Debug
KeyboardRectangle = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0, 0, new List
{
- Color.Red,
- Color.OrangeRed,
- Color.Yellow,
- Color.Green,
- Color.Blue,
- Color.Purple,
- Color.DeepPink
+ Color.FromArgb(0, 226, 190),
+ Color.FromArgb(0, 208, 255)
}, LinearGradientMode.Horizontal);
Initialized = true;
diff --git a/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs b/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs
index dec3ef5ec..25e8c3516 100644
--- a/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs
+++ b/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs
@@ -1,5 +1,4 @@
-using System;
-using System.ComponentModel;
+using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using Artemis.InjectionFactories;
@@ -16,7 +15,6 @@ namespace Artemis.ViewModels.Abstract
public abstract class GameViewModel : Screen
{
private GameSettings _gameSettings;
- private bool _startLoopManager;
protected GameViewModel(MainManager mainManager, GameModel gameModel, IEventAggregator events,
IProfileEditorViewModelFactory pFactory)
@@ -34,6 +32,7 @@ namespace Artemis.ViewModels.Abstract
[Inject]
public ILogger Logger { get; set; }
+
[Inject]
public ProfilePreviewModel ProfilePreviewModel { get; set; }
@@ -94,39 +93,38 @@ namespace Artemis.ViewModels.Abstract
protected override void OnActivate()
{
base.OnActivate();
- SetEditorShown(true);
-
- // OnActivate gets called at odd times, only start the LoopManager if it's been active
- // for 600ms.
- _startLoopManager = true;
- Task.Factory.StartNew(() =>
- {
- Thread.Sleep(600);
- if (MainManager.LoopManager.Running || !_startLoopManager)
- return;
-
- Logger.Debug("Starting LoopManager for profile preview");
- MainManager.LoopManager.Start();
- });
+ Task.Factory.StartNew(HandleActivationSwitch);
}
protected override void OnDeactivate(bool close)
{
base.OnDeactivate(close);
- SetEditorShown(false);
-
- _startLoopManager = false;
+ Task.Factory.StartNew(HandleActivationSwitch);
}
- public void SetEditorShown(bool enable)
+ private void HandleActivationSwitch()
{
- MainManager.EffectManager.ProfilePreviewModel = ProfilePreviewModel;
- MainManager.EffectManager.ProfilePreviewModel.SelectedProfile = enable ? ProfileEditor.SelectedProfile : null;
+ Thread.Sleep(600);
+ if (IsActive)
+ {
+ if (!MainManager.LoopManager.Running)
+ {
+ Logger.Debug("Starting LoopManager for profile preview");
+ MainManager.LoopManager.Start();
+ }
+ MainManager.EffectManager.ProfilePreviewModel = ProfilePreviewModel;
+ ProfilePreviewModel.SelectedProfile = ProfileEditor.SelectedProfile;
+ }
+ else
+ {
+ MainManager.EffectManager.ProfilePreviewModel = ProfilePreviewModel;
+ ProfilePreviewModel.SelectedProfile = null;
+ }
}
private void ProfileUpdater(object sender, PropertyChangedEventArgs e)
{
- if (e.PropertyName != "SelectedProfile")
+ if (e.PropertyName != "SelectedProfile" && IsActive)
return;
GameModel.Profile = ProfileEditor.SelectedProfile;
diff --git a/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs b/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs
index a34568039..ee4379427 100644
--- a/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs
+++ b/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs
@@ -48,7 +48,8 @@ namespace Artemis.ViewModels.Flyouts
{
get
{
- var collection = new BindableCollection(MainManager.KeyboardManager.KeyboardProviders.Select(k => k.Name));
+ var collection =
+ new BindableCollection(MainManager.KeyboardManager.KeyboardProviders.Select(k => k.Name));
collection.Insert(0, "None");
return collection;
}
@@ -70,7 +71,6 @@ namespace Artemis.ViewModels.Flyouts
get { return MainManager.ProgramEnabled; }
set
{
-
if (value)
MainManager.EnableProgram();
else
@@ -111,7 +111,8 @@ namespace Artemis.ViewModels.Flyouts
return;
_logger.Debug("Handling SelectedKeyboard change in UI");
- var keyboard = MainManager.KeyboardManager.KeyboardProviders.FirstOrDefault(k => k.Name == SelectedKeyboardProvider);
+ var keyboard = MainManager.KeyboardManager.KeyboardProviders
+ .FirstOrDefault(k => k.Name == SelectedKeyboardProvider);
if (keyboard != null)
{
MainManager.KeyboardManager.EnableKeyboard(keyboard);
@@ -119,7 +120,6 @@ namespace Artemis.ViewModels.Flyouts
}
else
MainManager.KeyboardManager.ReleaseActiveKeyboard();
-
}
public void ToggleEnabled()
diff --git a/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs b/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs
index ca1a6dccf..01e510ce8 100644
--- a/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs
+++ b/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs
@@ -212,7 +212,10 @@ namespace Artemis.ViewModels
private void LoadProfiles()
{
Profiles.Clear();
- Profiles.AddRange(ProfileProvider.GetAll(_gameModel));
+ if (_gameModel == null || ActiveKeyboard == null)
+ return;
+
+ Profiles.AddRange(ProfileProvider.GetAll(_gameModel, ActiveKeyboard));
SelectedProfile = Profiles.FirstOrDefault();
}
diff --git a/Artemis/Artemis/ViewModels/ShellViewModel.cs b/Artemis/Artemis/ViewModels/ShellViewModel.cs
index 67e0b79b9..b04887ff6 100644
--- a/Artemis/Artemis/ViewModels/ShellViewModel.cs
+++ b/Artemis/Artemis/ViewModels/ShellViewModel.cs
@@ -10,10 +10,12 @@ namespace Artemis.ViewModels
{
private readonly BaseViewModel[] _viewModels;
- public ShellViewModel(BaseViewModel[] viewModels, IKernel kernel)
+ public ShellViewModel(IKernel kernel, IEventAggregator events, BaseViewModel[] viewModels)
{
_viewModels = viewModels;
+ events.Subscribe(this);
+
// Setup UI
DisplayName = "Artemis";
Flyouts = new BindableCollection
diff --git a/Artemis/Artemis/ViewModels/WelcomeViewModel.cs b/Artemis/Artemis/ViewModels/WelcomeViewModel.cs
index 9b91abe16..4d8f23524 100644
--- a/Artemis/Artemis/ViewModels/WelcomeViewModel.cs
+++ b/Artemis/Artemis/ViewModels/WelcomeViewModel.cs
@@ -1,9 +1,9 @@
using System.Diagnostics;
-using Caliburn.Micro;
+using Artemis.ViewModels.Abstract;
namespace Artemis.ViewModels
{
- public sealed class WelcomeViewModel : Screen
+ public sealed class WelcomeViewModel : BaseViewModel
{
public WelcomeViewModel()
{