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

Smoothed out the way changing keyboards works in combination with profiles.

This commit is contained in:
SpoinkyNL 2016-05-11 12:14:32 +02:00
parent b9a55b896a
commit aafd361a6b
13 changed files with 174 additions and 146 deletions

View File

@ -4,6 +4,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Xml.Serialization; using System.Xml.Serialization;
using Artemis.KeyboardProviders;
using Artemis.Models; using Artemis.Models;
using Artemis.Models.Profiles; using Artemis.Models.Profiles;
@ -27,10 +28,16 @@ namespace Artemis.DAL
/// Get all profiles matching the provided game /// Get all profiles matching the provided game
/// </summary> /// </summary>
/// <param name="game">The game to match</param> /// <param name="game">The game to match</param>
/// <param name="keyboard">The keyboard to match</param>
/// <returns>All profiles matching the provided game</returns> /// <returns>All profiles matching the provided game</returns>
public static List<ProfileModel> GetAll(GameModel game) public static List<ProfileModel> 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();
} }
/// <summary> /// <summary>
@ -40,6 +47,8 @@ namespace Artemis.DAL
/// <param name="prof">The profile to add or update</param> /// <param name="prof">The profile to add or update</param>
public static void AddOrUpdate(ProfileModel prof) 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)) 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"); throw new ArgumentException("Profile is invalid. Name, GameName and KeyboardName are required");

View File

@ -1,12 +1,16 @@
namespace Artemis.Events using Artemis.KeyboardProviders;
namespace Artemis.Events
{ {
public class ActiveKeyboardChanged 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; }
} }
} }

View File

@ -17,6 +17,7 @@ namespace Artemis.InjectionModules
Bind<IScreen>().To<ShellViewModel>().InSingletonScope(); Bind<IScreen>().To<ShellViewModel>().InSingletonScope();
Bind<IProfileEditorViewModelFactory>().ToFactory(); Bind<IProfileEditorViewModelFactory>().ToFactory();
Bind<BaseViewModel>().To<WelcomeViewModel>().InSingletonScope();
Bind<BaseViewModel>().To<EffectsViewModel>().InSingletonScope(); Bind<BaseViewModel>().To<EffectsViewModel>().InSingletonScope();
Bind<BaseViewModel>().To<GamesViewModel>().InSingletonScope(); Bind<BaseViewModel>().To<GamesViewModel>().InSingletonScope();
Bind<BaseViewModel>().To<OverlaysViewModel>().InSingletonScope(); Bind<BaseViewModel>().To<OverlaysViewModel>().InSingletonScope();

View File

