diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index ae8690d13..198390572 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -318,7 +318,7 @@ - + @@ -611,7 +611,6 @@ - DebugView.xaml @@ -687,6 +686,7 @@ Code + diff --git a/Artemis/Artemis/DeviceProviders/CoolerMaster/MasterkeysProL.cs b/Artemis/Artemis/DeviceProviders/CoolerMaster/MasterkeysProL.cs index a5cd4bb66..dc9873fdf 100644 --- a/Artemis/Artemis/DeviceProviders/CoolerMaster/MasterkeysProL.cs +++ b/Artemis/Artemis/DeviceProviders/CoolerMaster/MasterkeysProL.cs @@ -1,9 +1,10 @@ using System.Drawing; -using System.Drawing.Imaging; -using System.Runtime.InteropServices; +using System.Linq; +using System.Threading; using System.Windows; using System.Windows.Forms; using Artemis.DeviceProviders.CoolerMaster.Utilities; +using Artemis.DeviceProviders.Logitech.Utilities; using Artemis.Properties; using Artemis.Utilities; @@ -11,6 +12,8 @@ namespace Artemis.DeviceProviders.CoolerMaster { public class MasterkeysProL : KeyboardProvider { + private bool _hasControl; + public MasterkeysProL() { Name = "CM Masterkeys Pro L"; @@ -22,76 +25,62 @@ namespace Artemis.DeviceProviders.CoolerMaster Height = 6; Width = 22; - // TODO - PreviewSettings = new PreviewSettings(665, 175, new Thickness(0, -15, 0, 0), Resources.blackwidow); + + PreviewSettings = new PreviewSettings(670, 189, new Thickness(-2, -5, 0, 0), Resources.masterkeys_pro_l); } public override void Disable() { - CmSdk.EnableLedControl(false); + if (_hasControl) + { + CmSdk.EnableLedControl(false); + Thread.Sleep(500); + } + _hasControl = false; } public override bool CanEnable() { - return true; + CmSdk.SetControlDevice(DEVICE_INDEX.DEV_MKeys_L); + + // Doesn't seem reliable but better than nothing I suppose + return CmSdk.IsDevicePlug(); } public override void Enable() { CmSdk.SetControlDevice(DEVICE_INDEX.DEV_MKeys_L); + + _hasControl = true; CmSdk.EnableLedControl(true); } public override void DrawBitmap(Bitmap bitmap) { + // Resize the bitmap using (var b = ImageUtilities.ResizeImage(bitmap, Width, Height)) { + // Create an empty matrix var matrix = new COLOR_MATRIX {KeyColor = new KEY_COLOR[Height, Width]}; + + // Map the bytes to the matix for (var x = 0; x < Width; x++) { for (var y = 0; y < Height; y++) { - var color = b.GetPixel(x, y); - matrix.KeyColor[y, x] = new KEY_COLOR(color.R, color.G, color.B); + var c = b.GetPixel(x, y); + matrix.KeyColor[y, x] = new KEY_COLOR(c.R, c.G, c.B); } } + + // Send the matrix to the keyboard CmSdk.SetAllLedColor(matrix); } } public override KeyMatch? GetKeyPosition(Keys keyCode) { - return null; - } - - private static byte[,,] BitmapToBytes(Bitmap bitmap) - { - BitmapData bitmapData = - bitmap.LockBits(new Rectangle(new System.Drawing.Point(), bitmap.Size), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); - byte[] bitmapBytes; - var stride = bitmapData.Stride; - try - { - int byteCount = bitmapData.Stride * bitmap.Height; - bitmapBytes = new byte[byteCount]; - Marshal.Copy(bitmapData.Scan0, bitmapBytes, 0, byteCount); - } - finally - { - bitmap.UnlockBits(bitmapData); - } - byte[,,] result = new byte[3, bitmap.Width, bitmap.Height]; - for (int k = 0; k < 3; k++) - { - for (int i = 0; i < bitmap.Width; i++) - { - for (int j = 0; j < bitmap.Height; j++) - { - result[k, i, j] = bitmapBytes[j * stride + i * 3 + k]; - } - } - } - return result; + return KeyMap.QwertyLayout.FirstOrDefault(k => k.KeyCode == keyCode); } } } \ No newline at end of file diff --git a/Artemis/Artemis/DeviceProviders/CoolerMaster/Utilities/CMSDK.cs b/Artemis/Artemis/DeviceProviders/CoolerMaster/Utilities/CMSDK.cs index a8621a27f..4283e412f 100644 --- a/Artemis/Artemis/DeviceProviders/CoolerMaster/Utilities/CMSDK.cs +++ b/Artemis/Artemis/DeviceProviders/CoolerMaster/Utilities/CMSDK.cs @@ -2,7 +2,6 @@ namespace Artemis.DeviceProviders.CoolerMaster.Utilities { - public struct KEY_COLOR { public byte r; @@ -17,12 +16,9 @@ namespace Artemis.DeviceProviders.CoolerMaster.Utilities } } - // set up/save the whole LED color structure - public struct COLOR_MATRIX { - [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 132)] - public KEY_COLOR[,] KeyColor; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 132)] public KEY_COLOR[,] KeyColor; } //Enumeration of device list @@ -45,15 +41,52 @@ namespace Artemis.DeviceProviders.CoolerMaster.Utilities public static class CmSdk { + /// + /// Sets the control device which all following actions are targetted to + /// + /// [DllImport("lib\\SDKDLL ", CallingConvention = CallingConvention.Cdecl)] public static extern void SetControlDevice(DEVICE_INDEX devIndex); + /// + /// Obtain current device layout + /// + /// + [DllImport("lib\\SDKDLL ", CallingConvention = CallingConvention.Cdecl)] + public static extern LAYOUT_KEYBOARD GetDeviceLayout(); + + /// + /// Verify if the currently conrolled device is plugged in + /// + /// + [DllImport("lib\\SDKDLL ", CallingConvention = CallingConvention.Cdecl)] + public static extern bool IsDevicePlug(); + + /// + /// Enables led control on the currently controlled device + /// + /// + /// [DllImport("lib\\SDKDLL ", CallingConvention = CallingConvention.Cdecl)] public static extern bool EnableLedControl(bool bEnable); + /// + /// Sets the LED of the currently controlled device + /// + /// + /// + /// + /// + /// + /// [DllImport("lib\\SDKDLL ", CallingConvention = CallingConvention.Cdecl)] public static extern bool SetLedColor(int iRow, int iColumn, byte r, byte g, byte b); + /// + /// Sets all LEDS using the given color matrix + /// + /// + /// [DllImport("lib\\SDKDLL ", CallingConvention = CallingConvention.Cdecl)] public static extern bool SetAllLedColor(COLOR_MATRIX colorMatrix); } diff --git a/Artemis/Artemis/DeviceProviders/Logitech/LogitechKeyboard.cs b/Artemis/Artemis/DeviceProviders/Logitech/LogitechKeyboard.cs index a4f65af0b..3fb2bfd0f 100644 --- a/Artemis/Artemis/DeviceProviders/Logitech/LogitechKeyboard.cs +++ b/Artemis/Artemis/DeviceProviders/Logitech/LogitechKeyboard.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Windows; using Artemis.DeviceProviders.Logitech.Utilities; +using Artemis.Utilities; using Artemis.Utilities.DataReaders; using Microsoft.Win32; diff --git a/Artemis/Artemis/DeviceProviders/Logitech/Utilities/OrionUtilities.cs b/Artemis/Artemis/DeviceProviders/Logitech/Utilities/OrionUtilities.cs index f39d7a27e..736794cca 100644 --- a/Artemis/Artemis/DeviceProviders/Logitech/Utilities/OrionUtilities.cs +++ b/Artemis/Artemis/DeviceProviders/Logitech/Utilities/OrionUtilities.cs @@ -153,7 +153,7 @@ namespace Artemis.DeviceProviders.Logitech.Utilities { if (b.Width > 21 || b.Height > 6) b = ResizeImage(b, 21, 6); - + var rect = new Rectangle(0, 0, b.Width, b.Height); var bitmapData = b.LockBits(rect, ImageLockMode.ReadWrite, b.PixelFormat); @@ -202,10 +202,16 @@ namespace Artemis.DeviceProviders.Logitech.Utilities { graphics.CompositingMode = CompositingMode.SourceCopy; graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.NearestNeighbor; + graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + // TODO: Make configurable + // Prevents light bleed + graphics.InterpolationMode = InterpolationMode.NearestNeighbor; + // Soft/semi-transparent keys + //graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + using (var wrapMode = new ImageAttributes()) { wrapMode.SetWrapMode(WrapMode.TileFlipXY); diff --git a/Artemis/Artemis/DeviceProviders/Razer/Utilities/RazerUtilities.cs b/Artemis/Artemis/DeviceProviders/Razer/Utilities/RazerUtilities.cs index 2ec0ebd43..44c7ae96a 100644 --- a/Artemis/Artemis/DeviceProviders/Razer/Utilities/RazerUtilities.cs +++ b/Artemis/Artemis/DeviceProviders/Razer/Utilities/RazerUtilities.cs @@ -10,19 +10,21 @@ namespace Artemis.DeviceProviders.Razer.Utilities public static Custom BitmapColorArray(Bitmap b, int height, int width) { var keyboardGrid = Custom.Create(); - if (b.Width > width || b.Height > height) - b = ImageUtilities.ResizeImage(b, width, height); - - for (var y = 0; y < b.Height; y++) + // Resize the bitmap + using (b = ImageUtilities.ResizeImage(b, width, height)) { + // Map the bytes to the grid for (var x = 0; x < b.Width; x++) { - var pixel = b.GetPixel(x, y); - keyboardGrid[y, x] = new Color(pixel.R, pixel.G, pixel.B); + for (var y = 0; y < b.Height; y++) + { + var c = b.GetPixel(x, y); + keyboardGrid[y, x] = new Color(c.R, c.G, c.B); + } } - } - return keyboardGrid; + return keyboardGrid; + } } } } \ No newline at end of file diff --git a/Artemis/Artemis/InjectionModules/BaseModules.cs b/Artemis/Artemis/InjectionModules/BaseModules.cs index cbe1f7980..cdd51407f 100644 --- a/Artemis/Artemis/InjectionModules/BaseModules.cs +++ b/Artemis/Artemis/InjectionModules/BaseModules.cs @@ -15,7 +15,6 @@ namespace Artemis.InjectionModules { // ViewModels Bind().ToSelf().InSingletonScope(); - Bind().ToSelf().InSingletonScope(); Bind().ToSelf(); Bind().ToSelf(); Bind().ToSelf().InSingletonScope(); diff --git a/Artemis/Artemis/Managers/DeviceManager.cs b/Artemis/Artemis/Managers/DeviceManager.cs index 362f5cc11..bc79efdb1 100644 --- a/Artemis/Artemis/Managers/DeviceManager.cs +++ b/Artemis/Artemis/Managers/DeviceManager.cs @@ -73,7 +73,7 @@ namespace Artemis.Managers public async void EnableKeyboard(KeyboardProvider keyboardProvider) { if (keyboardProvider == null) - throw new ArgumentNullException(nameof(keyboardProvider)); + return; if (ChangingKeyboard || (ActiveKeyboard?.Name == keyboardProvider.Name)) return; diff --git a/Artemis/Artemis/Managers/LoopManager.cs b/Artemis/Artemis/Managers/LoopManager.cs index df5c7b701..631017882 100644 --- a/Artemis/Artemis/Managers/LoopManager.cs +++ b/Artemis/Artemis/Managers/LoopManager.cs @@ -177,6 +177,9 @@ namespace Artemis.Managers { public RenderFrame(KeyboardProvider keyboard) { + if (keyboard == null) + return; + KeyboardBitmap = keyboard.KeyboardBitmap(4); KeyboardBitmap.SetResolution(96, 96); @@ -222,10 +225,10 @@ namespace Artemis.Managers public void Dispose() { - KeyboardBitmap.Dispose(); - MouseBitmap.Dispose(); - HeadsetBitmap.Dispose(); - GenericBitmap.Dispose(); + KeyboardBitmap?.Dispose(); + MouseBitmap?.Dispose(); + HeadsetBitmap?.Dispose(); + GenericBitmap?.Dispose(); } } } \ No newline at end of file diff --git a/Artemis/Artemis/Properties/Resources.Designer.cs b/Artemis/Artemis/Properties/Resources.Designer.cs index 207ddd094..318b52e6b 100644 --- a/Artemis/Artemis/Properties/Resources.Designer.cs +++ b/Artemis/Artemis/Properties/Resources.Designer.cs @@ -328,6 +328,16 @@ namespace Artemis.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap masterkeys_pro_l { + get { + object obj = ResourceManager.GetObject("masterkeys_pro_l", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/Artemis/Artemis/Properties/Resources.resx b/Artemis/Artemis/Properties/Resources.resx index 44eae2ca5..b2b934454 100644 --- a/Artemis/Artemis/Properties/Resources.resx +++ b/Artemis/Artemis/Properties/Resources.resx @@ -214,4 +214,7 @@ ..\Resources\ambilight.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\Keyboards\masterkeys-pro-l.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/Artemis/Artemis/Resources/Keyboards/masterkeys-pro-l.png b/Artemis/Artemis/Resources/Keyboards/masterkeys-pro-l.png new file mode 100644 index 000000000..4658fe7bd Binary files /dev/null and b/Artemis/Artemis/Resources/Keyboards/masterkeys-pro-l.png differ diff --git a/Artemis/Artemis/Services/MetroDialogService.cs b/Artemis/Artemis/Services/MetroDialogService.cs index c40f76583..dc52e96dd 100644 --- a/Artemis/Artemis/Services/MetroDialogService.cs +++ b/Artemis/Artemis/Services/MetroDialogService.cs @@ -40,8 +40,8 @@ namespace Artemis.Services Execute.OnUIThread(() => { - window = Application.Current.Windows.OfType().FirstOrDefault(w => w.IsActive) ?? - Application.Current.Windows.OfType().FirstOrDefault(); + window = Application.Current.Windows.OfType() + .FirstOrDefault(w => w.IsActive && w.IsVisible); }); return window; diff --git a/Artemis/Artemis/Utilities/ImageUtilities.cs b/Artemis/Artemis/Utilities/ImageUtilities.cs index 3326e3253..2984b1a6c 100644 --- a/Artemis/Artemis/Utilities/ImageUtilities.cs +++ b/Artemis/Artemis/Utilities/ImageUtilities.cs @@ -1,9 +1,12 @@ using System.Drawing; using System.Drawing.Imaging; using System.IO; +using System.Runtime.InteropServices; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; +using PixelFormat = System.Drawing.Imaging.PixelFormat; +using Point = System.Drawing.Point; namespace Artemis.Utilities { diff --git a/Artemis/Artemis/Utilities/Updater.cs b/Artemis/Artemis/Utilities/Updater.cs index 31555b81d..0c856cfd9 100644 --- a/Artemis/Artemis/Utilities/Updater.cs +++ b/Artemis/Artemis/Utilities/Updater.cs @@ -56,7 +56,7 @@ namespace Artemis.Utilities /// /// The dialog service to use for progress and result dialogs /// - public static async Task CheckChangelog(MetroDialogService dialogService) + public static async void CheckChangelog(MetroDialogService dialogService) { var settings = SettingsProvider.Load(); var currentVersion = Assembly.GetExecutingAssembly().GetName().Version; diff --git a/Artemis/Artemis/ViewModels/ShellViewModel.cs b/Artemis/Artemis/ViewModels/ShellViewModel.cs index fd56ee14c..de8d7c5de 100644 --- a/Artemis/Artemis/ViewModels/ShellViewModel.cs +++ b/Artemis/Artemis/ViewModels/ShellViewModel.cs @@ -1,11 +1,18 @@ using System; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using System.Windows; +using Artemis.DAL; +using Artemis.Events; using Artemis.Managers; using Artemis.Services; +using Artemis.Settings; +using Artemis.Utilities; using Artemis.ViewModels.Abstract; using Artemis.ViewModels.Flyouts; using Caliburn.Micro; +using Hardcodet.Wpf.TaskbarNotification; using MahApps.Metro.Controls; using Ninject; @@ -14,52 +21,130 @@ namespace Artemis.ViewModels public sealed class ShellViewModel : Conductor.Collection.OneActive { private readonly IKernel _kernel; + private string _activeIcon; + private bool _checked; + private bool _enabled; + private string _toggleText; + private bool _exiting; public ShellViewModel(IKernel kernel, MainManager mainManager, MetroDialogService metroDialogService, FlyoutSettingsViewModel flyoutSettings) { _kernel = kernel; + MainManager = mainManager; + MetroDialogService = metroDialogService; - // Setup UI DisplayName = "Artemis"; - + GeneralSettings = SettingsProvider.Load(); Flyouts = new BindableCollection { flyoutSettings }; + MainManager.OnEnabledChangedEvent += (sender, args) => Enabled = args.Enabled; - MainManager = mainManager; - MetroDialogService = metroDialogService; - MainManager.EnableProgram(); + // This gets updated automatically but during startup lets quickly preset it + Enabled = GeneralSettings.Suspended; } - public SystemTrayViewModel SystemTrayViewModel { get; set; } + protected override void OnViewReady(object view) + { + base.OnViewReady(view); + + Task.Run(() => StartupHide()); + } + + private void StartupHide() + { + // TODO: This is probably an awful idea. I can't reliably hook into the view being ready to be hidden + Thread.Sleep(500); + + if (GeneralSettings.ShowOnStartup) + ShowWindow(); + else + HideWindow(); + + if (!GeneralSettings.Suspended) + MainManager.EnableProgram(); + } + + public Mutex Mutex { get; set; } public MainManager MainManager { get; set; } public MetroDialogService MetroDialogService { get; set; } public IObservableCollection Flyouts { get; set; } - + public GeneralSettings GeneralSettings { get; set; } private MetroWindow Window => (MetroWindow) GetView(); + public bool CanShowWindow => Window != null && (Window != null || !Window.IsVisible); + public bool CanHideWindow => Window != null && Window.IsVisible; + + public bool Enabled + { + get { return _enabled; } + set + { + if (value == _enabled) return; + _enabled = value; + + ToggleText = _enabled ? "Disable Artemis" : "Enable Artemis"; + ActiveIcon = _enabled ? "../Resources/logo.ico" : "../Resources/logo-disabled.ico"; + NotifyOfPropertyChange(() => Enabled); + } + } + + public string ActiveIcon + { + get { return _activeIcon; } + set + { + _activeIcon = value; + NotifyOfPropertyChange(); + } + } + + public string ToggleText + { + get { return _toggleText; } + set + { + if (value == _toggleText) return; + _toggleText = value; + NotifyOfPropertyChange(() => ToggleText); + } + } + public override void CanClose(Action callback) { - if (Window.IsVisible) + if (CanHideWindow) HideWindow(); - else + else if (!_exiting) ShowWindow(); - // ShellView is a strong and independent view who won't let herself get closed by the likes of anyone! - callback(false); + // Only close if ExitApplication was called + callback(_exiting); } - public bool CanShowWindow => !Window.IsVisible; - public bool CanHideWindow => Window.IsVisible; - public void ShowWindow() { - if (!Window.IsVisible) - Window.Show(); + if (CanShowWindow) + Window?.Dispatcher.Invoke(() => + { + Window.Show(); + Window.Activate(); + }); + + GeneralSettings.ApplyTheme(); + + // Show certain dialogs if needed + CheckKeyboardState(); + CheckDuplicateInstances(); + Updater.CheckChangelog(MetroDialogService); + + var vms = _kernel.GetAll().ToList(); + Items.Clear(); + Items.AddRange(vms); + ActivateItem(vms.FirstOrDefault()); NotifyOfPropertyChange(() => CanShowWindow); NotifyOfPropertyChange(() => CanHideWindow); @@ -67,26 +152,44 @@ namespace Artemis.ViewModels public void HideWindow() { - if (Window.IsVisible) - Window.Hide(); + if (CanHideWindow) + Window?.Dispatcher.Invoke(() => { Window.Hide(); }); + Items.Clear(); NotifyOfPropertyChange(() => CanShowWindow); NotifyOfPropertyChange(() => CanHideWindow); + + // Force a GC since the UI releases a lot of resources + GC.Collect(); } - protected override void OnActivate() + public void ToggleEnabled() { - base.OnActivate(); - Items.Clear(); - - var vms = _kernel.GetAll(); - Items.AddRange(vms); + if (Enabled) + MainManager.DisableProgram(); + else + MainManager.EnableProgram(); } - protected override void OnDeactivate(bool close) + public void ExitApplication() { - base.OnDeactivate(close); - Items.Clear(); + MainManager.Dispose(); + + try + { + var icon = (TaskbarIcon) Window.FindResource("SystemTrayIcon"); + icon.Dispose(); + } + catch (Exception) + { + //ignored + } + + _exiting = true; + + // TODO: CoolerMaster SDK is freezing Artemis on shutdown, dunno what to do about it yet + System.Diagnostics.Process.GetCurrentProcess().Kill(); + // Application.Current.Shutdown(); } public void Settings() @@ -98,5 +201,42 @@ namespace Artemis.ViewModels { Flyouts.First().IsOpen = false; } + + private async void CheckKeyboardState() + { + var dialog = await MetroDialogService.ShowProgressDialog("Enabling keyboard", + "Artemis is still busy trying to enable your last used keyboard. " + + "Please wait while the process completes"); + dialog.SetIndeterminate(); + + while (MainManager.DeviceManager.ChangingKeyboard) + await Task.Delay(10); + + try + { + await dialog.CloseAsync(); + } + catch (InvalidOperationException) + { + // Occurs when window is closed again, can't find a proper check for this + } + } + + private void CheckDuplicateInstances() + { + if (_checked) + return; + _checked = true; + + bool aIsNewInstance; + Mutex = new Mutex(true, "ArtemisMutex", out aIsNewInstance); + if (aIsNewInstance) + return; + + MetroDialogService.ShowMessageBox("Multiple instances found", + "It looks like there are multiple running instances of Artemis. " + + "This can cause issues, especially with CS:GO and Dota2. " + + "If so, please make sure Artemis isn't already running"); + } } } \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/SystemTrayViewModel.cs b/Artemis/Artemis/ViewModels/SystemTrayViewModel.cs deleted file mode 100644 index b5adfcf72..000000000 --- a/Artemis/Artemis/ViewModels/SystemTrayViewModel.cs +++ /dev/null @@ -1,200 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using System.Windows; -using Artemis.DAL; -using Artemis.Events; -using Artemis.Managers; -using Artemis.Services; -using Artemis.Settings; -using Artemis.Utilities; -using Caliburn.Micro; - -namespace Artemis.ViewModels -{ - public class SystemTrayViewModel : Screen - { - private readonly WindowService _windowService; - private ShellViewModel _shellViewModel; - private string _activeIcon; - private bool _checked; - private bool _enabled; - private string _toggleText; - - public SystemTrayViewModel(WindowService windowService, MetroDialogService dialogService, MainManager mainManager) - { - _windowService = windowService; - - DialogService = dialogService; - MainManager = mainManager; - - MainManager.EnableProgram(); - MainManager.OnEnabledChangedEvent += MainManagerOnOnEnabledChangedEvent; - - var generalSettings = SettingsProvider.Load(); - Enabled = !generalSettings.Suspended; - if (generalSettings.ShowOnStartup) - ShowWindow(); - } - - public MetroDialogService DialogService { get; set; } - - public MainManager MainManager { get; set; } - - public bool CanShowWindow - { - get - { - if (_shellViewModel == null) - return true; - return !_shellViewModel.IsActive; - } - } - - public bool CanHideWindow => (_shellViewModel?.IsActive == true) && !MainManager.DeviceManager.ChangingKeyboard; - public bool CanToggleEnabled => !MainManager.DeviceManager.ChangingKeyboard; - - public bool Enabled - { - get { return _enabled; } - set - { - if (value == _enabled) return; - _enabled = value; - - ToggleText = _enabled ? "Disable Artemis" : "Enable Artemis"; - ActiveIcon = _enabled ? "../Resources/logo.ico" : "../Resources/logo-disabled.ico"; - NotifyOfPropertyChange(() => Enabled); - } - } - - public string ActiveIcon - { - get { return _activeIcon; } - set - { - _activeIcon = value; - NotifyOfPropertyChange(); - } - } - - public string ToggleText - { - get { return _toggleText; } - set - { - if (value == _toggleText) return; - _toggleText = value; - NotifyOfPropertyChange(() => ToggleText); - } - } - - public Mutex Mutex { get; set; } - - private void MainManagerOnOnEnabledChangedEvent(object sender, EnabledChangedEventArgs e) - { - Enabled = e.Enabled; - } - - public void ToggleEnabled() - { - if (Enabled) - MainManager.DisableProgram(); - else - MainManager.EnableProgram(); - } - - protected override void OnActivate() - { - base.OnActivate(); - - NotifyOfPropertyChange(() => CanShowWindow); - NotifyOfPropertyChange(() => CanHideWindow); - } - - public void ShowWindow() - { - if (!CanShowWindow) - return; - - // manually show the next window view-model - _shellViewModel = _windowService.ShowWindow(); - - NotifyOfPropertyChange(() => CanShowWindow); - NotifyOfPropertyChange(() => CanHideWindow); - - SettingsProvider.Load().ApplyTheme(); - - // Show certain dialogs if needed - CheckKeyboardState(); - CheckDuplicateInstances(); - Updater.CheckChangelog(DialogService); - } - - private void CheckDuplicateInstances() - { - if (_checked) - return; - _checked = true; - - bool aIsNewInstance; - Mutex = new Mutex(true, "ArtemisMutex", out aIsNewInstance); - if (aIsNewInstance) - return; - - DialogService.ShowMessageBox("Multiple instances found", - "It looks like there are multiple running instances of Artemis. " + - "This can cause issues, especially with CS:GO and Dota2. " + - "If so, please make sure Artemis isn't already running"); - } - - private async void CheckKeyboardState() - { - while (!_shellViewModel.IsActive) - await Task.Delay(200); - - NotifyOfPropertyChange(() => CanHideWindow); - NotifyOfPropertyChange(() => CanToggleEnabled); - - var dialog = await DialogService.ShowProgressDialog("Enabling keyboard", - "Artemis is still busy trying to enable your last used keyboard. " + - "Please wait while the process completes"); - dialog.SetIndeterminate(); - - while (MainManager.DeviceManager.ChangingKeyboard) - await Task.Delay(10); - - NotifyOfPropertyChange(() => CanHideWindow); - NotifyOfPropertyChange(() => CanToggleEnabled); - - try - { - await dialog.CloseAsync(); - } - catch (InvalidOperationException) - { - // Occurs when window is closed again, can't find a proper check for this - } - } - - public void HideWindow() - { - if (!CanHideWindow) - return; - - _shellViewModel.TryClose(); - - NotifyOfPropertyChange(() => CanShowWindow); - NotifyOfPropertyChange(() => CanHideWindow); - - // Force a GC since the UI releases a lot of resources - GC.Collect(); - } - - public void ExitApplication() - { - MainManager.Dispose(); - Application.Current.Shutdown(); - } - } -} \ No newline at end of file