@ -123,17 +123,10 @@ namespace Artemis.KeyboardProviders.Corsair
/// <param name="bitmap"></param> /// <param name="bitmap"></param>
public override void DrawBitmap(Bitmap bitmap) public override void DrawBitmap(Bitmap bitmap)
{ {
var fixedBmp = new Bitmap(bitmap.Width, bitmap.Height); var image = ImageUtilities.ResizeImage(bitmap, Width, Height);
using (var g = Graphics.FromImage(fixedBmp))
{
g.Clear(Color.Black);
g.DrawImage(bitmap, 0, 0);
}
var fixedImage = ImageUtilities.ResizeImage(fixedBmp, Width, Height);
var brush = new ImageBrush var brush = new ImageBrush
{ {
Image = fixedImage Image = image
}; };
_keyboard.Brush = brush; _keyboard.Brush = brush;

View File

@ -79,6 +79,9 @@ namespace Artemis.Managers
/// <param name="e"></param> /// <param name="e"></param>
private void SetupProfilePreview(object sender, ElapsedEventArgs e) private void SetupProfilePreview(object sender, ElapsedEventArgs e)
{ {
if (_keyboardManager.ChangingKeyboard)
return;
// Make sure the preview model should still be active // Make sure the preview model should still be active
if (ActiveEffect is ProfilePreviewModel) if (ActiveEffect is ProfilePreviewModel)
{ {
@ -133,41 +136,39 @@ namespace Artemis.Managers
if (effectModel is OverlayModel) if (effectModel is OverlayModel)
throw new ArgumentException("Can't set an Overlay effect as the active effect"); 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) wasNull = true;
{ ActiveEffect = effectModel;
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 lock (ActiveEffect)
var gameModel = effectModel as GameModel; {
if (gameModel != null) if (!wasNull)
if (!gameModel.Enabled) ActiveEffect.Dispose();
return;
var wasNull = false; ActiveEffect = effectModel;
if (ActiveEffect == null) ActiveEffect.Enable();
{
wasNull = true;
ActiveEffect = effectModel;
}
if (!wasNull)
ActiveEffect.Dispose();
ActiveEffect = effectModel; if (ActiveEffect is GameModel || ActiveEffect is ProfilePreviewModel)
ActiveEffect.Enable(); return;
if (ActiveEffect is GameModel || ActiveEffect is ProfilePreviewModel) // Non-game effects are stored as the new LastEffect.
return; 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) if (loopManager != null && !loopManager.Running)
@ -185,18 +186,19 @@ namespace Artemis.Managers
/// </summary> /// </summary>
public void ClearEffect() public void ClearEffect()
{ {
lock (_keyboardManager) if (ActiveEffect == null)
{ return;
lock (this)
{
ActiveEffect.Dispose();
ActiveEffect = null;
General.Default.LastEffect = null; lock (ActiveEffect)
General.Default.Save(); {
} ActiveEffect.Dispose();
ActiveEffect = null;
General.Default.LastEffect = null;
General.Default.Save();
} }
_logger.Debug("Cleared active effect"); _logger.Debug("Cleared active effect");
} }

View File

@ -18,7 +18,6 @@ namespace Artemis.Managers
{ {
private readonly IEventAggregator _events; private readonly IEventAggregator _events;
private readonly ILogger _logger; private readonly ILogger _logger;
private KeyboardProvider _activeKeyboard;
public KeyboardManager(IEventAggregator events, ILogger logger, List<KeyboardProvider> keyboardProviders) public KeyboardManager(IEventAggregator events, ILogger logger, List<KeyboardProvider> keyboardProviders)
{ {
@ -36,16 +35,9 @@ namespace Artemis.Managers
public List<KeyboardProvider> KeyboardProviders { get; set; } public List<KeyboardProvider> KeyboardProviders { get; set; }
public KeyboardProvider ActiveKeyboard public KeyboardProvider ActiveKeyboard { get; set; }
{
get { return _activeKeyboard; } public bool ChangingKeyboard { get; private set; }
set
{
_activeKeyboard = value;
// Let the ViewModels know
_events.PublishOnUIThread(new ActiveKeyboardChanged(value?.Name));
}
}
/// <summary> /// <summary>
/// Enables the last keyboard according to the settings file /// Enables the last keyboard according to the settings file
@ -68,11 +60,19 @@ namespace Artemis.Managers
{ {
lock (this) lock (this)
{ {
ChangingKeyboard = true;
if (keyboardProvider == null) if (keyboardProvider == null)
throw new ArgumentNullException(nameof(keyboardProvider)); throw new ArgumentNullException(nameof(keyboardProvider));
if (ActiveKeyboard?.Name == keyboardProvider.Name) if (ActiveKeyboard?.Name == keyboardProvider.Name)
{
ChangingKeyboard = false;
return; return;
}
// Store the old keyboard so it can be used in the event we're raising later
var oldKeyboard = ActiveKeyboard;
var wasNull = false; var wasNull = false;
if (ActiveKeyboard == null) if (ActiveKeyboard == null)
@ -94,6 +94,7 @@ namespace Artemis.Managers
General.Default.LastKeyboard = null; General.Default.LastKeyboard = null;
General.Default.Save(); General.Default.Save();
_logger.Warn("Failed enabling keyboard: {0}", keyboardProvider.Name); _logger.Warn("Failed enabling keyboard: {0}", keyboardProvider.Name);
ChangingKeyboard = false;
return; return;
} }
@ -102,6 +103,9 @@ namespace Artemis.Managers
General.Default.LastKeyboard = ActiveKeyboard.Name; General.Default.LastKeyboard = ActiveKeyboard.Name;
General.Default.Save(); General.Default.Save();
ChangingKeyboard = false;
_events.PublishOnUIThread(new ActiveKeyboardChanged(oldKeyboard, ActiveKeyboard));
_logger.Debug("Enabled keyboard: {0}", keyboardProvider.Name); _logger.Debug("Enabled keyboard: {0}", keyboardProvider.Name);
} }
} }
@ -116,9 +120,17 @@ namespace Artemis.Managers
if (ActiveKeyboard == null) if (ActiveKeyboard == null)
return; return;
// Store the old keyboard so it can be used in the event we're raising later
var oldKeyboard = ActiveKeyboard;
var releaseName = ActiveKeyboard.Name; var releaseName = ActiveKeyboard.Name;
ActiveKeyboard.Disable(); ActiveKeyboard.Disable();
ActiveKeyboard = null; ActiveKeyboard = null;
General.Default.LastKeyboard = null;
General.Default.Save();
_events.PublishOnUIThread(new ActiveKeyboardChanged(oldKeyboard, null));
_logger.Debug("Released keyboard: {0}", releaseName); _logger.Debug("Released keyboard: {0}", releaseName);
} }
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Drawing;
using System.Timers; using System.Timers;
using Artemis.Events; using Artemis.Events;
using Caliburn.Micro; using Caliburn.Micro;
@ -57,7 +58,6 @@ namespace Artemis.Managers
return; return;
} }
// TODO: Deadlock maybe? I don't know what Resharper is on about
if (_effectManager.ActiveEffect == null) if (_effectManager.ActiveEffect == null)
{ {
var lastEffect = _effectManager.GetLastEffect(); var lastEffect = _effectManager.GetLastEffect();
@ -88,6 +88,18 @@ namespace Artemis.Managers
if (!Running) if (!Running)
return; 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 // Stop if no active keyboard
if (_keyboardManager.ActiveKeyboard == null) if (_keyboardManager.ActiveKeyboard == null)
{ {
@ -95,50 +107,47 @@ namespace Artemis.Managers
Stop(); Stop();
return; 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 overlayModel.Update();
if (_effectManager.ActiveEffect == null) bitmap = bitmap != null
{ ? overlayModel.GenerateBitmap(bitmap)
_logger.Debug("No active effect, stopping"); : overlayModel.GenerateBitmap();
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));
} }
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));
} }
} }
} }

View File

@ -35,13 +35,8 @@ namespace Artemis.Modules.Effects.Debug
KeyboardRectangle = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0, 0, new List<Color> KeyboardRectangle = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0, 0, new List<Color>
{ {
Color.Red, Color.FromArgb(0, 226, 190),
Color.OrangeRed, Color.FromArgb(0, 208, 255)
Color.Yellow,
Color.Green,
Color.Blue,
Color.Purple,
Color.DeepPink
}, LinearGradientMode.Horizontal); }, LinearGradientMode.Horizontal);
Initialized = true; Initialized = true;

View File

@ -1,5 +1,4 @@
using System; using System.ComponentModel;
using System.ComponentModel;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Artemis.InjectionFactories; using Artemis.InjectionFactories;
@ -16,7 +15,6 @@ namespace Artemis.ViewModels.Abstract
public abstract class GameViewModel : Screen public abstract class GameViewModel : Screen
{ {
private GameSettings _gameSettings; private GameSettings _gameSettings;
private bool _startLoopManager;
protected GameViewModel(MainManager mainManager, GameModel gameModel, IEventAggregator events, protected GameViewModel(MainManager mainManager, GameModel gameModel, IEventAggregator events,
IProfileEditorViewModelFactory pFactory) IProfileEditorViewModelFactory pFactory)
@ -34,6 +32,7 @@ namespace Artemis.ViewModels.Abstract
[Inject] [Inject]
public ILogger Logger { get; set; } public ILogger Logger { get; set; }
[Inject] [Inject]
public ProfilePreviewModel ProfilePreviewModel { get; set; } public ProfilePreviewModel ProfilePreviewModel { get; set; }
@ -94,39 +93,38 @@ namespace Artemis.ViewModels.Abstract
protected override void OnActivate() protected override void OnActivate()
{ {
base.OnActivate(); base.OnActivate();
SetEditorShown(true); Task.Factory.StartNew(HandleActivationSwitch);
// 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();
});
} }
protected override void OnDeactivate(bool close) protected override void OnDeactivate(bool close)
{ {
base.OnDeactivate(close); base.OnDeactivate(close);
SetEditorShown(false); Task.Factory.StartNew(HandleActivationSwitch);
_startLoopManager = false;
} }
public void SetEditorShown(bool enable) private void HandleActivationSwitch()
{ {
MainManager.EffectManager.ProfilePreviewModel = ProfilePreviewModel; Thread.Sleep(600);
MainManager.EffectManager.ProfilePreviewModel.SelectedProfile = enable ? ProfileEditor.SelectedProfile : null; 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) private void ProfileUpdater(object sender, PropertyChangedEventArgs e)
{ {
if (e.PropertyName != "SelectedProfile") if (e.PropertyName != "SelectedProfile" && IsActive)
return; return;
GameModel.Profile = ProfileEditor.SelectedProfile; GameModel.Profile = ProfileEditor.SelectedProfile;

View File

@ -48,7 +48,8 @@ namespace Artemis.ViewModels.Flyouts
{ {
get get
{ {
var collection = new BindableCollection<string>(MainManager.KeyboardManager.KeyboardProviders.Select(k => k.Name)); var collection =
new BindableCollection<string>(MainManager.KeyboardManager.KeyboardProviders.Select(k => k.Name));
collection.Insert(0, "None"); collection.Insert(0, "None");
return collection; return collection;
} }
@ -70,7 +71,6 @@ namespace Artemis.ViewModels.Flyouts
get { return MainManager.ProgramEnabled; } get { return MainManager.ProgramEnabled; }
set set
{ {
if (value) if (value)
MainManager.EnableProgram(); MainManager.EnableProgram();
else else
@ -111,7 +111,8 @@ namespace Artemis.ViewModels.Flyouts
return; return;
_logger.Debug("Handling SelectedKeyboard change in UI"); _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) if (keyboard != null)
{ {
MainManager.KeyboardManager.EnableKeyboard(keyboard); MainManager.KeyboardManager.EnableKeyboard(keyboard);
@ -119,7 +120,6 @@ namespace Artemis.ViewModels.Flyouts
} }
else else
MainManager.KeyboardManager.ReleaseActiveKeyboard(); MainManager.KeyboardManager.ReleaseActiveKeyboard();
} }
public void ToggleEnabled() public void ToggleEnabled()

View File

@ -212,7 +212,10 @@ namespace Artemis.ViewModels
private void LoadProfiles() private void LoadProfiles()
{ {
Profiles.Clear(); Profiles.Clear();
Profiles.AddRange(ProfileProvider.GetAll(_gameModel)); if (_gameModel == null || ActiveKeyboard == null)
return;
Profiles.AddRange(ProfileProvider.GetAll(_gameModel, ActiveKeyboard));
SelectedProfile = Profiles.FirstOrDefault(); SelectedProfile = Profiles.FirstOrDefault();
} }

View File

@ -10,10 +10,12 @@ namespace Artemis.ViewModels
{ {
private readonly BaseViewModel[] _viewModels; private readonly BaseViewModel[] _viewModels;
public ShellViewModel(BaseViewModel[] viewModels, IKernel kernel) public ShellViewModel(IKernel kernel, IEventAggregator events, BaseViewModel[] viewModels)
{ {
_viewModels = viewModels; _viewModels = viewModels;
events.Subscribe(this);
// Setup UI // Setup UI
DisplayName = "Artemis"; DisplayName = "Artemis";
Flyouts = new BindableCollection<FlyoutBaseViewModel> Flyouts = new BindableCollection<FlyoutBaseViewModel>

View File

@ -1,9 +1,9 @@
using System.Diagnostics; using System.Diagnostics;
using Caliburn.Micro; using Artemis.ViewModels.Abstract;
namespace Artemis.ViewModels namespace Artemis.ViewModels
{ {
public sealed class WelcomeViewModel : Screen public sealed class WelcomeViewModel : BaseViewModel
{ {
public WelcomeViewModel() public WelcomeViewModel()
{ {