1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-31 17:53:32 +00:00

Merge pull request #99 from SpoinkyNL/development

Update 1.1.0 - Profiles
This commit is contained in:
Robert Beekman 2016-06-08 19:32:42 +02:00
commit b11317050a
219 changed files with 16335 additions and 6576 deletions

View File

@ -5,6 +5,8 @@ VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis", "Artemis\Artemis.csproj", "{ED9997A2-E54C-4E9F-9350-62BE672C3ABE}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis", "Artemis\Artemis.csproj", "{ED9997A2-E54C-4E9F-9350-62BE672C3ABE}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Razer2Artemis", "Razer2Artemis\Razer2Artemis.vcxproj", "{39711909-C1D5-46CE-A9EA-2D561692EA47}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
CD_ROM|Any CPU = CD_ROM|Any CPU CD_ROM|Any CPU = CD_ROM|Any CPU
@ -54,6 +56,34 @@ Global
{ED9997A2-E54C-4E9F-9350-62BE672C3ABE}.SingleImage|x64.Build.0 = Release|x64 {ED9997A2-E54C-4E9F-9350-62BE672C3ABE}.SingleImage|x64.Build.0 = Release|x64
{ED9997A2-E54C-4E9F-9350-62BE672C3ABE}.SingleImage|x86.ActiveCfg = Release|x86 {ED9997A2-E54C-4E9F-9350-62BE672C3ABE}.SingleImage|x86.ActiveCfg = Release|x86
{ED9997A2-E54C-4E9F-9350-62BE672C3ABE}.SingleImage|x86.Build.0 = Release|x86 {ED9997A2-E54C-4E9F-9350-62BE672C3ABE}.SingleImage|x86.Build.0 = Release|x86
{39711909-C1D5-46CE-A9EA-2D561692EA47}.CD_ROM|Any CPU.ActiveCfg = Release|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.CD_ROM|Any CPU.Build.0 = Release|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.CD_ROM|x64.ActiveCfg = Release|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.CD_ROM|x64.Build.0 = Release|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.CD_ROM|x86.ActiveCfg = Release|Win32
{39711909-C1D5-46CE-A9EA-2D561692EA47}.CD_ROM|x86.Build.0 = Release|Win32
{39711909-C1D5-46CE-A9EA-2D561692EA47}.Debug|Any CPU.ActiveCfg = Debug|Win32
{39711909-C1D5-46CE-A9EA-2D561692EA47}.Debug|x64.ActiveCfg = Debug|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.Debug|x64.Build.0 = Debug|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.Debug|x86.ActiveCfg = Debug|Win32
{39711909-C1D5-46CE-A9EA-2D561692EA47}.Debug|x86.Build.0 = Debug|Win32
{39711909-C1D5-46CE-A9EA-2D561692EA47}.DVD-5|Any CPU.ActiveCfg = Release|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.DVD-5|Any CPU.Build.0 = Release|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.DVD-5|x64.ActiveCfg = Debug|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.DVD-5|x64.Build.0 = Debug|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.DVD-5|x86.ActiveCfg = Debug|Win32
{39711909-C1D5-46CE-A9EA-2D561692EA47}.DVD-5|x86.Build.0 = Debug|Win32
{39711909-C1D5-46CE-A9EA-2D561692EA47}.Release|Any CPU.ActiveCfg = Release|Win32
{39711909-C1D5-46CE-A9EA-2D561692EA47}.Release|x64.ActiveCfg = Release|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.Release|x64.Build.0 = Release|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.Release|x86.ActiveCfg = Release|Win32
{39711909-C1D5-46CE-A9EA-2D561692EA47}.Release|x86.Build.0 = Release|Win32
{39711909-C1D5-46CE-A9EA-2D561692EA47}.SingleImage|Any CPU.ActiveCfg = Release|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.SingleImage|Any CPU.Build.0 = Release|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.SingleImage|x64.ActiveCfg = Release|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.SingleImage|x64.Build.0 = Release|x64
{39711909-C1D5-46CE-A9EA-2D561692EA47}.SingleImage|x86.ActiveCfg = Release|Win32
{39711909-C1D5-46CE-A9EA-2D561692EA47}.SingleImage|x86.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -4,6 +4,12 @@
<configSections> <configSections>
<sectionGroup name="userSettings" <sectionGroup name="userSettings"
type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="Artemis.Modules.Effects.WindowsProfile.WindowsProfile"
type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
allowExeDefinition="MachineToLocalUser" requirePermission="false" />
<section name="Artemis.Modules.Games.Overwatch.Overwatch"
type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
allowExeDefinition="MachineToLocalUser" requirePermission="false" />
<section name="Artemis.Modules.Games.TheDivision.TheDivision" <section name="Artemis.Modules.Games.TheDivision.TheDivision"
type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
allowExeDefinition="MachineToLocalUser" requirePermission="false" /> allowExeDefinition="MachineToLocalUser" requirePermission="false" />
@ -53,6 +59,22 @@
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" /> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup> </startup>
<userSettings> <userSettings>
<Artemis.Modules.Effects.WindowsProfile.WindowsProfile>
<setting name="LastProfile" serializeAs="String">
<value>Demo (Duplicate to keep changes)</value>
</setting>
</Artemis.Modules.Effects.WindowsProfile.WindowsProfile>
<Artemis.Modules.Games.Overwatch.Overwatch>
<setting name="Enabled" serializeAs="String">
<value>True</value>
</setting>
<setting name="LastProfile" serializeAs="String">
<value>Default</value>
</setting>
<setting name="GameDirectory" serializeAs="String">
<value />
</setting>
</Artemis.Modules.Games.Overwatch.Overwatch>
<Artemis.Modules.Games.TheDivision.TheDivision> <Artemis.Modules.Games.TheDivision.TheDivision>
<setting name="Enabled" serializeAs="String"> <setting name="Enabled" serializeAs="String">
<value>True</value> <value>True</value>
@ -111,14 +133,8 @@
<setting name="Enabled" serializeAs="String"> <setting name="Enabled" serializeAs="String">
<value>True</value> <value>True</value>
</setting> </setting>
<setting name="MainColor" serializeAs="String"> <setting name="LastProfile" serializeAs="String">
<value>#FFFF5000</value> <value>Default</value>
</setting>
<setting name="SecondaryColor" serializeAs="String">
<value>#FFFF0000</value>
</setting>
<setting name="ContextualColor" serializeAs="String">
<value>False</value>
</setting> </setting>
</Artemis.Modules.Games.RocketLeague.RocketLeague> </Artemis.Modules.Games.RocketLeague.RocketLeague>
<Artemis.Settings.Offsets> <Artemis.Settings.Offsets>
@ -185,6 +201,9 @@
<setting name="LowHpEnabled" serializeAs="String"> <setting name="LowHpEnabled" serializeAs="String">
<value>True</value> <value>True</value>
</setting> </setting>
<setting name="LastProfile" serializeAs="String">
<value>Default</value>
</setting>
</Artemis.Modules.Games.CounterStrike.CounterStrike> </Artemis.Modules.Games.CounterStrike.CounterStrike>
<Artemis.Settings.CounterStrike> <Artemis.Settings.CounterStrike>
<setting name="GameDirectory" serializeAs="String"> <setting name="GameDirectory" serializeAs="String">
@ -293,6 +312,9 @@
<setting name="CheckForUpdates" serializeAs="String"> <setting name="CheckForUpdates" serializeAs="String">
<value>True</value> <value>True</value>
</setting> </setting>
<setting name="Theme" serializeAs="String">
<value>Light</value>
</setting>
</Artemis.Settings.General> </Artemis.Settings.General>
</userSettings> </userSettings>
<runtime> <runtime>
@ -321,6 +343,10 @@
<assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" /> <assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.2.0" newVersion="3.0.2.0" /> <bindingRedirect oldVersion="0.0.0.0-3.0.2.0" newVersion="3.0.2.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Castle.Core" publicKeyToken="407dd0808d44fbdc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.3.0.0" newVersion="3.3.0.0" />
</dependentAssembly>
</assemblyBinding> </assemblyBinding>
</runtime> </runtime>

View File

@ -1,7 +1,8 @@
using System; using System;
using System.Security.Principal;
using System.Windows; using System.Windows;
using System.Windows.Threading; using System.Windows.Threading;
using Artemis.Utilities; using NLog;
using WpfExceptionViewer; using WpfExceptionViewer;
namespace Artemis namespace Artemis
@ -13,14 +14,22 @@ namespace Artemis
{ {
public App() public App()
{ {
if (!GeneralHelpers.IsRunAsAdministrator()) //if (!IsRunAsAdministrator())
GeneralHelpers.RunAsAdministrator(); // GeneralHelpers.RunAsAdministrator();
InitializeComponent(); InitializeComponent();
} }
public bool DoHandle { get; set; } public bool DoHandle { get; set; }
private static bool IsRunAsAdministrator()
{
var wi = WindowsIdentity.GetCurrent();
var wp = new WindowsPrincipal(wi);
return wp.IsInRole(WindowsBuiltInRole.Administrator);
}
private void Application_Startup(object sender, StartupEventArgs e) private void Application_Startup(object sender, StartupEventArgs e)
{ {
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
@ -40,7 +49,6 @@ namespace Artemis
} }
} }
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{ {
var ex = e.ExceptionObject as Exception; var ex = e.ExceptionObject as Exception;
@ -49,6 +57,8 @@ namespace Artemis
private static ExceptionViewer GetArtemisExceptionViewer(Exception e) private static ExceptionViewer GetArtemisExceptionViewer(Exception e)
{ {
var logger = LogManager.GetCurrentClassLogger();
logger.Fatal(e, "Unhandled exception, showing dialog and shutting down.");
return new ExceptionViewer("An unexpected error occurred in Artemis.", e) return new ExceptionViewer("An unexpected error occurred in Artemis.", e)
{ {
Title = "Artemis - Exception :c", Title = "Artemis - Exception :c",

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -120,20 +120,20 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup /> <PropertyGroup />
<ItemGroup> <ItemGroup>
<Reference Include="Autofac, Version=4.0.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL"> <Reference Include="Caliburn.Micro, Version=3.0.1.0, Culture=neutral, PublicKeyToken=8e5891231f2ed21f, processorArchitecture=MSIL">
<HintPath>..\packages\Autofac.4.0.0-rc1-177\lib\net45\Autofac.dll</HintPath> <HintPath>..\packages\Caliburn.Micro.Core.3.0.1\lib\net45\Caliburn.Micro.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Caliburn.Micro, Version=2.0.2.0, Culture=neutral, PublicKeyToken=8e5891231f2ed21f, processorArchitecture=MSIL"> <Reference Include="Caliburn.Micro.Platform, Version=3.0.1.0, Culture=neutral, PublicKeyToken=8e5891231f2ed21f, processorArchitecture=MSIL">
<HintPath>..\packages\Caliburn.Micro.Core.2.0.2\lib\net45\Caliburn.Micro.dll</HintPath> <HintPath>..\packages\Caliburn.Micro.3.0.1\lib\net45\Caliburn.Micro.Platform.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Caliburn.Micro.Autofac, Version=2.0.9.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Caliburn.Micro.Platform.Core, Version=3.0.1.0, Culture=neutral, PublicKeyToken=8e5891231f2ed21f, processorArchitecture=MSIL">
<HintPath>..\packages\Caliburn.Micro.AutofacBootstrap.2.0.9-beta\lib\net40\Caliburn.Micro.Autofac.dll</HintPath> <HintPath>..\packages\Caliburn.Micro.3.0.1\lib\net45\Caliburn.Micro.Platform.Core.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Caliburn.Micro.Platform, Version=2.0.2.0, Culture=neutral, PublicKeyToken=8e5891231f2ed21f, processorArchitecture=MSIL"> <Reference Include="Castle.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\packages\Caliburn.Micro.2.0.2\lib\net45\Caliburn.Micro.Platform.dll</HintPath> <HintPath>..\packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="ColorBox, Version=1.1.0.0, Culture=neutral, PublicKeyToken=f971124b2576acfc, processorArchitecture=MSIL"> <Reference Include="ColorBox, Version=1.1.0.0, Culture=neutral, PublicKeyToken=f971124b2576acfc, processorArchitecture=MSIL">
@ -144,8 +144,12 @@
<HintPath>..\packages\Colore.4.0.0\lib\net35\Corale.Colore.dll</HintPath> <HintPath>..\packages\Colore.4.0.0\lib\net35\Corale.Colore.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="CUE.NET, Version=1.0.2.2, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="CUE.NET, Version=1.0.3.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\CUE.NET.1.0.2.2\lib\net45\CUE.NET.dll</HintPath> <HintPath>..\packages\CUE.NET.1.0.3\lib\net45\CUE.NET.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="GongSolutions.Wpf.DragDrop, Version=0.1.4.3, Culture=neutral, PublicKeyToken=d19974ea350ccea1, processorArchitecture=MSIL">
<HintPath>..\packages\gong-wpf-dragdrop.0.1.4.3\lib\net40\GongSolutions.Wpf.DragDrop.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Hardcodet.Wpf.TaskbarNotification, Version=1.0.5.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Hardcodet.Wpf.TaskbarNotification, Version=1.0.5.0, Culture=neutral, processorArchitecture=MSIL">
@ -175,8 +179,24 @@
<HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath> <HintPath>..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="Ninject, Version=3.2.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
<HintPath>..\packages\Ninject.3.2.2.0\lib\net45-full\Ninject.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Ninject.Extensions.Factory, Version=3.2.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
<HintPath>..\packages\Ninject.Extensions.Factory.3.2.1.0\lib\net45-full\Ninject.Extensions.Factory.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Ninject.Extensions.Logging, Version=3.2.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
<HintPath>..\packages\Ninject.Extensions.Logging.3.2.3.0\lib\net45-full\Ninject.Extensions.Logging.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Ninject.Extensions.Logging.NLog4, Version=3.2.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
<HintPath>..\packages\Ninject.Extensions.Logging.nlog4.3.2.3.0\lib\net45-full\Ninject.Extensions.Logging.NLog4.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL"> <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.2\lib\net45\NLog.dll</HintPath> <HintPath>..\packages\NLog.4.3.4\lib\net45\NLog.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="SharpDX, Version=3.0.2.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL"> <Reference Include="SharpDX, Version=3.0.2.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
@ -191,10 +211,16 @@
<HintPath>..\packages\SharpDX.DXGI.3.0.2\lib\net45\SharpDX.DXGI.dll</HintPath> <HintPath>..\packages\SharpDX.DXGI.3.0.2\lib\net45\SharpDX.DXGI.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="SpotifyAPI, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\SpotifyAPI-NET.2.9.0\lib\SpotifyAPI.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" /> <Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Linq.Dynamic, Version=1.0.5840.25917, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="System.Linq.Dynamic, Version=1.0.5840.25917, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\System.Linq.Dynamic.1.0.6\lib\net40\System.Linq.Dynamic.dll</HintPath> <HintPath>..\packages\System.Linq.Dynamic.1.0.6\lib\net40\System.Linq.Dynamic.dll</HintPath>
<Private>True</Private> <Private>True</Private>
@ -202,7 +228,10 @@
<Reference Include="System.Runtime.Serialization" /> <Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Web" /> <Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" /> <Reference Include="System.Windows.Forms" />
<Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" /> <Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Caliburn.Micro.3.0.1\lib\net45\System.Windows.Interactivity.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
@ -259,34 +288,44 @@
</Compile> </Compile>
<Compile Include="ArtemisBootstrapper.cs" /> <Compile Include="ArtemisBootstrapper.cs" />
<Compile Include="DAL\ProfileProvider.cs" /> <Compile Include="DAL\ProfileProvider.cs" />
<Compile Include="DeviceProviders\Corsair\CorsairMice.cs" />
<Compile Include="DeviceProviders\Corsair\CorsairHeadsets.cs" />
<Compile Include="DeviceProviders\DeviceProvider.cs" />
<Compile Include="Events\ActiveKeyboardChanged.cs" /> <Compile Include="Events\ActiveKeyboardChanged.cs" />
<Compile Include="Events\ToggleEnabled.cs" /> <Compile Include="Events\ToggleEnabled.cs" />
<Compile Include="Events\ActiveEffectChanged.cs" /> <Compile Include="Events\ActiveEffectChanged.cs" />
<Compile Include="Events\ChangeBitmap.cs" /> <Compile Include="Events\ChangeBitmap.cs" />
<Compile Include="InjectionFactories\ILayerEditorVmFactory.cs" />
<Compile Include="InjectionFactories\IProfileEditorVmFactory.cs" />
<Compile Include="ItemBehaviours\BindableSelectedItemBehavior.cs" /> <Compile Include="ItemBehaviours\BindableSelectedItemBehavior.cs" />
<Compile Include="KeyboardProviders\Corsair\CorsairRGB.cs" /> <Compile Include="DeviceProviders\Corsair\CorsairRGB.cs" />
<Compile Include="KeyboardProviders\KeyboardProvider.cs" /> <Compile Include="DeviceProviders\KeyboardProvider.cs" />
<Compile Include="KeyboardProviders\KeyboardRegion.cs" /> <Compile Include="DeviceProviders\Logitech\Orion.cs" />
<Compile Include="KeyboardProviders\Logitech\Orion.cs" /> <Compile Include="DeviceProviders\Logitech\Utilities\KeyboardNames.cs" />
<Compile Include="KeyboardProviders\Logitech\Utilities\KeyboardNames.cs" /> <Compile Include="DeviceProviders\Logitech\Utilities\KeyMap.cs" />
<Compile Include="KeyboardProviders\Logitech\Utilities\KeyMap.cs" /> <Compile Include="DeviceProviders\Logitech\Utilities\LogitechGSDK.cs" />
<Compile Include="KeyboardProviders\Logitech\Utilities\LogitechGSDK.cs" /> <Compile Include="DeviceProviders\Logitech\Utilities\OrionUtilities.cs" />
<Compile Include="KeyboardProviders\Logitech\Utilities\OrionUtilities.cs" /> <Compile Include="DeviceProviders\Razer\BlackWidow.cs" />
<Compile Include="KeyboardProviders\ProviderHelper.cs" /> <Compile Include="DeviceProviders\Razer\Utilities\RazerUtilities.cs" />
<Compile Include="KeyboardProviders\Razer\BlackWidow.cs" />
<Compile Include="KeyboardProviders\Razer\Utilities\RazerUtilities.cs" />
<Compile Include="Managers\EffectManager.cs" /> <Compile Include="Managers\EffectManager.cs" />
<Compile Include="Managers\KeyboardManager.cs" /> <Compile Include="Managers\DeviceManager.cs" />
<Compile Include="Managers\LoopManager.cs" />
<Compile Include="Managers\MainManager.cs" /> <Compile Include="Managers\MainManager.cs" />
<Compile Include="Managers\ProfileManager.cs" />
<Compile Include="Models\EffectModel.cs" /> <Compile Include="Models\EffectModel.cs" />
<Compile Include="Models\EffectSettings.cs" /> <Compile Include="Models\EffectSettings.cs" />
<Compile Include="Models\GameSettings.cs" /> <Compile Include="Models\GameSettings.cs" />
<Compile Include="Models\Interfaces\GameDataModel.cs" /> <Compile Include="Models\Interfaces\GameDataModel.cs" />
<Compile Include="Models\OverlaySettings.cs" />
<Compile Include="Models\Profiles\LayerConditionModel.cs" /> <Compile Include="Models\Profiles\LayerConditionModel.cs" />
<Compile Include="Models\Profiles\LayerModel.cs" /> <Compile Include="Models\Profiles\LayerModel.cs" />
<Compile Include="Models\Profiles\LayerDynamicPropertiesModel.cs" />
<Compile Include="Models\Profiles\LayerPropertiesModel.cs" />
<Compile Include="Models\Profiles\ProfileModel.cs" /> <Compile Include="Models\Profiles\ProfileModel.cs" />
<Compile Include="Models\Profiles\Properties\DynamicPropertiesModel.cs" />
<Compile Include="Models\Profiles\Properties\HeadsetPropertiesModel.cs" />
<Compile Include="Models\Profiles\Properties\KeyboardPropertiesModel.cs" />
<Compile Include="Models\Profiles\Properties\LayerPropertiesModel.cs" />
<Compile Include="Models\Profiles\Properties\FolderPropertiesModel.cs" />
<Compile Include="Models\Profiles\Properties\MousePropertiesModel.cs" />
<Compile Include="Modules\Effects\AmbientLightning\AmbientLightningEffectModel.cs" /> <Compile Include="Modules\Effects\AmbientLightning\AmbientLightningEffectModel.cs" />
<Compile Include="Modules\Effects\AmbientLightning\AmbientLightningEffectSettings.cs" /> <Compile Include="Modules\Effects\AmbientLightning\AmbientLightningEffectSettings.cs" />
<Compile Include="Modules\Effects\AmbientLightning\AmbientLightningEffectView.xaml.cs"> <Compile Include="Modules\Effects\AmbientLightning\AmbientLightningEffectView.xaml.cs">
@ -302,9 +341,19 @@
<Compile Include="Modules\Effects\AudioVisualizer\AudioVisualizerModel.cs" /> <Compile Include="Modules\Effects\AudioVisualizer\AudioVisualizerModel.cs" />
<Compile Include="Modules\Effects\AudioVisualizer\Utilities\FftEventArgs.cs" /> <Compile Include="Modules\Effects\AudioVisualizer\Utilities\FftEventArgs.cs" />
<Compile Include="Modules\Effects\AudioVisualizer\Utilities\SampleAggregator.cs" /> <Compile Include="Modules\Effects\AudioVisualizer\Utilities\SampleAggregator.cs" />
<Compile Include="Modules\Effects\Debug\DebugEffectModel.cs" /> <Compile Include="Modules\Effects\WindowsProfile\WindowsProfile.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<DependentUpon>WindowsProfile.settings</DependentUpon>
</Compile>
<Compile Include="Modules\Effects\WindowsProfile\WindowsProfileSettings.cs" />
<Compile Include="Modules\Effects\WindowsProfile\WindowsProfileView.xaml.cs">
<DependentUpon>WindowsProfileView.xaml</DependentUpon>
</Compile>
<Compile Include="Modules\Effects\WindowsProfile\WindowsProfileViewModel.cs" />
<Compile Include="Modules\Effects\WindowsProfile\WindowsProfileDataModel.cs" />
<Compile Include="Modules\Effects\WindowsProfile\WindowsProfileModel.cs" />
<Compile Include="Modules\Effects\ProfilePreview\ProfilePreviewModel.cs" /> <Compile Include="Modules\Effects\ProfilePreview\ProfilePreviewModel.cs" />
<Compile Include="Modules\Effects\TypeHole\TypeHoleModel.cs" />
<Compile Include="Modules\Effects\TypeWave\TypeWave.Designer.cs"> <Compile Include="Modules\Effects\TypeWave\TypeWave.Designer.cs">
<DependentUpon>TypeWave.settings</DependentUpon> <DependentUpon>TypeWave.settings</DependentUpon>
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
@ -328,6 +377,9 @@
<Compile Include="Modules\Games\Dota2\Dota2DataModel.cs" /> <Compile Include="Modules\Games\Dota2\Dota2DataModel.cs" />
<Compile Include="Modules\Games\Dota2\Dota2Model.cs" /> <Compile Include="Modules\Games\Dota2\Dota2Model.cs" />
<Compile Include="Modules\Games\Dota2\Dota2Settings.cs" /> <Compile Include="Modules\Games\Dota2\Dota2Settings.cs" />
<Compile Include="Modules\Games\Overwatch\OverwatchView.xaml.cs">
<DependentUpon>OverwatchView.xaml</DependentUpon>
</Compile>
<Compile Include="Modules\Games\RocketLeague\RocketLeague.Designer.cs"> <Compile Include="Modules\Games\RocketLeague\RocketLeague.Designer.cs">
<DependentUpon>RocketLeague.settings</DependentUpon> <DependentUpon>RocketLeague.settings</DependentUpon>
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
@ -347,6 +399,16 @@
<DependentUpon>TheDivisionView.xaml</DependentUpon> <DependentUpon>TheDivisionView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Modules\Games\TheDivision\TheDivisionViewModel.cs" /> <Compile Include="Modules\Games\TheDivision\TheDivisionViewModel.cs" />
<Compile Include="Modules\Games\Overwatch\OverwatchDataModel.cs" />
<Compile Include="Modules\Games\Overwatch\Overwatch.Designer.cs">
<DependentUpon>Overwatch.settings</DependentUpon>
<AutoGen>True</AutoGen>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<Compile Include="Modules\Games\Overwatch\OverwatchModel.cs" />
<Compile Include="Modules\Games\Overwatch\OverwatchSettings.cs" />
<Compile Include="Modules\Games\Overwatch\OverwatchViewModel.cs" />
<Compile Include="Modules\Games\Witcher3\Witcher3DataModel.cs" />
<Compile Include="Modules\Games\Witcher3\Witcher3Settings.cs" /> <Compile Include="Modules\Games\Witcher3\Witcher3Settings.cs" />
<Compile Include="Modules\Games\Witcher3\Witcher3.Designer.cs"> <Compile Include="Modules\Games\Witcher3\Witcher3.Designer.cs">
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
@ -363,10 +425,12 @@
</Compile> </Compile>
<Compile Include="Modules\Overlays\VolumeDisplay\VolumeDisplayModel.cs" /> <Compile Include="Modules\Overlays\VolumeDisplay\VolumeDisplayModel.cs" />
<Compile Include="Modules\Effects\AudioVisualizer\AudioVisualizerSettings.cs" /> <Compile Include="Modules\Effects\AudioVisualizer\AudioVisualizerSettings.cs" />
<Compile Include="Modules\Effects\Debug\DebugEffectSettings.cs" />
<Compile Include="Modules\Overlays\VolumeDisplay\VolumeDisplaySettings.cs" /> <Compile Include="Modules\Overlays\VolumeDisplay\VolumeDisplaySettings.cs" />
<Compile Include="Modules\Games\RocketLeague\RocketLeagueSettings.cs" /> <Compile Include="Modules\Games\RocketLeague\RocketLeagueSettings.cs" />
<Compile Include="Modules\Effects\TypeWave\TypeWaveSettings.cs" /> <Compile Include="Modules\Effects\TypeWave\TypeWaveSettings.cs" />
<Compile Include="InjectionModules\ArtemisModules.cs" />
<Compile Include="InjectionModules\BaseModules.cs" />
<Compile Include="InjectionModules\ManagerModules.cs" />
<Compile Include="Properties\Annotations.cs" /> <Compile Include="Properties\Annotations.cs" />
<Compile Include="Properties\Resources.Designer.cs"> <Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
@ -386,14 +450,19 @@
<DesignTimeSharedInput>True</DesignTimeSharedInput> <DesignTimeSharedInput>True</DesignTimeSharedInput>
<DependentUpon>Offsets.settings</DependentUpon> <DependentUpon>Offsets.settings</DependentUpon>
</Compile> </Compile>
<Compile Include="Styles\DropTargetAdorners\DropTargetMetroHighlightAdorner.cs" />
<Compile Include="Styles\DropTargetAdorners\DropTargetMetroInsertionAdorner.cs" />
<Compile Include="Utilities\ColorHelpers.cs" /> <Compile Include="Utilities\ColorHelpers.cs" />
<Compile Include="Utilities\DataReaders\MmfReader.cs" />
<Compile Include="Utilities\ExtensionMethods.cs" /> <Compile Include="Utilities\ExtensionMethods.cs" />
<Compile Include="Utilities\GameState\GameDataReceivedEventArgs.cs" /> <Compile Include="Utilities\GameState\GameDataReceivedEventArgs.cs" />
<Compile Include="Utilities\GameState\GameStateWebServer.cs" /> <Compile Include="Utilities\GameState\GameStateWebServer.cs" />
<Compile Include="Utilities\GeneralHelpers.cs" /> <Compile Include="Utilities\GeneralHelpers.cs" />
<Compile Include="Utilities\GifImage.cs" />
<Compile Include="Utilities\ImageUtilities.cs" /> <Compile Include="Utilities\ImageUtilities.cs" />
<Compile Include="Utilities\Keyboard\KeyboardHook.cs" /> <Compile Include="Utilities\Keyboard\KeyboardHook.cs" />
<Compile Include="Utilities\LayerDrawer.cs" /> <Compile Include="Utilities\Layers\AnimationUpdater.cs" />
<Compile Include="Utilities\Layers\Drawer.cs" />
<Compile Include="Utilities\LogitechDll\DllManager.cs" /> <Compile Include="Utilities\LogitechDll\DllManager.cs" />
<Compile Include="Utilities\LogitechDll\NamedPipeServer.cs" /> <Compile Include="Utilities\LogitechDll\NamedPipeServer.cs" />
<Compile Include="Utilities\LogitechDll\PipeServer.cs" /> <Compile Include="Utilities\LogitechDll\PipeServer.cs" />
@ -409,12 +478,12 @@
<Compile Include="Utilities\StickyValue.cs" /> <Compile Include="Utilities\StickyValue.cs" />
<Compile Include="Utilities\Updater.cs" /> <Compile Include="Utilities\Updater.cs" />
<Compile Include="Utilities\ValueConverters.cs" /> <Compile Include="Utilities\ValueConverters.cs" />
<Compile Include="ViewModels\Abstract\BaseViewModel.cs" />
<Compile Include="ViewModels\Abstract\OverlayViewModel.cs" />
<Compile Include="ViewModels\Abstract\EffectViewModel.cs" /> <Compile Include="ViewModels\Abstract\EffectViewModel.cs" />
<Compile Include="ViewModels\Abstract\GameViewModel.cs" /> <Compile Include="ViewModels\Abstract\GameViewModel.cs" />
<Compile Include="ViewModels\EffectsViewModel.cs" /> <Compile Include="ViewModels\EffectsViewModel.cs" />
<Compile Include="Modules\Effects\AudioVisualizer\AudioVisualizerViewModel.cs" /> <Compile Include="Modules\Effects\AudioVisualizer\AudioVisualizerViewModel.cs" />
<Compile Include="Modules\Effects\Debug\DebugEffectViewModel.cs" />
<Compile Include="Modules\Effects\TypeHole\TypeHoleViewModel.cs" />
<Compile Include="Modules\Effects\TypeWave\TypeWaveViewModel.cs" /> <Compile Include="Modules\Effects\TypeWave\TypeWaveViewModel.cs" />
<Compile Include="ViewModels\FlyoutBaseViewModel.cs" /> <Compile Include="ViewModels\FlyoutBaseViewModel.cs" />
<Compile Include="ViewModels\Flyouts\FlyoutSettingsViewModel.cs" /> <Compile Include="ViewModels\Flyouts\FlyoutSettingsViewModel.cs" />
@ -423,12 +492,18 @@
<Compile Include="Modules\Games\Dota2\Dota2ViewModel.cs" /> <Compile Include="Modules\Games\Dota2\Dota2ViewModel.cs" />
<Compile Include="Modules\Games\RocketLeague\RocketLeagueViewModel.cs" /> <Compile Include="Modules\Games\RocketLeague\RocketLeagueViewModel.cs" />
<Compile Include="Modules\Games\Witcher3\Witcher3ViewModel.cs" /> <Compile Include="Modules\Games\Witcher3\Witcher3ViewModel.cs" />
<Compile Include="ViewModels\LayerEditor\LayerConditionViewModel.cs" /> <Compile Include="ViewModels\Profiles\ProfileViewModel.cs" />
<Compile Include="ViewModels\LayerEditor\LayerDynamicPropertiesViewModel.cs" /> <Compile Include="ViewModels\Profiles\Properties\KeyboardPropertiesViewModel.cs" />
<Compile Include="ViewModels\LayerEditor\LayerEditorViewModel.cs" /> <Compile Include="ViewModels\Profiles\LayerConditionViewModel.cs" />
<Compile Include="ViewModels\Profiles\LayerDynamicPropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\LayerEditorViewModel.cs" />
<Compile Include="ViewModels\Profiles\Properties\LayerPropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\Properties\HeadsetPropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\Properties\FolderPropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\Properties\MousePropertiesViewModel.cs" />
<Compile Include="ViewModels\OverlaysViewModel.cs" /> <Compile Include="ViewModels\OverlaysViewModel.cs" />
<Compile Include="Modules\Overlays\VolumeDisplay\VolumeDisplayViewModel.cs" /> <Compile Include="Modules\Overlays\VolumeDisplay\VolumeDisplayViewModel.cs" />
<Compile Include="ViewModels\ProfileEditorViewModel.cs" /> <Compile Include="ViewModels\Profiles\ProfileEditorViewModel.cs" />
<Compile Include="ViewModels\ShellViewModel.cs" /> <Compile Include="ViewModels\ShellViewModel.cs" />
<Compile Include="ViewModels\SystemTrayViewModel.cs" /> <Compile Include="ViewModels\SystemTrayViewModel.cs" />
<Compile Include="ViewModels\WelcomeViewModel.cs" /> <Compile Include="ViewModels\WelcomeViewModel.cs" />
@ -438,15 +513,9 @@
<Compile Include="Views\Flyouts\FlyoutSettingsView.xaml.cs"> <Compile Include="Views\Flyouts\FlyoutSettingsView.xaml.cs">
<DependentUpon>FlyoutSettingsView.xaml</DependentUpon> <DependentUpon>FlyoutSettingsView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Modules\Effects\Debug\DebugEffectView.xaml.cs">
<DependentUpon>DebugEffectView.xaml</DependentUpon>
</Compile>
<Compile Include="Modules\Effects\AudioVisualizer\AudioVisualizerView.xaml.cs"> <Compile Include="Modules\Effects\AudioVisualizer\AudioVisualizerView.xaml.cs">
<DependentUpon>AudioVisualizerView.xaml</DependentUpon> <DependentUpon>AudioVisualizerView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Modules\Effects\TypeHole\TypeHoleView.xaml.cs">
<DependentUpon>TypeHoleView.xaml</DependentUpon>
</Compile>
<Compile Include="Modules\Effects\TypeWave\TypeWaveView.xaml.cs"> <Compile Include="Modules\Effects\TypeWave\TypeWaveView.xaml.cs">
<DependentUpon>TypeWaveView.xaml</DependentUpon> <DependentUpon>TypeWaveView.xaml</DependentUpon>
</Compile> </Compile>
@ -465,22 +534,34 @@
<Compile Include="Modules\Games\Witcher3\Witcher3View.xaml.cs"> <Compile Include="Modules\Games\Witcher3\Witcher3View.xaml.cs">
<DependentUpon>Witcher3View.xaml</DependentUpon> <DependentUpon>Witcher3View.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\LayerEditor\LayerConditionView.xaml.cs"> <Compile Include="Views\Profiles\Properties\FolderPropertiesView.xaml.cs">
<DependentUpon>FolderPropertiesView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Profiles\Properties\HeadsetPropertiesView.xaml.cs">
<DependentUpon>HeadsetPropertiesView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Profiles\Properties\KeyboardPropertiesView.xaml.cs">
<DependentUpon>KeyboardPropertiesView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Profiles\LayerConditionView.xaml.cs">
<DependentUpon>LayerConditionView.xaml</DependentUpon> <DependentUpon>LayerConditionView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\LayerEditor\LayerDynamicPropertiesView.xaml.cs"> <Compile Include="Views\Profiles\LayerDynamicPropertiesView.xaml.cs">
<DependentUpon>LayerDynamicPropertiesView.xaml</DependentUpon> <DependentUpon>LayerDynamicPropertiesView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\LayerEditor\LayerEditorView.xaml.cs"> <Compile Include="Views\Profiles\LayerEditorView.xaml.cs">
<DependentUpon>LayerEditorView.xaml</DependentUpon> <DependentUpon>LayerEditorView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\Profiles\Properties\MousePropertiesView.xaml.cs">
<DependentUpon>MousePropertiesView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\OverlaysView.xaml.cs"> <Compile Include="Views\OverlaysView.xaml.cs">
<DependentUpon>OverlaysView.xaml</DependentUpon> <DependentUpon>OverlaysView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Modules\Overlays\VolumeDisplay\VolumeDisplayView.xaml.cs"> <Compile Include="Modules\Overlays\VolumeDisplay\VolumeDisplayView.xaml.cs">
<DependentUpon>VolumeDisplayView.xaml</DependentUpon> <DependentUpon>VolumeDisplayView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\ProfileEditorView.xaml.cs"> <Compile Include="Views\Profiles\ProfileEditorView.xaml.cs">
<DependentUpon>ProfileEditorView.xaml</DependentUpon> <DependentUpon>ProfileEditorView.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\ShellView.xaml.cs"> <Compile Include="Views\ShellView.xaml.cs">
@ -510,6 +591,10 @@
<Generator>SettingsSingleFileGenerator</Generator> <Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>TypeWave.Designer.cs</LastGenOutput> <LastGenOutput>TypeWave.Designer.cs</LastGenOutput>
</None> </None>
<None Include="Modules\Effects\WindowsProfile\WindowsProfile.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>WindowsProfile.Designer.cs</LastGenOutput>
</None>
<None Include="Modules\Games\CounterStrike\CounterStrike.settings"> <None Include="Modules\Games\CounterStrike\CounterStrike.settings">
<Generator>SettingsSingleFileGenerator</Generator> <Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>CounterStrike.Designer.cs</LastGenOutput> <LastGenOutput>CounterStrike.Designer.cs</LastGenOutput>
@ -526,6 +611,10 @@
<Generator>SettingsSingleFileGenerator</Generator> <Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>TheDivision.Designer.cs</LastGenOutput> <LastGenOutput>TheDivision.Designer.cs</LastGenOutput>
</None> </None>
<None Include="Modules\Games\Overwatch\Overwatch.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Overwatch.Designer.cs</LastGenOutput>
</None>
<None Include="Modules\Games\Witcher3\Witcher3.settings"> <None Include="Modules\Games\Witcher3\Witcher3.settings">
<Generator>SettingsSingleFileGenerator</Generator> <Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Witcher3.Designer.cs</LastGenOutput> <LastGenOutput>Witcher3.Designer.cs</LastGenOutput>
@ -540,7 +629,9 @@
<None Include="NLog.xsd"> <None Include="NLog.xsd">
<SubType>Designer</SubType> <SubType>Designer</SubType>
</None> </None>
<None Include="packages.config" /> <None Include="packages.config">
<SubType>Designer</SubType>
</None>
<AppDesigner Include="Properties\" /> <AppDesigner Include="Properties\" />
<Resource Include="Resources\bow.png" /> <Resource Include="Resources\bow.png" />
<Content Include="logo.ico"> <Content Include="logo.ico">
@ -550,15 +641,23 @@
<Resource Include="Resources\logo-disabled.ico" /> <Resource Include="Resources\logo-disabled.ico" />
<Resource Include="Resources\Dota2\dotaGamestateConfiguration.txt" /> <Resource Include="Resources\Dota2\dotaGamestateConfiguration.txt" />
<Resource Include="Resources\Entypo.ttf" /> <Resource Include="Resources\Entypo.ttf" />
<EmbeddedResource Include="Resources\Keyboards\default-profiles.zip" />
<None Include="Resources\LogitechLED.dll" /> <None Include="Resources\LogitechLED.dll" />
<None Include="Resources\folder.png" />
<Resource Include="Resources\Keyboards\k65.png" /> <Resource Include="Resources\Keyboards\k65.png" />
<Resource Include="Resources\Keyboards\k70.png" /> <Resource Include="Resources\Keyboards\k70.png" />
<Resource Include="Resources\Keyboards\k95.png" /> <Resource Include="Resources\Keyboards\k95.png" />
<Resource Include="Resources\Keyboards\strafe.png" /> <Resource Include="Resources\Keyboards\strafe.png" />
<Resource Include="Resources\Keyboards\g910.png" /> <Resource Include="Resources\Keyboards\g910.png" />
<None Include="Resources\folder.png" />
<None Include="Resources\headset.png" />
<None Include="Resources\mouse.png" />
<None Include="Resources\gif.png" />
<Resource Include="Resources\WindowsIcons-license.txt" /> <Resource Include="Resources\WindowsIcons-license.txt" />
<Resource Include="Resources\Entypo-license.txt" /> <Resource Include="Resources\Entypo-license.txt" />
<None Include="Resources\RzChromaSDK64.dll" />
<Resource Include="Resources\Keyboards\blackwidow.png" />
<None Include="Resources\Keyboards\none.png" />
<None Include="Resources\Keyboards\demo-gif.gif" />
<Content Include="Resources\Witcher3\playerWitcher.txt" /> <Content Include="Resources\Witcher3\playerWitcher.txt" />
<Content Include="Resources\Witcher3\artemis.txt" /> <Content Include="Resources\Witcher3\artemis.txt" />
<None Include="Settings\Offsets.settings"> <None Include="Settings\Offsets.settings">
@ -578,6 +677,14 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Modules\Effects\WindowsProfile\WindowsProfileView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Modules\Games\Overwatch\OverwatchView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Modules\Games\TheDivision\TheDivisionView.xaml"> <Page Include="Modules\Games\TheDivision\TheDivisionView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -586,10 +693,14 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</Page> </Page>
<Page Include="Styles\Accents\CorsairYellow.xaml"> <Page Include="Resources\IconsNonShared.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Resource Include="Styles\Accents\CorsairYellow.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Resource>
<Page Include="Styles\ColorBox.xaml"> <Page Include="Styles\ColorBox.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -598,18 +709,10 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Modules\Effects\Debug\DebugEffectView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Modules\Effects\AudioVisualizer\AudioVisualizerView.xaml"> <Page Include="Modules\Effects\AudioVisualizer\AudioVisualizerView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Modules\Effects\TypeHole\TypeHoleView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Modules\Effects\TypeWave\TypeWaveView.xaml"> <Page Include="Modules\Effects\TypeWave\TypeWaveView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -638,18 +741,34 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Views\LayerEditor\LayerConditionView.xaml"> <Page Include="Views\Profiles\Properties\FolderPropertiesView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Views\LayerEditor\LayerDynamicPropertiesView.xaml"> <Page Include="Views\Profiles\Properties\HeadsetPropertiesView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Views\LayerEditor\LayerEditorView.xaml"> <Page Include="Views\Profiles\Properties\KeyboardPropertiesView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Profiles\LayerConditionView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Profiles\LayerDynamicPropertiesView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Profiles\LayerEditorView.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</Page> </Page>
<Page Include="Views\Profiles\Properties\MousePropertiesView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\OverlaysView.xaml"> <Page Include="Views\OverlaysView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -658,7 +777,7 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Views\ProfileEditorView.xaml"> <Page Include="Views\Profiles\ProfileEditorView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
@ -695,12 +814,12 @@
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\CUE.NET.1.0.2.2\build\net45\CUE.NET.targets" Condition="Exists('..\packages\CUE.NET.1.0.2.2\build\net45\CUE.NET.targets')" /> <Import Project="..\packages\CUE.NET.1.0.3\build\net45\CUE.NET.targets" Condition="Exists('..\packages\CUE.NET.1.0.3\build\net45\CUE.NET.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup> <PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup> </PropertyGroup>
<Error Condition="!Exists('..\packages\CUE.NET.1.0.2.2\build\net45\CUE.NET.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CUE.NET.1.0.2.2\build\net45\CUE.NET.targets'))" /> <Error Condition="!Exists('..\packages\CUE.NET.1.0.3\build\net45\CUE.NET.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\CUE.NET.1.0.3\build\net45\CUE.NET.targets'))" />
</Target> </Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets. Other similar extension points exist, see Microsoft.Common.targets.

View File

@ -1,27 +1,34 @@
using System.Diagnostics; using System;
using System.Linq; using System.Collections.Generic;
using System.Reflection; using System.Threading;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Forms; using System.Windows.Forms;
using Artemis.InjectionModules;
using Artemis.ViewModels; using Artemis.ViewModels;
using Autofac;
using Caliburn.Micro; using Caliburn.Micro;
using Caliburn.Micro.Autofac; using Ninject;
using Application = System.Windows.Application; using Application = System.Windows.Application;
using MessageBox = System.Windows.Forms.MessageBox; using MessageBox = System.Windows.Forms.MessageBox;
using MouseEventArgs = System.Windows.Input.MouseEventArgs; using MouseEventArgs = System.Windows.Input.MouseEventArgs;
namespace Artemis namespace Artemis
{ {
public class ArtemisBootstrapper : AutofacBootstrapper<SystemTrayViewModel> public class ArtemisBootstrapper : BootstrapperBase
{ {
private IKernel _kernel;
public ArtemisBootstrapper() public ArtemisBootstrapper()
{ {
CheckDuplicateInstances(); CheckDuplicateInstances();
Initialize(); Initialize();
BindSpecialValues();
}
public Mutex Mutex { get; set; }
private void BindSpecialValues()
{
MessageBinder.SpecialValues.Add("$scaledmousex", ctx => MessageBinder.SpecialValues.Add("$scaledmousex", ctx =>
{ {
var img = ctx.Source as Image; var img = ctx.Source as Image;
@ -64,14 +71,35 @@ namespace Artemis
}); });
} }
protected override void ConfigureContainer(ContainerBuilder builder) protected override void Configure()
{ {
base.ConfigureContainer(builder); _kernel = new StandardKernel(new BaseModules(), new ArtemisModules(), new ManagerModules());
_kernel.Bind<IWindowManager>().To<WindowManager>().InSingletonScope();
_kernel.Bind<IEventAggregator>().To<EventAggregator>().InSingletonScope();
}
// create a window manager instance to be used by everyone asking for one (including Caliburn.Micro) protected override void OnExit(object sender, EventArgs e)
builder.RegisterInstance<IWindowManager>(new WindowManager()); {
builder.RegisterType<SystemTrayViewModel>(); _kernel.Dispose();
builder.RegisterType<ShellViewModel>(); base.OnExit(sender, e);
}
protected override object GetInstance(Type service, string key)
{
if (service == null)
throw new ArgumentNullException(nameof(service));
return _kernel.Get(service);
}
protected override IEnumerable<object> GetAllInstances(Type service)
{
return _kernel.GetAll(service);
}
protected override void BuildUp(object instance)
{
_kernel.Inject(instance);
} }
protected override void OnStartup(object sender, StartupEventArgs e) protected override void OnStartup(object sender, StartupEventArgs e)
@ -81,8 +109,9 @@ namespace Artemis
private void CheckDuplicateInstances() private void CheckDuplicateInstances()
{ {
if (Process.GetProcesses().Count(p => p.ProcessName.Contains(Assembly.GetExecutingAssembly() bool aIsNewInstance;
.FullName.Split(',')[0]) && !p.Modules[0].FileName.Contains("vshost")) < 2) Mutex = new Mutex(true, "ArtemisMutex", out aIsNewInstance);
if (aIsNewInstance)
return; return;
MessageBox.Show("An instance of Artemis is already running (check your system tray).", MessageBox.Show("An instance of Artemis is already running (check your system tray).",

View File

@ -1,18 +1,28 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Xml.Serialization; using System.Xml.Serialization;
using Artemis.DeviceProviders;
using Artemis.Models; using Artemis.Models;
using Artemis.Models.Profiles; using Artemis.Models.Profiles;
using Artemis.Models.Profiles.Properties;
using Artemis.Properties;
using Artemis.Utilities;
using NLog;
namespace Artemis.DAL namespace Artemis.DAL
{ {
public static class ProfileProvider public static class ProfileProvider
{ {
private static readonly string ProfileFolder = private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\profiles";
private static readonly string ProfileFolder = Environment
.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\profiles";
private static bool _installedDefaults;
/// <summary> /// <summary>
/// Get all profiles /// Get all profiles
@ -27,10 +37,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(EffectModel 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.KeyboardSlug.Equals(keyboard.Slug)).ToList();
} }
/// <summary> /// <summary>
@ -40,44 +56,100 @@ 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.GameName?.Length > 1) || !(prof.KeyboardName?.Length > 1) || !(prof.Name?.Length > 1)) if (prof == null)
throw new ArgumentException("Profile is invalid. Name, GameName and KeyboardName are required"); throw new ArgumentNullException(nameof(prof));
if (!(prof.GameName?.Length > 1) || !(prof.KeyboardSlug?.Length > 1) || !(prof.Name?.Length > 1))
throw new ArgumentException("Profile is invalid. Name, GameName and KeyboardSlug are required");
var path = ProfileFolder + $@"\{prof.KeyboardName}\{prof.GameName}"; var path = ProfileFolder + $@"\{prof.KeyboardSlug}\{prof.GameName}";
if (!Directory.Exists(path)) if (!Directory.Exists(path))
Directory.CreateDirectory(path); Directory.CreateDirectory(path);
var serializer = new XmlSerializer(typeof (ProfileModel)); var serializer = new XmlSerializer(typeof(ProfileModel));
using (var file = new StreamWriter(path + $@"\{prof.Name}.xml"))
// Could use a StreamWriter but should serializing fail this method doesn't ruin the existing XML file
using (var xml = new StringWriter())
{ {
serializer.Serialize(file, prof); serializer.Serialize(xml, prof);
File.WriteAllText(path + $@"\{prof.Name}.xml", xml.ToString());
} }
} }
private static List<ProfileModel> ReadProfiles() private static List<ProfileModel> ReadProfiles()
{ {
CheckProfiles(); CheckProfiles();
InstallDefaults();
var profiles = new List<ProfileModel>(); var profiles = new List<ProfileModel>();
// Create the directory structure // Create the directory structure
var profilePaths = Directory.GetFiles(ProfileFolder, "*.xml", SearchOption.AllDirectories); var profilePaths = Directory.GetFiles(ProfileFolder, "*.xml", SearchOption.AllDirectories);
// Parse the JSON files into objects and add them if they are valid // Parse the JSON files into objects and add them if they are valid
// TODO: Invalid file handling var deserializer = new XmlSerializer(typeof(ProfileModel));
var deserializer = new XmlSerializer(typeof (ProfileModel));
foreach (var path in profilePaths) foreach (var path in profilePaths)
{ {
using (var file = new StreamReader(path)) try
{ {
var prof = (ProfileModel) deserializer.Deserialize(file); using (var file = new StreamReader(path))
if (prof.GameName?.Length > 1 && prof.KeyboardName?.Length > 1 && prof.Name?.Length > 1) {
profiles.Add(prof); var prof = (ProfileModel) deserializer.Deserialize(file);
if (prof.GameName?.Length > 1 && prof.KeyboardSlug?.Length > 1 && prof.Name?.Length > 1)
profiles.Add(prof);
}
}
catch (InvalidOperationException e)
{
Logger.Error("Failed to load profile: {0} - {1}", path, e.InnerException.Message);
} }
} }
return profiles; return profiles;
} }
/// <summary>
/// Unpacks the default profiles into the profile directory
/// </summary>
private static void InstallDefaults()
{
// Only install the defaults once per session
if (_installedDefaults)
return;
_installedDefaults = true;
// Load the ZIP from resources
var stream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream("Artemis.Resources.Keyboards.default-profiles.zip");
// Extract it over the old defaults in case one was updated
if (stream == null)
return;
var archive = new ZipArchive(stream);
archive.ExtractToDirectory(ProfileFolder, true);
// Extract the demo GIF file
var gifPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\demo-gif.gif";
Resources.demo_gif.Save(gifPath);
// Set the GIF path on each demo profile
var demoProfiles = GetAll().Where(d => d.Name == "Demo (Duplicate to keep changes)");
foreach (var demoProfile in demoProfiles)
{
var gifLayer = demoProfile
.Layers.FirstOrDefault(l => l.Name == "Demo - GIFs")?
.Children.FirstOrDefault(c => c.Name == "GIF");
if (gifLayer == null)
continue;
((KeyboardPropertiesModel) gifLayer.Properties).GifFile = gifPath;
AddOrUpdate(demoProfile);
}
}
/// <summary>
/// Makes sure the profile directory structure is in order and places default profiles
/// </summary>
private static void CheckProfiles() private static void CheckProfiles()
{ {
// Create the directory structure // Create the directory structure
@ -85,7 +157,72 @@ namespace Artemis.DAL
return; return;
Directory.CreateDirectory(ProfileFolder); Directory.CreateDirectory(ProfileFolder);
Debug.WriteLine("Place presets"); }
/// <summary>
/// Attempts to load a profile from a given path
/// </summary>
/// <param name="path">The absolute path to load the profile from</param>
/// <returns>The loaded profile, or null if invalid</returns>
public static ProfileModel LoadProfileIfValid(string path)
{
try
{
var deserializer = new XmlSerializer(typeof(ProfileModel));
using (var file = new StreamReader(path))
{
var prof = (ProfileModel) deserializer.Deserialize(file);
if (!(prof.GameName?.Length > 1) || !(prof.KeyboardSlug?.Length > 1) || !(prof.Name?.Length > 1))
return null;
return prof;
}
}
catch (InvalidOperationException)
{
return null;
}
}
/// <summary>
/// Exports the given profile to the provided path in XML
/// </summary>
/// <param name="selectedProfile">The profile to export</param>
/// <param name="path">The path to save the profile to</param>
public static void ExportProfile(ProfileModel selectedProfile, string path)
{
var serializer = new XmlSerializer(typeof(ProfileModel));
using (var file = new StreamWriter(path))
{
serializer.Serialize(file, selectedProfile);
}
}
/// <summary>
/// Renames the profile on the model and filesystem
/// </summary>
/// <param name="profile">The profile to rename</param>
/// <param name="name">The new name</param>
public static void RenameProfile(ProfileModel profile, string name)
{
if (string.IsNullOrEmpty(name))
return;
// Remove the old file
var path = ProfileFolder + $@"\{profile.KeyboardSlug}\{profile.GameName}\{profile.Name}.xml";
if (File.Exists(path))
File.Delete(path);
// Update the profile, creating a new file
profile.Name = name;
AddOrUpdate(profile);
}
public static void DeleteProfile(ProfileModel profile)
{
// Remove the file
var path = ProfileFolder + $@"\{profile.KeyboardSlug}\{profile.GameName}\{profile.Name}.xml";
if (File.Exists(path))
File.Delete(path);
} }
} }
} }

View File

@ -0,0 +1,80 @@
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Media;
using Artemis.Utilities;
using CUE.NET;
using CUE.NET.Devices.Generic.Enums;
using Ninject.Extensions.Logging;
namespace Artemis.DeviceProviders.Corsair
{
internal class CorsairHeadsets : DeviceProvider
{
public CorsairHeadsets(ILogger logger)
{
Logger = logger;
Type = DeviceType.Headset;
}
public ILogger Logger { get; set; }
public override bool TryEnable()
{
CanUse = CanInitializeSdk();
if (CanUse && !CueSDK.IsInitialized)
CueSDK.Initialize();
Logger.Debug("Attempted to enable Corsair headset. CanUse: {0}", CanUse);
return CanUse;
}
public override void Disable()
{
if (CueSDK.IsInitialized)
CueSDK.Reinitialize();
}
public override void UpdateDevice(Brush brush)
{
if (!CanUse || brush == null)
return;
var leds = CueSDK.HeadsetSDK.Leds.Count();
var rect = new Rect(new Size(leds*20, leds*20));
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
c.DrawRectangle(brush, null, rect);
var img = ImageUtilities.DrawinVisualToBitmap(visual, rect);
var ledIndex = 0;
// Color each LED according to one of the pixels
foreach (var corsairLed in CueSDK.HeadsetSDK.Leds)
{
corsairLed.Color = ledIndex == 0
? img.GetPixel(0, 0)
: img.GetPixel((ledIndex + 1)*20 - 1, (ledIndex + 1)*20 - 1);
ledIndex++;
}
// Flush is required for headset to work reliably on CUE2 for some reason
CueSDK.HeadsetSDK.Update(true);
}
private static bool CanInitializeSdk()
{
// This will skip the check-loop if the SDK is initialized
if (CueSDK.IsInitialized)
return CueSDK.IsSDKAvailable(CorsairDeviceType.Headset);
for (var tries = 0; tries < 9; tries++)
{
if (CueSDK.IsSDKAvailable(CorsairDeviceType.Headset))
return true;
Thread.Sleep(2000);
}
return false;
}
}
}

View File

@ -0,0 +1,79 @@
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Media;
using Artemis.Utilities;
using CUE.NET;
using CUE.NET.Devices.Generic.Enums;
using Ninject.Extensions.Logging;
namespace Artemis.DeviceProviders.Corsair
{
internal class CorsairMice : DeviceProvider
{
public CorsairMice(ILogger logger)
{
Logger = logger;
Type = DeviceType.Mouse;
}
public ILogger Logger { get; set; }
public override bool TryEnable()
{
CanUse = CanInitializeSdk();
if (CanUse && !CueSDK.IsInitialized)
CueSDK.Initialize();
Logger.Debug("Attempted to enable Corsair mice. CanUse: {0}", CanUse);
return CanUse;
}
public override void Disable()
{
if (CueSDK.IsInitialized)
CueSDK.Reinitialize();
}
public override void UpdateDevice(Brush brush)
{
if (!CanUse || brush == null)
return;
var leds = CueSDK.MouseSDK.Leds.Count();
var rect = new Rect(new Size(leds*20, leds*20));
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
c.DrawRectangle(brush, null, rect);
var img = ImageUtilities.DrawinVisualToBitmap(visual, rect);
var ledIndex = 0;
// Color each LED according to one of the pixels
foreach (var corsairLed in CueSDK.MouseSDK.Leds)
{
corsairLed.Color = ledIndex == 0
? img.GetPixel(0, 0)
: img.GetPixel((ledIndex + 1)*20 - 1, (ledIndex + 1)*20 - 1);
ledIndex++;
}
CueSDK.MouseSDK.Update();
}
private static bool CanInitializeSdk()
{
// This will skip the check-loop if the SDK is initialized
if (CueSDK.IsInitialized)
return CueSDK.IsSDKAvailable(CorsairDeviceType.Mouse);
for (var tries = 0; tries < 9; tries++)
{
if (CueSDK.IsSDKAvailable(CorsairDeviceType.Mouse))
return true;
Thread.Sleep(2000);
}
return false;
}
}
}

View File

@ -0,0 +1,111 @@
using System.Drawing;
using System.Threading;
using System.Windows;
using Artemis.Properties;
using Artemis.Utilities;
using CUE.NET;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic.Enums;
using CUE.NET.Devices.Keyboard;
using Point = System.Drawing.Point;
namespace Artemis.DeviceProviders.Corsair
{
public class CorsairRGB : KeyboardProvider
{
private CorsairKeyboard _keyboard;
private ImageBrush _keyboardBrush;
public CorsairRGB()
{
Name = "Corsair RGB Keyboards";
CantEnableText = "Couldn't connect to your Corsair keyboard.\n" +
"Please check your cables and/or drivers (could be outdated) and that Corsair Utility Engine is running.\n" +
"In CUE, make sure \"Enable SDK\" is checked under Settings > Program.\n\n" +
"If needed, you can select a different keyboard in Artemis under settings.";
}
public override bool CanEnable()
{
// This will skip the check-loop if the SDK is initialized
if (CueSDK.IsInitialized)
return CueSDK.IsSDKAvailable(CorsairDeviceType.Keyboard);
for (var tries = 0; tries < 9; tries++)
{
if (CueSDK.IsSDKAvailable(CorsairDeviceType.Keyboard))
return true;
Thread.Sleep(2000);
}
return false;
}
/// <summary>
/// Enables the SDK and sets updatemode to manual as well as the color of the background to black.
/// </summary>
public override void Enable()
{
if (!CueSDK.IsInitialized)
CueSDK.Initialize();
_keyboard = CueSDK.KeyboardSDK;
switch (_keyboard.DeviceInfo.Model)
{
case "K95 RGB":
Height = 7;
Width = 25;
PreviewSettings = new PreviewSettings(676, 190, new Thickness(0, -15, 0, 0), Resources.k95);
break;
case "K70 RGB":
Height = 7;
Width = 21;
PreviewSettings = new PreviewSettings(676, 210, new Thickness(0, -25, 0, 0), Resources.k70);
break;
case "K65 RGB":
Height = 7;
Width = 18;
PreviewSettings = new PreviewSettings(610, 240, new Thickness(0, -30, 0, 0), Resources.k65);
break;
case "STRAFE RGB":
Height = 7;
Width = 22;
PreviewSettings = new PreviewSettings(665, 215, new Thickness(0, -5, 0, 0), Resources.strafe);
break;
}
Slug = "corsair-" + _keyboard.DeviceInfo.Model.Replace(' ', '-').ToLower();
_keyboard.Brush = _keyboardBrush ?? (_keyboardBrush = new ImageBrush());
}
public override void Disable()
{
if (CueSDK.IsInitialized)
CueSDK.Reinitialize();
}
/// <summary>
/// Properly resizes any size bitmap to the keyboard by creating a rectangle whose size is dependent on the bitmap
/// size.
/// </summary>
/// <param name="bitmap"></param>
public override void DrawBitmap(Bitmap bitmap)
{
var image = ImageUtilities.ResizeImage(bitmap, Width, Height);
// For STRAFE, stretch the image on row 2.
if (_keyboard.DeviceInfo.Model == "STRAFE RGB")
{
var strafeBitmap = new Bitmap(22, 8);
using (var g = Graphics.FromImage(strafeBitmap))
{
g.DrawImage(image, new Point(0, 0));
g.DrawImage(image, new Rectangle(0, 3, 22, 7), new Rectangle(0, 2, 22, 7), GraphicsUnit.Pixel);
}
image = strafeBitmap;
}
_keyboardBrush.Image = image;
_keyboard.Update();
}
}
}

View File

@ -0,0 +1,40 @@
using System.Windows.Media;
namespace Artemis.DeviceProviders
{
public abstract class DeviceProvider
{
/// <summary>
/// Indicates the device type
/// </summary>
public DeviceType Type { get; set; }
/// <summary>
/// Indicates whether or not the device can be updated
/// </summary>
public bool CanUse { get; set; }
/// <summary>
/// Updates a non-keyboard to take the colours of the provided brush
/// </summary>
/// <param name="brush"></param>
public abstract void UpdateDevice(Brush brush);
/// <summary>
/// Tries to enable the device and updates CanUse accordingly
/// </summary>
public abstract bool TryEnable();
/// <summary>
/// Disables the device
/// </summary>
public abstract void Disable();
}
public enum DeviceType
{
Keyboard,
Mouse,
Headset
}
}

View File

@ -1,24 +1,28 @@
using System.Collections.Generic; using System;
using System.Drawing; using System.Drawing;
using System.Windows; using System.Windows;
using Brush = System.Windows.Media.Brush;
using Size = System.Windows.Size; using Size = System.Windows.Size;
namespace Artemis.KeyboardProviders namespace Artemis.DeviceProviders
{ {
public abstract class KeyboardProvider public abstract class KeyboardProvider : DeviceProvider
{ {
protected KeyboardProvider()
{
Type = DeviceType.Keyboard;
}
public string Name { get; set; } public string Name { get; set; }
public string Slug { get; set; }
public int Height { get; set; } public int Height { get; set; }
public int Width { get; set; } public int Width { get; set; }
public string CantEnableText { get; set; } public string CantEnableText { get; set; }
public List<KeyboardRegion> KeyboardRegions { get; set; }
public PreviewSettings PreviewSettings { get; set; } public PreviewSettings PreviewSettings { get; set; }
public abstract bool CanEnable(); public abstract bool CanEnable();
public abstract void Enable(); public abstract void Enable();
public abstract void Disable();
public abstract void DrawBitmap(Bitmap bitmap); public abstract void DrawBitmap(Bitmap bitmap);
/// <summary> /// <summary>
@ -34,6 +38,16 @@ namespace Artemis.KeyboardProviders
public Bitmap KeyboardBitmap(int scale) => new Bitmap(Width*scale, Height*scale); public Bitmap KeyboardBitmap(int scale) => new Bitmap(Width*scale, Height*scale);
public Rect KeyboardRectangle(int scale) => new Rect(new Size(Width*scale, Height*scale)); public Rect KeyboardRectangle(int scale) => new Rect(new Size(Width*scale, Height*scale));
public override void UpdateDevice(Brush brush)
{
throw new NotImplementedException("KeyboardProvider doesn't implement UpdateDevice, use DrawBitmap instead.");
}
public override bool TryEnable()
{
throw new NotImplementedException("KeyboardProvider doesn't implement TryEnable, use CanEnable instead.");
}
} }
public struct PreviewSettings public struct PreviewSettings

View File

@ -1,38 +1,46 @@
using System.Collections.Generic; using System.Drawing;
using System.Drawing;
using System.Threading; using System.Threading;
using System.Windows; using System.Windows;
using Artemis.KeyboardProviders.Logitech.Utilities; using Artemis.DeviceProviders.Logitech.Utilities;
using Artemis.Properties; using Artemis.Properties;
using Artemis.Utilities; using Artemis.Utilities;
using Point = System.Drawing.Point; using Artemis.Utilities.LogitechDll;
using Microsoft.Win32;
namespace Artemis.KeyboardProviders.Logitech namespace Artemis.DeviceProviders.Logitech
{ {
internal class Orion : KeyboardProvider internal class Orion : KeyboardProvider
{ {
public Orion() public Orion()
{ {
Name = "Logitech G910 RGB"; Name = "Logitech G910 RGB";
Slug = "logitech-g910";
CantEnableText = "Couldn't connect to your Logitech G910.\n" + CantEnableText = "Couldn't connect to your Logitech G910.\n" +
"Please check your cables and updating the Logitech Gaming Software\n" + "Please check your cables and updating the Logitech Gaming Software\n" +
"A minimum version of 8.81.15 is required.\n\n" + "A minimum version of 8.81.15 is required.\n\n" +
"If needed, you can select a different keyboard in Artemis under settings."; "If needed, you can select a different keyboard in Artemis under settings.";
Height = 6; Height = 6;
Width = 21; Width = 21;
PreviewSettings = new PreviewSettings(626, 175, new Thickness(0, -15, 0, 0), Resources.g910); PreviewSettings = new PreviewSettings(540, 154, new Thickness(25, -80, 0, 0), Resources.g910);
KeyboardRegions = new List<KeyboardRegion>
{
new KeyboardRegion("TopRow", new Point(0, 0), new Point(18, 0)),
new KeyboardRegion("NumPad", new Point(17, 1), new Point(21, 6)),
new KeyboardRegion("QWER", new Point(2, 2), new Point(5, 2))
};
} }
public override bool CanEnable() public override bool CanEnable()
{ {
//if (DllManager.RestoreDll()) //Check to see if VC++ 2012 x64 is installed.
// RestoreDll();
if (Registry.LocalMachine.OpenSubKey(
@"SOFTWARE\Classes\Installer\Dependencies\{ca67548a-5ebe-413a-b50c-4b9ceb6d66c6}") == null)
{
CantEnableText = "Couldn't connect to your Logitech G910.\n" +
"The Visual C 2012 Redistributable could not be found, which is required.\n" +
"Please download it by going to the following URL:\n\n" +
"https://www.microsoft.com/download/confirmation.aspx?id=30679";
return false;
}
if (DllManager.RestoreDll())
RestoreDll();
int majorNum = 0, minorNum = 0, buildNum = 0; int majorNum = 0, minorNum = 0, buildNum = 0;
LogitechGSDK.LogiLedInit(); LogitechGSDK.LogiLedInit();

View File

@ -2,7 +2,7 @@
using System.Windows.Forms; using System.Windows.Forms;
using Artemis.Utilities.Keyboard; using Artemis.Utilities.Keyboard;
namespace Artemis.KeyboardProviders.Logitech.Utilities namespace Artemis.DeviceProviders.Logitech.Utilities
{ {
public static class KeyMap public static class KeyMap
{ {

View File

@ -1,4 +1,4 @@
namespace Artemis.KeyboardProviders.Logitech.Utilities namespace Artemis.DeviceProviders.Logitech.Utilities
{ {
public enum KeyboardNames public enum KeyboardNames
{ {

View File

@ -2,7 +2,7 @@
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace Artemis.KeyboardProviders.Logitech.Utilities namespace Artemis.DeviceProviders.Logitech.Utilities
{ {
public class LogitechGSDK public class LogitechGSDK
{ {

View File

@ -3,7 +3,7 @@ using System.Drawing.Drawing2D;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Artemis.KeyboardProviders.Logitech.Utilities namespace Artemis.DeviceProviders.Logitech.Utilities
{ {
public static class OrionUtilities public static class OrionUtilities
{ {

View File

@ -1,19 +1,26 @@
using System.Drawing; using System.Drawing;
using Artemis.KeyboardProviders.Razer.Utilities; using System.Windows;
using Artemis.DeviceProviders.Razer.Utilities;
using Artemis.Properties;
using Corale.Colore.Core; using Corale.Colore.Core;
using Corale.Colore.Razer; using Corale.Colore.Razer;
using Constants = Corale.Colore.Razer.Keyboard.Constants; using Constants = Corale.Colore.Razer.Keyboard.Constants;
namespace Artemis.KeyboardProviders.Razer namespace Artemis.DeviceProviders.Razer
{ {
public class BlackWidow : KeyboardProvider public class BlackWidow : KeyboardProvider
{ {
public BlackWidow() public BlackWidow()
{ {
Name = "Razer BlackWidow Chroma"; Name = "Razer BlackWidow Chroma";
Slug = "razer-blackwidow-chroma";
CantEnableText = "Couldn't connect to your Razer BlackWidow Chroma.\n" + CantEnableText = "Couldn't connect to your Razer BlackWidow Chroma.\n" +
"Please check your cables and try updating Razer Synapse.\n\n" + "Please check your cables and try updating Razer Synapse.\n\n" +
"If needed, you can select a different keyboard in Artemis under settings."; "If needed, you can select a different keyboard in Artemis under settings.";
Height = Constants.MaxRows;
Width = Constants.MaxColumns;
PreviewSettings = new PreviewSettings(665, 175, new Thickness(0, -15, 0, 0), Resources.blackwidow);
} }
public override bool CanEnable() public override bool CanEnable()
@ -30,12 +37,6 @@ namespace Artemis.KeyboardProviders.Razer
public override void Enable() public override void Enable()
{ {
Chroma.Instance.Initialize(); Chroma.Instance.Initialize();
Height = Constants.MaxRows;
Width = Constants.MaxColumns;
KeyboardRegions.Add(new KeyboardRegion("TopRow", new Point(0, 0), new Point(19, 0)));
KeyboardRegions.Add(new KeyboardRegion("NumPad", new Point(20, 1), new Point(23, 6)));
KeyboardRegions.Add(new KeyboardRegion("QWER", new Point(2, 2), new Point(5, 2)));
} }
public override void Disable() public override void Disable()
@ -46,7 +47,6 @@ namespace Artemis.KeyboardProviders.Razer
public override void DrawBitmap(Bitmap bitmap) public override void DrawBitmap(Bitmap bitmap)
{ {
var razerArray = RazerUtilities.BitmapColorArray(bitmap, Height, Width); var razerArray = RazerUtilities.BitmapColorArray(bitmap, Height, Width);
Chroma.Instance.Keyboard.SetCustom(razerArray); Chroma.Instance.Keyboard.SetCustom(razerArray);
} }
} }

View File

@ -2,7 +2,7 @@
using Artemis.Utilities; using Artemis.Utilities;
using Corale.Colore.Razer.Keyboard.Effects; using Corale.Colore.Razer.Keyboard.Effects;
namespace Artemis.KeyboardProviders.Razer.Utilities namespace Artemis.DeviceProviders.Razer.Utilities
{ {
public static class RazerUtilities public static class RazerUtilities
{ {

View File

@ -1,12 +1,16 @@
namespace Artemis.Events using Artemis.DeviceProviders;
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

@ -0,0 +1,11 @@
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles;
using Artemis.ViewModels.Profiles;
namespace Artemis.InjectionFactories
{
public interface ILayerEditorVmFactory
{
LayerEditorViewModel CreateLayerEditorVm(IDataModel dataModel, LayerModel layer);
}
}

View File

@ -0,0 +1,13 @@
using Artemis.Managers;
using Artemis.Models;
using Artemis.ViewModels.Profiles;
using Caliburn.Micro;
namespace Artemis.InjectionFactories
{
public interface IProfileEditorVmFactory
{
ProfileEditorViewModel CreateProfileEditorVm(IEventAggregator events, MainManager mainManager,
EffectModel gameModel, string lastProfile);
}
}

View File

@ -0,0 +1,59 @@
using Artemis.DeviceProviders;
using Artemis.DeviceProviders.Corsair;
using Artemis.DeviceProviders.Logitech;
using Artemis.DeviceProviders.Razer;
using Artemis.Modules.Effects.AudioVisualizer;
using Artemis.Modules.Effects.TypeWave;
using Artemis.Modules.Effects.WindowsProfile;
using Artemis.Modules.Games.CounterStrike;
using Artemis.Modules.Games.Dota2;
using Artemis.Modules.Games.Overwatch;
using Artemis.Modules.Games.RocketLeague;
using Artemis.Modules.Games.TheDivision;
using Artemis.Modules.Games.Witcher3;
using Artemis.Modules.Overlays.VolumeDisplay;
using Artemis.ViewModels.Abstract;
using Ninject.Modules;
namespace Artemis.InjectionModules
{
public class ArtemisModules : NinjectModule
{
public override void Load()
{
#region Modules
// Effects
Bind<EffectViewModel>().To<AudioVisualizerViewModel>().InSingletonScope();
Bind<EffectViewModel>().To<TypeWaveViewModel>().InSingletonScope();
Bind<EffectViewModel>().To<WindowsProfileViewModel>().InSingletonScope();
//Bind<EffectViewModel>().To<AmbientLightningEffectViewModel>().InSingletonScope();
// Games
Bind<GameViewModel>().To<CounterStrikeViewModel>().InSingletonScope();
Bind<GameViewModel>().To<Dota2ViewModel>().InSingletonScope();
Bind<GameViewModel>().To<RocketLeagueViewModel>().InSingletonScope();
Bind<GameViewModel>().To<TheDivisionViewModel>().InSingletonScope();
Bind<GameViewModel>().To<Witcher3ViewModel>().InSingletonScope();
Bind<GameViewModel>().To<OverwatchViewModel>().InSingletonScope();
// Overlays
Bind<OverlayViewModel>().To<VolumeDisplayViewModel>().InSingletonScope();
#endregion
#region Devices
// Keyboards
Bind<DeviceProvider>().To<CorsairRGB>().InSingletonScope();
Bind<DeviceProvider>().To<Orion>().InSingletonScope();
Bind<DeviceProvider>().To<BlackWidow>().InSingletonScope();
// Mice
Bind<DeviceProvider>().To<CorsairMice>().InSingletonScope();
// Headsets
Bind<DeviceProvider>().To<CorsairHeadsets>().InSingletonScope();
#endregion
}
}
}

View File

@ -0,0 +1,35 @@
using Artemis.InjectionFactories;
using Artemis.Modules.Effects.ProfilePreview;
using Artemis.Services;
using Artemis.ViewModels;
using Artemis.ViewModels.Abstract;
using Artemis.ViewModels.Profiles;
using Caliburn.Micro;
using Ninject.Extensions.Factory;
using Ninject.Modules;
namespace Artemis.InjectionModules
{
internal class BaseModules : NinjectModule
{
public override void Load()
{
// ViewModels
Bind<IScreen>().To<ShellViewModel>().InSingletonScope();
Bind<IProfileEditorVmFactory>().ToFactory();
Bind<ILayerEditorVmFactory>().ToFactory();
Bind<ProfileViewModel>().ToSelf();
Bind<BaseViewModel>().To<WelcomeViewModel>().InSingletonScope();
Bind<BaseViewModel>().To<EffectsViewModel>().InSingletonScope();
Bind<BaseViewModel>().To<GamesViewModel>().InSingletonScope();
Bind<BaseViewModel>().To<OverlaysViewModel>().InSingletonScope();
// Models
Bind<ProfilePreviewModel>().ToSelf().InSingletonScope();
// Services
Bind<MetroDialogService>().ToSelf().InSingletonScope();
}
}
}

View File

@ -0,0 +1,17 @@
using Artemis.Managers;
using Ninject.Modules;
namespace Artemis.InjectionModules
{
internal class ManagerModules : NinjectModule
{
public override void Load()
{
Bind<MainManager>().ToSelf().InSingletonScope();
Bind<LoopManager>().ToSelf().InSingletonScope();
Bind<DeviceManager>().ToSelf().InSingletonScope();
Bind<EffectManager>().ToSelf().InSingletonScope();
Bind<ProfileManager>().ToSelf().InSingletonScope();
}
}
}

View File

@ -1,4 +1,5 @@
using System.Collections; using System.Linq;
using System.Reflection;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Interactivity; using System.Windows.Interactivity;
@ -6,21 +7,19 @@ using System.Windows.Interactivity;
namespace Artemis.ItemBehaviours namespace Artemis.ItemBehaviours
{ {
/// <summary> /// <summary>
/// Steve Greatrex - http://stackoverflow.com/a/5118406/5015269 /// Chaitanya Kadamati - http://stackoverflow.com/a/33233162/5015269
/// </summary> /// </summary>
public class BindableSelectedItemBehavior : Behavior<TreeView> public class BindableSelectedItemBehavior : Behavior<TreeView>
{ {
protected override void OnAttached() protected override void OnAttached()
{ {
base.OnAttached(); base.OnAttached();
AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged; AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged;
} }
protected override void OnDetaching() protected override void OnDetaching()
{ {
base.OnDetaching(); base.OnDetaching();
if (AssociatedObject != null) if (AssociatedObject != null)
AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged; AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged;
} }
@ -38,49 +37,59 @@ namespace Artemis.ItemBehaviours
set { SetValue(SelectedItemProperty, value); } set { SetValue(SelectedItemProperty, value); }
} }
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", public static readonly DependencyProperty SelectedItemProperty =
typeof (object), typeof (BindableSelectedItemBehavior), new UIPropertyMetadata(null, OnSelectedItemChanged)); DependencyProperty.Register("SelectedItem", typeof(object), typeof(BindableSelectedItemBehavior),
new UIPropertyMetadata(null, OnSelectedItemChanged));
private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{ {
var item = ((BindableSelectedItemBehavior) sender).AssociatedObject var behavior = sender as BindableSelectedItemBehavior;
.ItemContainerGenerator.ContainerFromItem(e.NewValue) as TreeViewItem; var tree = behavior?.AssociatedObject;
if (item != null) if (tree == null)
item.SetValue(TreeViewItem.IsSelectedProperty, true);
else
ClearTreeViewSelection(((BindableSelectedItemBehavior) sender).AssociatedObject);
}
/// <summary>
/// Clears a TreeView's selected item recursively
/// Tom Wright - http://stackoverflow.com/a/1406116/5015269
/// </summary>
/// <param name="tv"></param>
public static void ClearTreeViewSelection(TreeView tv)
{
if (tv != null)
ClearTreeViewItemsControlSelection(tv.Items, tv.ItemContainerGenerator);
}
/// <summary>
/// Clears a TreeView's selected item recursively
/// Tom Wright - http://stackoverflow.com/a/1406116/5015269
/// </summary>
/// <param name="ic"></param>
/// <param name="icg"></param>
private static void ClearTreeViewItemsControlSelection(ICollection ic, ItemContainerGenerator icg)
{
if ((ic == null) || (icg == null))
return; return;
for (var i = 0; i < ic.Count; i++) if (e.NewValue == null)
{ {
var tvi = icg.ContainerFromIndex(i) as TreeViewItem; foreach (var item in tree.Items.OfType<TreeViewItem>())
if (tvi == null) item.SetValue(TreeViewItem.IsSelectedProperty, false);
continue;
ClearTreeViewItemsControlSelection(tvi.Items, tvi.ItemContainerGenerator);
tvi.IsSelected = false;
} }
var treeViewItem = e.NewValue as TreeViewItem;
if (treeViewItem != null)
treeViewItem.SetValue(TreeViewItem.IsSelectedProperty, true);
else
{
var itemsHostProperty = tree.GetType()
.GetProperty("ItemsHost", BindingFlags.NonPublic | BindingFlags.Instance);
var itemsHost = itemsHostProperty?.GetValue(tree, null) as Panel;
if (itemsHost == null)
return;
foreach (var item in itemsHost.Children.OfType<TreeViewItem>())
{
if (WalkTreeViewItem(item, e.NewValue))
break;
}
}
}
public static bool WalkTreeViewItem(TreeViewItem treeViewItem, object selectedValue)
{
if (treeViewItem.DataContext == selectedValue)
{
treeViewItem.SetValue(TreeViewItem.IsSelectedProperty, true);
treeViewItem.Focus();
return true;
}
var itemsHostProperty = treeViewItem.GetType()
.GetProperty("ItemsHost", BindingFlags.NonPublic | BindingFlags.Instance);
var itemsHost = itemsHostProperty?.GetValue(treeViewItem, null) as Panel;
if (itemsHost == null) return false;
foreach (var item in itemsHost.Children.OfType<TreeViewItem>())
{
if (WalkTreeViewItem(item, selectedValue))
break;
}
return false;
} }
#endregion #endregion

View File

@ -1,140 +0,0 @@
using System.Collections.Generic;
using System.Drawing;
using System.Threading;
using System.Windows;
using Artemis.Properties;
using Artemis.Utilities;
using CUE.NET;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic.Enums;
using CUE.NET.Devices.Keyboard;
using CUE.NET.Exceptions;
using Point = System.Drawing.Point;
namespace Artemis.KeyboardProviders.Corsair
{
internal class CorsairRGB : KeyboardProvider
{
private CorsairKeyboard _keyboard;
public CorsairRGB()
{
Name = "Corsair RGB Keyboards";
CantEnableText = "Couldn't connect to your Corsair keyboard.\n" +
"Please check your cables and/or drivers (could be outdated) and that Corsair Utility Engine is running.\n\n" +
"If needed, you can select a different keyboard in Artemis under settings.";
KeyboardRegions = new List<KeyboardRegion>();
}
public override bool CanEnable()
{
// Try for about 10 seconds, in case CUE isn't started yet
var tries = 0;
while (tries < 9)
{
try
{
CueSDK.Initialize();
}
catch (CUEException e)
{
if (e.Error == CorsairError.ServerNotFound)
{
tries++;
Thread.Sleep(1000);
continue;
}
}
catch (WrapperException)
{
CueSDK.Reinitialize();
return true;
}
return true;
}
return false;
}
/// <summary>
/// Enables the SDK and sets updatemode to manual as well as the color of the background to black.
/// </summary>
public override void Enable()
{
try
{
CueSDK.Initialize();
}
catch (WrapperException)
{
/*CUE is already initialized*/
}
_keyboard = CueSDK.KeyboardSDK;
switch (_keyboard.DeviceInfo.Model)
{
case "K95 RGB":
Height = 7;
Width = 25;
PreviewSettings = new PreviewSettings(626, 175, new Thickness(0, -15, 0, 0), Resources.k95);
KeyboardRegions.Add(new KeyboardRegion("TopRow", new Point(0, 1), new Point(20, 1)));
KeyboardRegions.Add(new KeyboardRegion("NumPad", new Point(21, 2), new Point(25, 7)));
KeyboardRegions.Add(new KeyboardRegion("QWER", new Point(5, 3), new Point(8, 3)));
break;
case "K70 RGB":
Height = 7;
Width = 21;
PreviewSettings = new PreviewSettings(626, 175, new Thickness(0, -15, 0, 0), Resources.k70);
KeyboardRegions.Add(new KeyboardRegion("TopRow", new Point(0, 1), new Point(18, 1)));
KeyboardRegions.Add(new KeyboardRegion("NumPad", new Point(17, 2), new Point(21, 7)));
KeyboardRegions.Add(new KeyboardRegion("QWER", new Point(2, 3), new Point(5, 3)));
break;
case "K65 RGB":
Height = 7;
Width = 18;
PreviewSettings = new PreviewSettings(626, 175, new Thickness(0, -15, 0, 0), Resources.k65);
KeyboardRegions.Add(new KeyboardRegion("TopRow", new Point(0, 1), new Point(18, 1)));
KeyboardRegions.Add(new KeyboardRegion("NumPad", new Point(17, 2), new Point(20, 7)));
KeyboardRegions.Add(new KeyboardRegion("QWER", new Point(2, 3), new Point(5, 3)));
break;
case "STRAFE RGB":
Height = 6;
Width = 22;
PreviewSettings = new PreviewSettings(626, 175, new Thickness(0, -15, 0, 0), Resources.strafe);
KeyboardRegions.Add(new KeyboardRegion("TopRow", new Point(0, 1), new Point(18, 1)));
KeyboardRegions.Add(new KeyboardRegion("NumPad", new Point(18, 2), new Point(22, 7)));
KeyboardRegions.Add(new KeyboardRegion("QWER", new Point(1, 3), new Point(4, 3)));
break;
}
}
public override void Disable()
{
CueSDK.Reinitialize();
}
/// <summary>
/// Properly resizes any size bitmap to the keyboard by creating a rectangle whose size is dependent on the bitmap
/// size.
/// </summary>
/// <param name="bitmap"></param>
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 brush = new ImageBrush
{
Image = fixedImage
};
_keyboard.Brush = brush;
_keyboard.Update();
}
}
}

View File

@ -1,21 +0,0 @@
using System.Drawing;
namespace Artemis.KeyboardProviders
{
public class KeyboardRegion
{
public KeyboardRegion(string regionName, Point topLeft, Point bottomRight)
{
RegionName = regionName;
TopLeft = topLeft;
BottomRight = bottomRight;
}
public string RegionName { get; set; }
public Point TopLeft { get; set; }
public Point BottomRight { get; set; }
public Rectangle GetRectangle()
=> new Rectangle(TopLeft.X, TopLeft.Y, BottomRight.X - TopLeft.X, BottomRight.Y - TopLeft.Y);
}
}

View File

@ -1,20 +0,0 @@
using System.Collections.Generic;
using Artemis.KeyboardProviders.Corsair;
using Artemis.KeyboardProviders.Logitech;
using Artemis.KeyboardProviders.Razer;
namespace Artemis.KeyboardProviders
{
public static class ProviderHelper
{
public static List<KeyboardProvider> GetKeyboardProviders()
{
return new List<KeyboardProvider>
{
new CorsairRGB(),
new Orion(),
new BlackWidow()
};
}
}
}

View File

@ -0,0 +1,160 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Artemis.DeviceProviders;
using Artemis.Events;
using Artemis.Services;
using Artemis.Settings;
using Caliburn.Micro;
using Ninject;
using Ninject.Extensions.Logging;
namespace Artemis.Managers
{
/// <summary>
/// Manages the keyboard providers
/// </summary>
public class DeviceManager
{
private readonly IEventAggregator _events;
private readonly ILogger _logger;
public DeviceManager(IEventAggregator events, ILogger logger, List<DeviceProvider> deviceProviders)
{
_logger = logger;
_logger.Info("Intializing DeviceManager");
_events = events;
KeyboardProviders = deviceProviders.Where(d => d.Type == DeviceType.Keyboard)
.Cast<KeyboardProvider>().ToList();
MiceProviders = deviceProviders.Where(d => d.Type == DeviceType.Mouse).ToList();
HeadsetProviders = deviceProviders.Where(d => d.Type == DeviceType.Headset).ToList();
_logger.Info("Intialized DeviceManager");
}
public List<DeviceProvider> HeadsetProviders { get; set; }
public List<DeviceProvider> MiceProviders { get; set; }
[Inject]
public MetroDialogService DialogService { get; set; }
public List<KeyboardProvider> KeyboardProviders { get; set; }
public KeyboardProvider ActiveKeyboard { get; set; }
public bool ChangingKeyboard { get; private set; }
/// <summary>
/// Enables the last keyboard according to the settings file
/// </summary>
public void EnableLastKeyboard()
{
_logger.Debug("Getting last keyboard: {0}", General.Default.LastKeyboard);
if (string.IsNullOrEmpty(General.Default.LastKeyboard))
return;
var keyboard = KeyboardProviders.FirstOrDefault(k => k.Name == General.Default.LastKeyboard);
EnableKeyboard(keyboard);
}
/// <summary>
/// Enables the given keyboard
/// </summary>
/// <param name="keyboardProvider"></param>
public void EnableKeyboard(KeyboardProvider keyboardProvider)
{
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)
{
wasNull = true;
ActiveKeyboard = keyboardProvider;
}
_logger.Debug("Enabling keyboard: {0}", keyboardProvider.Name);
if (!wasNull)
ReleaseActiveKeyboard();
// Disable everything if there's no active keyboard found
if (!keyboardProvider.CanEnable())
{
DialogService.ShowErrorMessageBox(keyboardProvider.CantEnableText);
ActiveKeyboard = null;
General.Default.LastKeyboard = null;
General.Default.Save();
_logger.Warn("Failed enabling keyboard: {0}", keyboardProvider.Name);
ChangingKeyboard = false;
return;
}
ActiveKeyboard = keyboardProvider;
ActiveKeyboard.Enable();
General.Default.LastKeyboard = ActiveKeyboard.Name;
General.Default.Save();
EnableUsableDevices();
ChangingKeyboard = false;
_events.PublishOnUIThread(new ActiveKeyboardChanged(oldKeyboard, ActiveKeyboard));
_logger.Debug("Enabled keyboard: {0}", keyboardProvider.Name);
}
}
private void EnableUsableDevices()
{
foreach (var mouseProvider in MiceProviders)
mouseProvider.TryEnable();
foreach (var headsetProvider in HeadsetProviders)
headsetProvider.TryEnable();
}
/// <summary>
/// Releases the active keyboard
/// </summary>
/// <param name="save">Whether to save the LastKeyboard (making it null)</param>
public void ReleaseActiveKeyboard(bool save = false)
{
lock (this)
{
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;
if (save)
{
General.Default.LastKeyboard = null;
General.Default.Save();
}
_events.PublishOnUIThread(new ActiveKeyboardChanged(oldKeyboard, null));
_logger.Debug("Released keyboard: {0}", releaseName);
}
}
}
}

View File

@ -1,41 +1,38 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading;
using Artemis.Events; using Artemis.Events;
using Artemis.Models; using Artemis.Models;
using Artemis.Modules.Effects.ProfilePreview; using Artemis.Modules.Effects.ProfilePreview;
using Artemis.Settings; using Artemis.Settings;
using Caliburn.Micro; using Caliburn.Micro;
using NLog; using Ninject.Extensions.Logging;
using LogManager = NLog.LogManager;
namespace Artemis.Managers namespace Artemis.Managers
{ {
/// <summary>
/// Manages the effects
/// </summary>
public class EffectManager public class EffectManager
{ {
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private readonly DeviceManager _deviceManager;
private readonly IEventAggregator _events; private readonly IEventAggregator _events;
private readonly MainManager _mainManager; private readonly ILogger _logger;
private EffectModel _activeEffect; private EffectModel _activeEffect;
private bool _clearing;
public EffectManager(MainManager mainManager, IEventAggregator events) public EffectManager(ILogger logger, IEventAggregator events, DeviceManager deviceManager)
{ {
Logger.Info("Intializing EffectManager"); _logger = logger;
_mainManager = mainManager; _logger.Info("Intializing EffectManager");
_events = events; _events = events;
_deviceManager = deviceManager;
EffectModels = new List<EffectModel>(); EffectModels = new List<EffectModel>();
ProfilePreviewModel = new ProfilePreviewModel(_mainManager);
Logger.Info("Intialized EffectManager"); _logger.Info("Intialized EffectManager");
} }
public EffectModel PauseEffect { get; set; }
/// <summary>
/// Used by ViewModels to show a preview of the profile currently being edited
/// </summary>
public ProfilePreviewModel ProfilePreviewModel { get; set; } public ProfilePreviewModel ProfilePreviewModel { get; set; }
/// <summary> /// <summary>
@ -75,134 +72,101 @@ namespace Artemis.Managers
/// <returns>Whether enabling was successful or not.</returns> /// <returns>Whether enabling was successful or not.</returns>
public EffectModel GetLastEffect() public EffectModel GetLastEffect()
{ {
Logger.Debug("Getting last effect: {0}", General.Default.LastEffect); _logger.Debug("Getting last effect: {0}", General.Default.LastEffect);
if (General.Default.LastEffect == null) return General.Default.LastEffect == null
return null; ? null
: EffectModels.FirstOrDefault(e => e.Name == General.Default.LastEffect);
var effect = EffectModels.FirstOrDefault(e => e.Name == General.Default.LastEffect);
// Fall back to the first effect found, in case settings are messed up
return effect;
} }
/// <summary> /// <summary>
/// Disables the current effect and changes it to the provided effect. /// Disables the current effect and changes it to the provided effect.
/// </summary> /// </summary>
/// <param name="effectModel"></param> /// <param name="effectModel">The effect to activate</param>
/// <param name="force">Changes the effect, even if it's already running (effectively restarting it)</param> /// <param name="loopManager">Optionally pass the LoopManager to automatically start it, if it's not running.</param>
public void ChangeEffect(EffectModel effectModel, bool force = false) public void ChangeEffect(EffectModel effectModel, LoopManager loopManager = null)
{ {
if (effectModel == null)
throw new ArgumentNullException(nameof(effectModel));
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");
if (_deviceManager.ActiveKeyboard == null)
_deviceManager.EnableLastKeyboard();
// If still null, no last keyboard, so stop.
if (_deviceManager.ActiveKeyboard == null)
{
_logger.Debug("Cancelling effect change, no LastKeyboard");
return;
}
// Game models are only used if they are enabled // Game models are only used if they are enabled
var gameModel = effectModel as GameModel; var gameModel = effectModel as GameModel;
if (gameModel != null) if (gameModel != null)
if (!gameModel.Enabled) if (!gameModel.Enabled)
{
_logger.Debug("Cancelling effect change, provided game not enabled");
return; return;
}
if (ActiveEffect != null)
if (effectModel.Name == ActiveEffect.Name && !force) var wasNull = false;
if (ActiveEffect == null)
{
wasNull = true;
ActiveEffect = effectModel;
}
lock (ActiveEffect)
{
if (!wasNull)
ActiveEffect.Dispose();
ActiveEffect = effectModel;
ActiveEffect.Enable();
if (!ActiveEffect.Initialized)
{
_logger.Debug("Cancelling effect change, couldn't initialize the effect ({0})", effectModel.Name);
ActiveEffect = null;
return; return;
}
Logger.Debug("Changing effect to: {0}, force: {1}", effectModel?.Name, force);
// If the main manager is running, pause it and safely change the effect
if (_mainManager.Running)
{
ChangeEffectWithPause(effectModel);
return;
} }
// If it's not running start it, and let the next recursion handle changing the effect if (loopManager != null && !loopManager.Running)
_mainManager.Start(effectModel);
}
private void ChangeEffectWithPause(EffectModel effectModel)
{
var tryCount = 0;
while (PauseEffect != null)
{ {
Thread.Sleep(500); _logger.Debug("Starting LoopManager for effect change");
tryCount++; loopManager.Start();
if (tryCount > 20)
throw new Exception("Couldn't change effect before the time expired");
} }
// Don't interrupt an ongoing effect change _logger.Debug("Changed active effect to: {0}", effectModel.Name);
if (PauseEffect != null)
{
Logger.Debug("Change effect with pause cancelled");
return;
}
Logger.Debug("Changing effect with pause: {0}", effectModel?.Name);
PauseEffect = effectModel;
_mainManager.Pause();
_mainManager.PauseCallback += ChangeEffectPauseCallback;
}
private void ChangeEffectPauseCallback()
{
_mainManager.PauseCallback -= ChangeEffectPauseCallback;
// Change effect logic
ActiveEffect?.Dispose();
ActiveEffect = PauseEffect;
ActiveEffect.Enable();
_mainManager.Unpause();
PauseEffect = null;
Logger.Debug("Finishing change effect with pause");
if (ActiveEffect is GameModel || ActiveEffect is ProfilePreviewModel) if (ActiveEffect is GameModel || ActiveEffect is ProfilePreviewModel)
return; return;
// Non-game effects are stored as the new LastEffect. // Non-game effects are stored as the new LastEffect.
General.Default.LastEffect = ActiveEffect.Name; General.Default.LastEffect = ActiveEffect?.Name;
General.Default.Save(); General.Default.Save();
} }
/// <summary> /// <summary>
/// Clears the current effect /// Clears the current effect
/// </summary> /// </summary>
public void ClearEffect() public void ClearEffect()
{ {
if (_clearing)
return;
// Don't mess with the ActiveEffect if in the process of changing the effect.
if (PauseEffect != null)
return;
if (ActiveEffect == null) if (ActiveEffect == null)
return; return;
_clearing = true; lock (ActiveEffect)
Logger.Debug("Clearing active effect");
_mainManager.Pause();
_mainManager.PauseCallback += ClearEffectPauseCallback;
}
private void ClearEffectPauseCallback()
{
_mainManager.PauseCallback -= ClearEffectPauseCallback;
if (PauseEffect != null)
{ {
Logger.Debug("Cancelling clearing effect"); ActiveEffect.Dispose();
return; ActiveEffect = null;
General.Default.LastEffect = null;
General.Default.Save();
} }
ActiveEffect.Dispose();
ActiveEffect = null;
General.Default.LastEffect = null; _logger.Debug("Cleared active effect");
General.Default.Save();
_clearing = false;
Logger.Debug("Finishing clearing active effect");
_mainManager.Unpause();
} }
/// <summary> /// <summary>
@ -211,7 +175,7 @@ namespace Artemis.Managers
/// <param name="activeEffect"></param> /// <param name="activeEffect"></param>
public void DisableGame(EffectModel activeEffect) public void DisableGame(EffectModel activeEffect)
{ {
Logger.Debug("Disabling game: {0}", activeEffect?.Name); _logger.Debug("Disabling game: {0}", activeEffect?.Name);
if (GetLastEffect() == null) if (GetLastEffect() == null)
ClearEffect(); ClearEffect();
else else

View File

@ -1,122 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Artemis.Events;
using Artemis.KeyboardProviders;
using Artemis.Settings;
using Caliburn.Micro;
using NLog;
using LogManager = NLog.LogManager;
namespace Artemis.Managers
{
public class KeyboardManager
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly IEventAggregator _events;
private readonly MainManager _mainManager;
private KeyboardProvider _activeKeyboard;
public KeyboardManager(MainManager mainManager, IEventAggregator events)
{
Logger.Info("Intializing KeyboardManager");
_mainManager = mainManager;
_events = events;
KeyboardProviders = ProviderHelper.GetKeyboardProviders();
Logger.Info("Intialized KeyboardManager");
}
public List<KeyboardProvider> KeyboardProviders { get; set; }
public KeyboardProvider ActiveKeyboard
{
get { return _activeKeyboard; }
set
{
_activeKeyboard = value;
// Let the ViewModels know
_events.PublishOnUIThread(new ActiveKeyboardChanged(value?.Name));
}
}
public bool CanDisable { get; set; }
/// <summary>
/// Enables the last keyboard according to the settings file
/// </summary>
public void EnableLastKeyboard()
{
Logger.Debug("Enabling last keyboard: {0}", General.Default.LastKeyboard);
if (General.Default.LastKeyboard == null)
return;
if (General.Default.LastKeyboard == "")
return;
var keyboard = KeyboardProviders.FirstOrDefault(k => k.Name == General.Default.LastKeyboard);
EnableKeyboard(keyboard);
}
/// <summary>
/// Enables the given keyboard
/// </summary>
/// <param name="keyboardProvider"></param>
public void EnableKeyboard(KeyboardProvider keyboardProvider)
{
Logger.Debug("Enabling keyboard: {0}", keyboardProvider?.Name);
ReleaseActiveKeyboard();
if (keyboardProvider == null)
return;
if (ActiveKeyboard != null)
if (keyboardProvider.Name == ActiveKeyboard.Name)
return;
// Disable everything if there's no active keyboard found
if (!keyboardProvider.CanEnable())
{
_mainManager.DialogService.ShowErrorMessageBox(keyboardProvider.CantEnableText);
General.Default.LastKeyboard = null;
General.Default.Save();
return;
}
CanDisable = false;
ActiveKeyboard = keyboardProvider;
keyboardProvider.Enable();
General.Default.LastKeyboard = ActiveKeyboard.Name;
General.Default.Save();
CanDisable = true;
}
/// <summary>
/// Releases the active keyboard, if CanDisable is true
/// </summary>
public void ReleaseActiveKeyboard()
{
if (ActiveKeyboard == null || !CanDisable)
return;
ActiveKeyboard.Disable();
Logger.Debug("Released keyboard: {0}", ActiveKeyboard?.Name);
ActiveKeyboard = null;
}
/// <summary>
/// Changes the active keyboard
/// </summary>
/// <param name="keyboardProvider"></param>
public void ChangeKeyboard(KeyboardProvider keyboardProvider)
{
Logger.Debug("Changing active keyboard");
if (keyboardProvider == ActiveKeyboard)
return;
General.Default.LastKeyboard = keyboardProvider?.Name;
General.Default.Save();
Logger.Debug("Restarting for keyboard change");
_mainManager.Restart();
}
}
}

View File

@ -0,0 +1,161 @@
using System;
using System.Drawing;
using System.Linq;
using System.Timers;
using Ninject.Extensions.Logging;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Managers
{
/// <summary>
/// Manages the main programn loop
/// </summary>
public class LoopManager : IDisposable
{
private readonly DeviceManager _deviceManager;
private readonly EffectManager _effectManager;
private readonly ILogger _logger;
private readonly Timer _loopTimer;
public LoopManager(ILogger logger, EffectManager effectManager, DeviceManager deviceManager)
{
_logger = logger;
_effectManager = effectManager;
_deviceManager = deviceManager;
// Setup timers
_loopTimer = new Timer(40);
_loopTimer.Elapsed += Render;
_loopTimer.Start();
}
/// <summary>
/// Gets whether the loop is running
/// </summary>
public bool Running { get; private set; }
public void Dispose()
{
_loopTimer.Stop();
_loopTimer.Dispose();
}
public void Start()
{
if (Running)
return;
_logger.Debug("Starting LoopManager");
if (_deviceManager.ActiveKeyboard == null)
_deviceManager.EnableLastKeyboard();
// If still null, no last keyboard, so stop.
if (_deviceManager.ActiveKeyboard == null)
{
_logger.Debug("Cancel LoopManager start, no keyboard");
return;
}
if (_effectManager.ActiveEffect == null)
{
var lastEffect = _effectManager.GetLastEffect();
if (lastEffect == null)
{
_logger.Debug("Cancel LoopManager start, no effect");
return;
}
_effectManager.ChangeEffect(lastEffect);
}
Running = true;
}
public void Stop()
{
if (!Running)
return;
_logger.Debug("Stopping LoopManager");
Running = false;
_deviceManager.ReleaseActiveKeyboard();
}
private void Render(object sender, ElapsedEventArgs e)
{
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 (_deviceManager.ChangingKeyboard)
return;
// Stop if no active keyboard
if (_deviceManager.ActiveKeyboard == null)
{
_logger.Debug("No active keyboard, stopping");
Stop();
return;
}
lock (_deviceManager.ActiveKeyboard)
{
// Skip frame if effect is still initializing
if (renderEffect.Initialized == false)
return;
// ApplyProperties the current effect
if (renderEffect.Initialized)
renderEffect.Update();
// Get ActiveEffect's bitmap
Bitmap bitmap = null;
Brush mouseBrush = null;
Brush headsetBrush = null;
var mice = _deviceManager.MiceProviders.Where(m => m.CanUse).ToList();
var headsets = _deviceManager.HeadsetProviders.Where(m => m.CanUse).ToList();
if (renderEffect.Initialized)
renderEffect.Render(out bitmap, out mouseBrush, out headsetBrush, mice.Any(), headsets.Any());
// Draw enabled overlays on top of the renderEffect
foreach (var overlayModel in _effectManager.EnabledOverlays)
{
overlayModel.Update();
overlayModel.RenderOverlay(ref bitmap, ref mouseBrush, ref headsetBrush, mice.Any(), headsets.Any());
}
// Update mice and headsets
foreach (var mouse in mice)
mouse.UpdateDevice(mouseBrush);
foreach (var headset in headsets)
headset.UpdateDevice(headsetBrush);
// If no bitmap was generated this frame is done
if (bitmap == null)
return;
// Fill the bitmap's background with black to avoid trailing colors on some keyboards
var fixedBmp = new Bitmap(bitmap.Width, bitmap.Height);
using (var g = Graphics.FromImage(fixedBmp))
{
g.Clear(Color.Black);
g.DrawImage(bitmap, 0, 0);
}
bitmap = fixedBmp;
// Update the keyboard
_deviceManager.ActiveKeyboard?.DrawBitmap(bitmap);
}
}
}
}

View File

@ -1,56 +1,55 @@
using System.ComponentModel; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading; using System.Timers;
using Artemis.Events; using Artemis.Events;
using Artemis.Models; using Artemis.Models;
using Artemis.Services; using Artemis.Modules.Effects.ProfilePreview;
using Artemis.Utilities.GameState; using Artemis.Utilities.GameState;
using Artemis.Utilities.Keyboard; using Artemis.Utilities.Keyboard;
using Artemis.Utilities.LogitechDll; using Artemis.Utilities.LogitechDll;
using Artemis.ViewModels;
using Caliburn.Micro; using Caliburn.Micro;
using NLog; using Ninject;
using LogManager = NLog.LogManager; using Ninject.Extensions.Logging;
namespace Artemis.Managers namespace Artemis.Managers
{ {
public class MainManager /// <summary>
/// Contains all the other managers and non-loop related components
/// </summary>
public class MainManager : IDisposable
{ {
public delegate void PauseCallbackHandler(); public delegate void PauseCallbackHandler();
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private readonly IEventAggregator _events;
private readonly ILogger _logger;
private readonly Timer _processTimer;
private readonly int _fps; public MainManager(IEventAggregator events, ILogger logger, LoopManager loopManager,
private bool _paused; DeviceManager deviceManager, EffectManager effectManager, ProfileManager profileManager)
private bool _restarting;
public MainManager(IEventAggregator events, MetroDialogService dialogService)
{ {
Logger.Info("Intializing MainManager"); _logger = logger;
LoopManager = loopManager;
DeviceManager = deviceManager;
EffectManager = effectManager;
ProfileManager = profileManager;
Events = events; _logger.Info("Intializing MainManager");
DialogService = dialogService;
KeyboardManager = new KeyboardManager(this, Events); _events = events;
EffectManager = new EffectManager(this, Events);
KeyboardHook = new KeyboardHook();
_fps = 25; _processTimer = new Timer(1000);
UpdateWorker = new BackgroundWorker {WorkerSupportsCancellation = true}; _processTimer.Elapsed += ScanProcesses;
ProcessWorker = new BackgroundWorker {WorkerSupportsCancellation = true}; _processTimer.Start();
UpdateWorker.DoWork += UpdateWorker_DoWork;
UpdateWorker.RunWorkerCompleted += BackgroundWorkerExceptionCatcher;
ProcessWorker.DoWork += ProcessWorker_DoWork;
ProcessWorker.RunWorkerCompleted += BackgroundWorkerExceptionCatcher;
// Process worker will always run (and just do nothing when ProgramEnabled is false)
ProcessWorker.RunWorkerAsync();
ProgramEnabled = false; ProgramEnabled = false;
Running = false; Running = false;
// TODO: Dependency inject utilities?
KeyboardHook = new KeyboardHook();
// Create and start the web server // Create and start the web server
GameStateWebServer = new GameStateWebServer(); GameStateWebServer = new GameStateWebServer();
GameStateWebServer.Start(); GameStateWebServer.Start();
@ -59,141 +58,44 @@ namespace Artemis.Managers
PipeServer = new PipeServer(); PipeServer = new PipeServer();
PipeServer.Start("artemis"); PipeServer.Start("artemis");
Logger.Info("Intialized MainManager"); _logger.Info("Intialized MainManager");
} }
[Inject]
public Lazy<ShellViewModel> ShellViewModel { get; set; }
public LoopManager LoopManager { get; }
public DeviceManager DeviceManager { get; set; }
public EffectManager EffectManager { get; set; }
public ProfileManager ProfileManager { get; set; }
public PipeServer PipeServer { get; set; } public PipeServer PipeServer { get; set; }
public BackgroundWorker UpdateWorker { get; set; }
public BackgroundWorker ProcessWorker { get; set; }
public KeyboardManager KeyboardManager { get; set; }
public EffectManager EffectManager { get; set; }
public KeyboardHook KeyboardHook { get; set; } public KeyboardHook KeyboardHook { get; set; }
public GameStateWebServer GameStateWebServer { get; set; } public GameStateWebServer GameStateWebServer { get; set; }
public IEventAggregator Events { get; set; }
public MetroDialogService DialogService { get; set; }
public bool ProgramEnabled { get; private set; } public bool ProgramEnabled { get; private set; }
public bool Suspended { get; set; }
public bool Running { get; private set; } public bool Running { get; private set; }
public event PauseCallbackHandler PauseCallback; public void Dispose()
/// <summary>
/// Take control of the keyboard and start sending data to it
/// </summary>
/// <returns>Whether starting was successful or not</returns>
public bool Start(EffectModel effect = null)
{ {
Logger.Debug("Starting MainManager"); _logger.Debug("Shutting down MainManager");
// Can't take control when not enabled
if (!ProgramEnabled || UpdateWorker.CancellationPending || UpdateWorker.IsBusy || _paused)
return false;
// Do nothing if already running _processTimer.Stop();
if (Running) _processTimer.Dispose();
return true; LoopManager.Stop();
EffectManager.ActiveEffect.Dispose();
// Only continue if a keyboard was loaded
KeyboardManager.EnableLastKeyboard();
if (KeyboardManager.ActiveKeyboard == null)
return false;
Running = true;
if (effect != null)
EffectManager.ChangeEffect(effect);
// Start the update worker
if (!UpdateWorker.IsBusy)
UpdateWorker.RunWorkerAsync();
return Running;
}
/// <summary>
/// Releases control of the keyboard and stop sending data to it
/// </summary>
public void Stop()
{
Logger.Debug("Stopping MainManager");
if (!Running || UpdateWorker.CancellationPending || _paused)
return;
// Stop the update worker
UpdateWorker.CancelAsync();
UpdateWorker.RunWorkerCompleted += FinishStop;
}
private void FinishStop(object sender, RunWorkerCompletedEventArgs e)
{
UpdateWorker.RunWorkerCompleted -= FinishStop;
KeyboardManager.ReleaseActiveKeyboard();
Running = false;
Logger.Debug("Stopped MainManager");
if (e.Error != null || !_restarting)
return;
Start();
_restarting = false;
}
public void Pause()
{
if (!Running || UpdateWorker.CancellationPending || _paused)
return;
Logger.Debug("Pausing MainManager");
_paused = true;
}
public void Unpause()
{
if (!_paused)
return;
Logger.Debug("Unpausing MainManager");
_paused = false;
}
public void Shutdown()
{
Logger.Debug("Shutting down MainManager");
Stop();
ProcessWorker.CancelAsync();
ProcessWorker.CancelAsync();
GameStateWebServer.Stop(); GameStateWebServer.Stop();
PipeServer.Stop(); PipeServer.Stop();
} }
public void Restart()
{
if (_restarting)
return;
Logger.Debug("Restarting MainManager");
if (!Running)
{
Start();
return;
}
_restarting = true;
Stop();
}
/// <summary> /// <summary>
/// Loads the last active effect and starts the program /// Loads the last active effect and starts the program
/// </summary> /// </summary>
public void EnableProgram() public void EnableProgram()
{ {
Logger.Debug("Enabling program"); _logger.Debug("Enabling program");
ProgramEnabled = true; ProgramEnabled = true;
Start(EffectManager.GetLastEffect()); LoopManager.Start();
Events.PublishOnUIThread(new ToggleEnabled(ProgramEnabled)); _events.PublishOnUIThread(new ToggleEnabled(ProgramEnabled));
} }
/// <summary> /// <summary>
@ -201,129 +103,52 @@ namespace Artemis.Managers
/// </summary> /// </summary>
public void DisableProgram() public void DisableProgram()
{ {
Logger.Debug("Disabling program"); _logger.Debug("Disabling program");
Stop(); LoopManager.Stop();
ProgramEnabled = false; ProgramEnabled = false;
Events.PublishOnUIThread(new ToggleEnabled(ProgramEnabled)); _events.PublishOnUIThread(new ToggleEnabled(ProgramEnabled));
} }
#region Workers /// <summary>
/// Manages active games by keeping an eye on their processes
private void UpdateWorker_DoWork(object sender, DoWorkEventArgs e) /// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ScanProcesses(object sender, ElapsedEventArgs e)
{ {
var sw = new Stopwatch(); if (!ProgramEnabled)
while (!UpdateWorker.CancellationPending)
{
// Skip frame when paused
if (_paused)
{
PauseCallback?.Invoke();
Thread.Sleep(1000/_fps);
continue;
}
// Stop if no keyboard/effect are present
if (KeyboardManager.ActiveKeyboard == null || EffectManager.ActiveEffect == null)
{
Thread.Sleep(1000/_fps);
Logger.Debug("No active effect/keyboard, stopping");
if (EffectManager.PauseEffect != null)
{
PauseCallback?.Invoke();
Thread.Sleep(1000/_fps);
}
else
Stop();
continue;
}
// Don't stop when the effect is still initialized, just skip this frame
if (!EffectManager.ActiveEffect.Initialized)
{
Thread.Sleep(1000/_fps);
continue;
}
sw.Start();
// 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 it exists, send bitmap to the device
if (bitmap != null && KeyboardManager.ActiveKeyboard != null)
{
KeyboardManager.ActiveKeyboard.DrawBitmap(bitmap);
// debugging TODO: Disable when window isn't shown
Events.PublishOnUIThread(new ChangeBitmap(bitmap));
}
// Sleep according to time left this frame
var sleep = (int) (1000/_fps - sw.ElapsedMilliseconds);
if (sleep > 0)
Thread.Sleep(sleep);
sw.Reset();
}
}
private void BackgroundWorkerExceptionCatcher(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error == null)
return; return;
Logger.Error(e.Error, "Exception in the BackgroundWorker"); var runningProcesses = Process.GetProcesses();
throw e.Error;
}
private void ProcessWorker_DoWork(object sender, DoWorkEventArgs e) // If the currently active effect is a disabled game, get rid of it.
{ if (EffectManager.ActiveEffect != null)
while (!ProcessWorker.CancellationPending) EffectManager.DisableInactiveGame();
if (EffectManager.ActiveEffect is ProfilePreviewModel)
return;
// If the currently active effect is a no longer running game, get rid of it.
var activeGame = EffectManager.ActiveEffect as GameModel;
if (activeGame != null)
{ {
if (!ProgramEnabled) if (!runningProcesses.Any(p => p.ProcessName == activeGame.ProcessName && p.HasExited == false))
{ {
Thread.Sleep(1000); _logger.Info("Disabling game: {0}", activeGame.Name);
continue; EffectManager.DisableGame(activeGame);
} }
var runningProcesses = Process.GetProcesses();
// If the currently active effect is a disabled game, get rid of it.
if (EffectManager.ActiveEffect != null)
EffectManager.DisableInactiveGame();
// If the currently active effect is a no longer running game, get rid of it.
var activeGame = EffectManager.ActiveEffect as GameModel;
if (activeGame != null)
if (!runningProcesses.Any(p => p.ProcessName == activeGame.ProcessName && p.HasExited == false))
EffectManager.DisableGame(activeGame);
// Look for running games, stopping on the first one that's found.
var newGame = EffectManager.EnabledGames
.FirstOrDefault(
g => runningProcesses.Any(p => p.ProcessName == g.ProcessName && p.HasExited == false));
// If it's not already enabled, do so.
if (newGame != null && EffectManager.ActiveEffect != newGame)
EffectManager.ChangeEffect(newGame);
Thread.Sleep(1000);
} }
}
#endregion // Look for running games, stopping on the first one that's found.
var newGame = EffectManager.EnabledGames
.FirstOrDefault(g => runningProcesses
.Any(p => p.ProcessName == g.ProcessName && p.HasExited == false));
if (newGame == null || EffectManager.ActiveEffect == newGame)
return;
// If it's not already enabled, do so.
_logger.Info("Detected and enabling game: {0}", newGame.Name);
EffectManager.ChangeEffect(newGame, LoopManager);
}
} }
} }

View File

@ -0,0 +1,78 @@
using System.Collections.Generic;
using System.Linq;
using System.Timers;
using Artemis.Modules.Effects.ProfilePreview;
using Artemis.Settings;
using Artemis.ViewModels.Abstract;
using Ninject.Extensions.Logging;
namespace Artemis.Managers
{
public class ProfileManager
{
private readonly DeviceManager _deviceManager;
private readonly EffectManager _effectManager;
private readonly ILogger _logger;
private readonly LoopManager _loopManager;
public ProfileManager(ILogger logger, EffectManager effectManager, DeviceManager deviceManager,
LoopManager loopManager)
{
_logger = logger;
_effectManager = effectManager;
_deviceManager = deviceManager;
_loopManager = loopManager;
GameViewModels = new List<GameViewModel>();
var profilePreviewTimer = new Timer(500);
profilePreviewTimer.Elapsed += SetupProfilePreview;
profilePreviewTimer.Start();
}
public ProfilePreviewModel ProfilePreviewModel { get; set; }
public List<GameViewModel> GameViewModels { get; set; }
/// <summary>
/// Keeps track of profiles being previewed and sets up the active efffect accordingly
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void SetupProfilePreview(object sender, ElapsedEventArgs e)
{
if (string.IsNullOrEmpty(General.Default.LastKeyboard) || _deviceManager.ChangingKeyboard ||
ProfilePreviewModel == null)
return;
var activePreview = GameViewModels.FirstOrDefault(vm => vm.IsActive);
if (activePreview == null)
{
// Should not be active if no selected profile is set
if (_effectManager.ActiveEffect != ProfilePreviewModel)
return;
_logger.Debug("Loading last effect after profile preview");
var lastEffect = _effectManager.GetLastEffect();
if (lastEffect != null)
_effectManager.ChangeEffect(lastEffect);
else
_effectManager.ClearEffect();
}
else
{
if (_effectManager.ActiveEffect != ProfilePreviewModel)
{
_logger.Debug("Activate profile preview");
_effectManager.ChangeEffect(ProfilePreviewModel);
}
// LoopManager might be running, this method won't do any harm in that case.
_loopManager.Start();
if (!ReferenceEquals(ProfilePreviewModel.Profile, activePreview.ProfileEditor.SelectedProfile))
ProfilePreviewModel.Profile = activePreview.ProfileEditor.SelectedProfile;
}
}
}
}

View File

@ -1,6 +1,11 @@
using System; using System;
using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq;
using Artemis.Managers; using Artemis.Managers;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Models namespace Artemis.Models
{ {
@ -9,24 +14,50 @@ namespace Artemis.Models
public delegate void SettingsUpdateHandler(EffectSettings settings); public delegate void SettingsUpdateHandler(EffectSettings settings);
public bool Initialized; public bool Initialized;
public MainManager MainManager; public MainManager MainManager;
public string Name; public string Name;
protected EffectModel(MainManager mainManager) protected EffectModel(MainManager mainManager, IDataModel dataModel)
{ {
MainManager = mainManager; MainManager = mainManager;
DataModel = dataModel;
} }
// Used by profile system
public IDataModel DataModel { get; set; }
public ProfileModel Profile { get; set; }
public abstract void Dispose(); public abstract void Dispose();
// Called on creation // Called on creation
public abstract void Enable(); public abstract void Enable();
// Called every iteration // Called every frame
public abstract void Update(); public abstract void Update();
// Called after every update // Called after every update
public abstract Bitmap GenerateBitmap(); public virtual void Render(out Bitmap keyboard, out Brush mouse, out Brush headset, bool renderMice,
bool renderHeadsets)
{
keyboard = null;
mouse = null;
headset = null;
if (Profile == null || DataModel == null || MainManager.DeviceManager.ActiveKeyboard == null)
return;
// Get all enabled layers who's conditions are met
var renderLayers = GetRenderLayers(renderMice, renderHeadsets);
// Render the keyboard layer-by-layer
keyboard = Profile.GenerateBitmap(renderLayers, DataModel,
MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(4), false, true);
// Render the first enabled mouse (will default to null if renderMice was false)
mouse = Profile.GenerateBrush(renderLayers.LastOrDefault(l => l.LayerType == LayerType.Mouse), DataModel);
// Render the first enabled headset (will default to null if renderHeadsets was false)
headset = Profile.GenerateBrush(renderLayers.LastOrDefault(l => l.LayerType == LayerType.Headset), DataModel);
}
public abstract List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets);
} }
} }

View File

@ -1,12 +1,12 @@
using Artemis.Managers; using Artemis.Managers;
using Artemis.Models.Interfaces; using Artemis.Models.Interfaces;
using Artemis.Models.Profiles;
namespace Artemis.Models namespace Artemis.Models
{ {
public abstract class GameModel : EffectModel public abstract class GameModel : EffectModel
{ {
protected GameModel(MainManager mainManager, GameSettings settings) : base(mainManager) protected GameModel(MainManager mainManager, GameSettings settings, IDataModel dataModel)
: base(mainManager, dataModel)
{ {
Settings = settings; Settings = settings;
} }
@ -14,7 +14,5 @@ namespace Artemis.Models
public GameSettings Settings { get; set; } public GameSettings Settings { get; set; }
public bool Enabled { get; set; } public bool Enabled { get; set; }
public string ProcessName { get; set; } public string ProcessName { get; set; }
public IGameDataModel GameDataModel { get; set; }
public ProfileModel Profile { get; set; }
} }
} }

View File

@ -3,5 +3,6 @@
public abstract class GameSettings : EffectSettings public abstract class GameSettings : EffectSettings
{ {
public bool Enabled { get; set; } public bool Enabled { get; set; }
public string LastProfile { get; set; }
} }
} }

View File

@ -1,6 +1,6 @@
namespace Artemis.Models.Interfaces namespace Artemis.Models.Interfaces
{ {
public interface IGameDataModel public interface IDataModel
{ {
} }
} }

View File

@ -1,5 +1,6 @@
using System.Drawing; using System.Drawing;
using Artemis.Managers; using Artemis.Managers;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Models namespace Artemis.Models
{ {
@ -8,7 +9,7 @@ namespace Artemis.Models
private bool _enabled; private bool _enabled;
public string ProcessName; public string ProcessName;
protected OverlayModel(MainManager mainManager) : base(mainManager) protected OverlayModel(MainManager mainManager) : base(mainManager, null)
{ {
} }
@ -28,19 +29,7 @@ namespace Artemis.Models
} }
} }
public void SetEnabled(bool enabled) public abstract void RenderOverlay(ref Bitmap keyboard, ref Brush mouse, ref Brush headset, bool renderMice,
{ bool renderHeadsets);
if (Enabled == enabled)
return;
if (enabled)
Enable();
else
Dispose();
Enabled = enabled;
}
public abstract Bitmap GenerateBitmap(Bitmap bitmap);
} }
} }

View File

@ -0,0 +1,7 @@
namespace Artemis.Models
{
public abstract class OverlaySettings : EffectSettings
{
public bool Enabled { get; set; }
}
}

View File

@ -12,7 +12,7 @@ namespace Artemis.Models.Profiles
public string Operator { get; set; } public string Operator { get; set; }
public string Type { get; set; } public string Type { get; set; }
public bool ConditionMet<T>(IGameDataModel subject) public bool ConditionMet<T>(IDataModel subject)
{ {
if (string.IsNullOrEmpty(Field) || string.IsNullOrEmpty(Value) || string.IsNullOrEmpty(Type)) if (string.IsNullOrEmpty(Field) || string.IsNullOrEmpty(Value) || string.IsNullOrEmpty(Type))
return false; return false;
@ -23,9 +23,13 @@ namespace Artemis.Models.Profiles
// Put the subject in a list, allowing Dynamic Linq to be used. // Put the subject in a list, allowing Dynamic Linq to be used.
var subjectList = new List<T> {(T) subject}; var subjectList = new List<T> {(T) subject};
var res = Type == "String" bool res;
? subjectList.Where($"{Field}.ToLower() {Operator} @0", Value.ToLower()).Any() if (Type == "String")
: subjectList.Where($"{Field} {Operator} {Value}").Any(); res = subjectList.Where($"{Field}.ToLower() {Operator} @0", Value.ToLower()).Any();
else if (Type == "Enum")
res = subjectList.Where($"{Field} {Operator} \"{Value}\"").Any();
else
res = subjectList.Where($"{Field} {Operator} {Value}").Any();
return res; return res;
} }
} }

View File

@ -1,79 +0,0 @@
using System.ComponentModel;
using Artemis.Models.Interfaces;
using Artemis.Utilities;
using static System.Decimal;
namespace Artemis.Models.Profiles
{
public class LayerDynamicPropertiesModel
{
/// <summary>
/// Property this dynamic property applies on
/// </summary>
public string LayerProperty { get; set; }
/// <summary>
/// Property to base the percentage upon
/// </summary>
public string GameProperty { get; set; }
/// <summary>
/// Percentage source, the number that defines 100%
/// </summary>
public string PercentageSource { get; set; }
/// <summary>
/// Type of property
/// </summary>
public LayerPropertyType LayerPropertyType { get; set; }
internal void ApplyProperty<T>(IGameDataModel data, LayerPropertiesModel userProps, LayerPropertiesModel props)
{
if (LayerPropertyType == LayerPropertyType.PercentageOf)
Apply(props, userProps, data, int.Parse(PercentageSource));
if (LayerPropertyType == LayerPropertyType.PercentageOfProperty)
ApplyProp(props, userProps, data);
}
private void Apply(LayerPropertiesModel props, LayerPropertiesModel userProps, IGameDataModel data,
int percentageSource)
{
// Property to apply on
var layerProp = props.GetType().GetProperty(LayerProperty);
// User's settings
var userProp = userProps.GetType().GetProperty(LayerProperty);
// Property to base the percentage upon
var gameProperty = data.GetPropValue<int>(GameProperty);
if (layerProp == null || userProp == null)
return;
var percentage = ToDouble(gameProperty) / percentageSource;
// Opacity requires some special treatment as it causes an exception if it's < 0.0 or > 1.0
if (LayerProperty == "Opacity")
{
var opacity = percentage*(double) userProp.GetValue(userProps, null);
if (opacity < 0.0)
opacity = 0.0;
if (opacity > 1.0)
opacity = 1.0;
layerProp.SetValue(props, opacity);
}
else
layerProp.SetValue(props, (int) (percentage*(int) userProp.GetValue(userProps, null)));
}
private void ApplyProp(LayerPropertiesModel props, LayerPropertiesModel userProps, IGameDataModel data)
{
var value = data.GetPropValue<int>(PercentageSource);
Apply(props, userProps, data, value);
}
}
public enum LayerPropertyType
{
[Description("None")] None,
[Description("% of")] PercentageOf,
[Description("% of property")] PercentageOfProperty
}
}

View File

@ -4,142 +4,262 @@ using System.Linq;
using System.Windows.Media; using System.Windows.Media;
using System.Xml.Serialization; using System.Xml.Serialization;
using Artemis.Models.Interfaces; using Artemis.Models.Interfaces;
using Artemis.Models.Profiles.Properties;
using Artemis.Utilities; using Artemis.Utilities;
using Artemis.Utilities.Layers;
using Artemis.Utilities.ParentChild; using Artemis.Utilities.ParentChild;
namespace Artemis.Models.Profiles namespace Artemis.Models.Profiles
{ {
public class LayerModel : IChildItem<LayerModel>, IChildItem<ProfileModel> public class LayerModel : IChildItem<LayerModel>, IChildItem<ProfileModel>
{ {
[XmlIgnore] private readonly LayerDrawer _drawer;
[XmlIgnore] private bool _mustDraw;
public LayerModel() public LayerModel()
{ {
UserProps = new LayerPropertiesModel();
CalcProps = new LayerPropertiesModel();
Children = new ChildItemCollection<LayerModel, LayerModel>(this); Children = new ChildItemCollection<LayerModel, LayerModel>(this);
LayerConditions = new List<LayerConditionModel>();
LayerProperties = new List<LayerDynamicPropertiesModel>();
_mustDraw = true;
_drawer = new LayerDrawer(this, 4);
} }
public string Name { get; set; } public string Name { get; set; }
public int Order { get; set; }
public LayerType LayerType { get; set; } public LayerType LayerType { get; set; }
public bool Enabled { get; set; } public bool Enabled { get; set; }
public int Order { get; set; } public bool Expanded { get; set; }
public LayerPropertiesModel UserProps { get; set; } public LayerPropertiesModel Properties { get; set; }
public ChildItemCollection<LayerModel, LayerModel> Children { get; } public ChildItemCollection<LayerModel, LayerModel> Children { get; }
public List<LayerConditionModel> LayerConditions { get; set; }
public List<LayerDynamicPropertiesModel> LayerProperties { get; set; }
[XmlIgnore] [XmlIgnore]
public LayerPropertiesModel CalcProps { get; set; } public ImageSource LayerImage => Drawer.DrawThumbnail(this);
[XmlIgnore] [XmlIgnore]
public ImageSource LayerImage => _drawer.GetThumbnail(); public LayerModel Parent { get; internal set; }
[XmlIgnore] [XmlIgnore]
public LayerModel ParentLayer { get; internal set; } public ProfileModel Profile { get; internal set; }
[XmlIgnore] [XmlIgnore]
public ProfileModel ParentProfile { get; internal set; } public GifImage GifImage { get; set; }
public bool ConditionsMet<T>(IGameDataModel dataModel) public bool ConditionsMet<T>(IDataModel dataModel)
{ {
return Enabled && LayerConditions.All(cm => cm.ConditionMet<T>(dataModel)); return Enabled && Properties.Conditions.All(cm => cm.ConditionMet<T>(dataModel));
} }
public void DrawPreview(DrawingContext c) public void Draw(IDataModel dataModel, DrawingContext c, bool preview, bool updateAnimations)
{ {
GeneralHelpers.CopyProperties(CalcProps, UserProps); if (LayerType != LayerType.Keyboard && LayerType != LayerType.KeyboardGif)
if (LayerType == LayerType.Keyboard || LayerType == LayerType.Keyboard) return;
_drawer.Draw(c, _mustDraw);
// Preview simply shows the properties as they are. When not previewing they are applied
var appliedProperties = !preview
? Properties.GetAppliedProperties(dataModel)
: Properties.GetAppliedProperties(dataModel, true);
// Update animations
AnimationUpdater.UpdateAnimation((KeyboardPropertiesModel) Properties, updateAnimations);
if (LayerType == LayerType.Keyboard)
Drawer.Draw(c, (KeyboardPropertiesModel) Properties, appliedProperties);
else if (LayerType == LayerType.KeyboardGif) else if (LayerType == LayerType.KeyboardGif)
_drawer.DrawGif(c); GifImage = Drawer.DrawGif(c, (KeyboardPropertiesModel) Properties, appliedProperties, GifImage);
_mustDraw = false;
} }
public void Draw<T>(IGameDataModel dataModel, DrawingContext c, bool preview = false) public Brush GenerateBrush<T>(LayerType type, IDataModel dataModel, bool preview, bool updateAnimations)
{ {
// Conditions aren't checked during a preview because there is no game data to base them on if (!Enabled)
return null;
if (LayerType != LayerType.Folder && LayerType != type)
return null;
// Preview simply shows the properties as they are. When not previewing they are applied
AppliedProperties appliedProperties;
if (!preview) if (!preview)
if (!ConditionsMet<T>(dataModel))
return;
if (LayerType == LayerType.Folder)
foreach (var layerModel in Children.OrderByDescending(l => l.Order))
layerModel.Draw<T>(dataModel, c);
else if (LayerType == LayerType.Keyboard || LayerType == LayerType.Keyboard)
_drawer.Draw(c);
else if (LayerType == LayerType.KeyboardGif)
_drawer.DrawGif(c);
else if (LayerType == LayerType.Mouse)
_drawer.UpdateMouse();
else if (LayerType == LayerType.Headset)
_drawer.UpdateHeadset();
}
public void Update<T>(IGameDataModel dataModel, bool preview = false)
{
if (LayerType == LayerType.Folder)
{ {
foreach (var layerModel in Children) if (!ConditionsMet<T>(dataModel))
layerModel.Update<T>(dataModel); return null; // Return null when not previewing and the conditions arent met
return; appliedProperties = Properties.GetAppliedProperties(dataModel);
} }
GeneralHelpers.CopyProperties(CalcProps, UserProps);
// Dynamic properties aren't applied during preview because there is no game data to base them on
if (preview)
return;
foreach (var dynamicProperty in LayerProperties)
dynamicProperty.ApplyProperty<T>(dataModel, UserProps, CalcProps);
}
public void Reorder(LayerModel selectedLayer, bool moveUp)
{
// Fix the sorting just in case
FixOrder();
int newOrder;
if (moveUp)
newOrder = selectedLayer.Order - 1;
else else
newOrder = selectedLayer.Order + 1; appliedProperties = Properties.GetAppliedProperties(dataModel, true);
var target = Children.FirstOrDefault(l => l.Order == newOrder); // TODO: Mouse/headset animations
if (target == null)
return;
target.Order = selectedLayer.Order; if (LayerType != LayerType.Folder)
selectedLayer.Order = newOrder; return appliedProperties.Brush;
Brush res = null;
foreach (var layerModel in Children.OrderByDescending(l => l.Order))
{
var brush = layerModel.GenerateBrush<T>(type, dataModel, preview, updateAnimations);
if (brush != null)
res = brush;
}
return res;
} }
private void FixOrder() public void SetupProperties()
{
if ((LayerType == LayerType.Keyboard || LayerType == LayerType.KeyboardGif) &&
!(Properties is KeyboardPropertiesModel))
{
Properties = new KeyboardPropertiesModel
{
Brush = new SolidColorBrush(ColorHelpers.GetRandomRainbowMediaColor()),
Animation = LayerAnimation.None,
Height = 1,
Width = 1,
X = 0,
Y = 0,
Opacity = 1
};
}
else if (LayerType == LayerType.Mouse && !(Properties is MousePropertiesModel))
Properties = new MousePropertiesModel
{
Brush = new SolidColorBrush(ColorHelpers.GetRandomRainbowMediaColor())
};
else if (LayerType == LayerType.Headset && !(Properties is HeadsetPropertiesModel))
Properties = new HeadsetPropertiesModel
{
Brush = new SolidColorBrush(ColorHelpers.GetRandomRainbowMediaColor())
};
}
public void FixOrder()
{ {
Children.Sort(l => l.Order); Children.Sort(l => l.Order);
for (var i = 0; i < Children.Count; i++) for (var i = 0; i < Children.Count; i++)
Children[i].Order = i; Children[i].Order = i;
} }
/// <summary>
/// Returns whether the layer meets the requirements to be drawn
/// </summary>
/// <returns></returns>
public bool MustDraw()
{
// If any of the parents are disabled, this layer must not be drawn
var parent = Parent;
while (parent != null)
{
if (!parent.Enabled)
return false;
parent = parent.Parent;
}
return Enabled && (LayerType == LayerType.Keyboard || LayerType == LayerType.KeyboardGif);
}
public IEnumerable<LayerModel> GetLayers()
{
var layers = new List<LayerModel>();
foreach (var layerModel in Children)
{
layers.Add(layerModel);
layers.AddRange(layerModel.GetLayers());
}
return layers;
}
public static LayerModel CreateLayer()
{
return new LayerModel
{
Name = "New layer",
Enabled = true,
Order = -1,
LayerType = LayerType.Keyboard,
Properties = new KeyboardPropertiesModel
{
Brush = new SolidColorBrush(ColorHelpers.GetRandomRainbowMediaColor()),
Animation = LayerAnimation.None,
Height = 1,
Width = 1,
X = 0,
Y = 0,
Opacity = 1
}
};
}
public void InsertBefore(LayerModel source)
{
source.Order = Order;
Insert(source);
}
public void InsertAfter(LayerModel source)
{
source.Order = Order + 1;
Insert(source);
}
private void Insert(LayerModel source)
{
if (Parent != null)
{
foreach (var child in Parent.Children.OrderBy(c => c.Order))
{
if (child.Order >= source.Order)
child.Order++;
}
Parent.Children.Add(source);
}
else if (Profile != null)
{
foreach (var layer in Profile.Layers.OrderBy(l => l.Order))
{
if (layer.Order >= source.Order)
layer.Order++;
}
Profile.Layers.Add(source);
}
}
/// <summary>
/// Generates a flat list containing all layers that must be rendered on the keyboard,
/// the first mouse layer to be rendered and the first headset layer to be rendered
/// </summary>
/// <typeparam name="T">The game data model to base the conditions on</typeparam>
/// <param name="dataModel">Instance of said game data model</param>
/// <param name="includeMice">Whether or not to include mice in the list</param>
/// <param name="includeHeadsets">Whether or not to include headsets in the list</param>
/// <param name="ignoreConditions"></param>
/// <returns>A flat list containing all layers that must be rendered</returns>
public List<LayerModel> GetRenderLayers<T>(IDataModel dataModel, bool includeMice, bool includeHeadsets,
bool ignoreConditions = false)
{
var layers = new List<LayerModel>();
foreach (var layerModel in Children.OrderByDescending(c => c.Order))
{
if (!layerModel.Enabled ||
!includeMice && layerModel.LayerType == LayerType.Mouse ||
!includeHeadsets && layerModel.LayerType == LayerType.Headset)
continue;
if (!ignoreConditions)
{
if (!layerModel.ConditionsMet<T>(dataModel))
continue;
}
layers.Add(layerModel);
layers.AddRange(layerModel.GetRenderLayers<T>(dataModel, includeMice, includeHeadsets, ignoreConditions));
}
return layers;
}
#region IChildItem<Parent> Members #region IChildItem<Parent> Members
LayerModel IChildItem<LayerModel>.Parent LayerModel IChildItem<LayerModel>.Parent
{ {
get { return ParentLayer; } get { return Parent; }
set { ParentLayer = value; } set { Parent = value; }
} }
ProfileModel IChildItem<ProfileModel>.Parent ProfileModel IChildItem<ProfileModel>.Parent
{ {
get { return ParentProfile; } get { return Profile; }
set { ParentProfile = value; } set { Profile = value; }
} }
#endregion #endregion

View File

@ -1,41 +0,0 @@
using System.ComponentModel;
using System.Windows;
using System.Windows.Media;
using System.Xml.Serialization;
namespace Artemis.Models.Profiles
{
[XmlInclude(typeof (SolidColorBrush))]
[XmlInclude(typeof (LinearGradientBrush))]
[XmlInclude(typeof (RadialGradientBrush))]
[XmlInclude(typeof (MatrixTransform))]
public class LayerPropertiesModel
{
public int X { get; set; }
public int Y { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public double Opacity { get; set; }
public bool ContainedBrush { get; set; }
public LayerAnimation Animation { get; set; }
public double AnimationSpeed { get; set; }
public Brush Brush { get; set; }
public Rect GetRect(int scale = 4)
{
return new Rect(X*scale, Y*scale, Width*scale, Height*scale);
}
}
public enum LayerAnimation
{
[Description("None")] None,
[Description("Slide left")] SlideLeft,
[Description("Slide right")] SlideRight,
[Description("Slide up")] SlideUp,
[Description("Slide down")] SlideDown,
[Description("Grow")] Grow,
[Description("Pulse")] Pulse
}
}

View File

@ -1,11 +1,17 @@
using System.Drawing; using System.Collections.Generic;
using System.Drawing;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Media; using System.Windows.Media;
using System.Xml.Serialization;
using Artemis.Models.Interfaces; using Artemis.Models.Interfaces;
using Artemis.Models.Profiles.Properties;
using Artemis.Utilities; using Artemis.Utilities;
using Artemis.Utilities.ParentChild; using Artemis.Utilities.ParentChild;
using Brush = System.Windows.Media.Brush;
using Color = System.Windows.Media.Color; using Color = System.Windows.Media.Color;
using Point = System.Windows.Point;
using Size = System.Windows.Size;
namespace Artemis.Models.Profiles namespace Artemis.Models.Profiles
{ {
@ -20,14 +26,17 @@ namespace Artemis.Models.Profiles
public ChildItemCollection<ProfileModel, LayerModel> Layers { get; } public ChildItemCollection<ProfileModel, LayerModel> Layers { get; }
public string Name { get; set; } public string Name { get; set; }
public string KeyboardName { get; set; } public bool IsDefault { get; set; }
public string KeyboardSlug { get; set; }
public string GameName { get; set; } public string GameName { get; set; }
public DrawingVisual DrawingVisual { get; set; }
[XmlIgnore]
public DrawingVisual DrawingVisual { get; set; }
protected bool Equals(ProfileModel other) protected bool Equals(ProfileModel other)
{ {
return string.Equals(Name, other.Name) && string.Equals(KeyboardName, other.KeyboardName) && return string.Equals(Name, other.Name) &&
string.Equals(KeyboardSlug, other.KeyboardSlug) &&
string.Equals(GameName, other.GameName); string.Equals(GameName, other.GameName);
} }
@ -44,61 +53,12 @@ namespace Artemis.Models.Profiles
unchecked unchecked
{ {
var hashCode = Name?.GetHashCode() ?? 0; var hashCode = Name?.GetHashCode() ?? 0;
hashCode = (hashCode*397) ^ (KeyboardName?.GetHashCode() ?? 0); hashCode = (hashCode*397) ^ (KeyboardSlug?.GetHashCode() ?? 0);
hashCode = (hashCode*397) ^ (GameName?.GetHashCode() ?? 0); hashCode = (hashCode*397) ^ (GameName?.GetHashCode() ?? 0);
return hashCode; return hashCode;
} }
} }
/// <summary>
/// Adds a new layer with default settings to the profile
/// </summary>
/// <returns>The newly added layer</returns>
public LayerModel AddLayer()
{
var layer = new LayerModel
{
Name = "New layer",
Enabled = true,
Order = -1,
LayerType = LayerType.Keyboard,
UserProps = new LayerPropertiesModel
{
Brush = new SolidColorBrush(ColorHelpers.GetRandomRainbowMediaColor()),
Animation = LayerAnimation.None,
Height = 1,
Width = 1,
X = 0,
Y = 0,
Opacity = 1
}
};
Layers.Add(layer);
FixOrder();
return layer;
}
public void Reorder(LayerModel selectedLayer, bool moveUp)
{
// Fix the sorting just in case
FixOrder();
int newOrder;
if (moveUp)
newOrder = selectedLayer.Order - 1;
else
newOrder = selectedLayer.Order + 1;
var target = Layers.FirstOrDefault(l => l.Order == newOrder);
if (target == null)
return;
target.Order = selectedLayer.Order;
selectedLayer.Order = newOrder;
}
public void FixOrder() public void FixOrder()
{ {
Layers.Sort(l => l.Order); Layers.Sort(l => l.Order);
@ -106,29 +66,156 @@ namespace Artemis.Models.Profiles
Layers[i].Order = i; Layers[i].Order = i;
} }
public Bitmap GenerateBitmap<T>(Rect keyboardRect, IGameDataModel gameDataModel, bool preview = false) public Bitmap GenerateBitmap<T>(Rect keyboardRect, IDataModel dataModel, bool preview,
bool updateAnimations)
{ {
Bitmap bitmap = null; var visual = new DrawingVisual();
DrawingVisual.Dispatcher.Invoke(delegate using (var c = visual.RenderOpen())
{ {
var visual = new DrawingVisual(); // Setup the DrawingVisual's size
using (var c = visual.RenderOpen()) c.PushClip(new RectangleGeometry(keyboardRect));
c.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, keyboardRect);
// Draw the layers
foreach (var layerModel in Layers.OrderByDescending(l => l.Order))
layerModel.Draw(dataModel, c, preview, updateAnimations);
// Remove the clip
c.Pop();
}
return ImageUtilities.DrawinVisualToBitmap(visual, keyboardRect);
}
public Brush GenerateBrush<T>(IDataModel dataModel, LayerType type, bool preview, bool updateAnimations)
{
Brush result = null;
// Draw the layers
foreach (var layerModel in Layers.OrderByDescending(l => l.Order))
{
var generated = layerModel.GenerateBrush<T>(type, dataModel, preview, updateAnimations);
if (generated != null)
result = generated;
}
return result;
}
/// <summary>
/// Gives all the layers and their children in a flat list
/// </summary>
public List<LayerModel> GetLayers()
{
var layers = new List<LayerModel>();
foreach (var layerModel in Layers)
{
layers.Add(layerModel);
layers.AddRange(layerModel.GetLayers());
}
return layers;
}
/// <summary>
/// Generates a flat list containing all layers that must be rendered on the keyboard,
/// the first mouse layer to be rendered and the first headset layer to be rendered
/// </summary>
/// <typeparam name="T">The game data model to base the conditions on</typeparam>
/// <param name="dataModel">Instance of said game data model</param>
/// <param name="includeMice">Whether or not to include mice in the list</param>
/// <param name="includeHeadsets">Whether or not to include headsets in the list</param>
/// <param name="ignoreConditions"></param>
/// <returns>A flat list containing all layers that must be rendered</returns>
public List<LayerModel> GetRenderLayers<T>(IDataModel dataModel, bool includeMice, bool includeHeadsets,
bool ignoreConditions = false)
{
var layers = new List<LayerModel>();
foreach (var layerModel in Layers.OrderByDescending(l => l.Order))
{
if (!layerModel.Enabled ||
!includeMice && layerModel.LayerType == LayerType.Mouse ||
!includeHeadsets && layerModel.LayerType == LayerType.Headset)
continue;
if (!ignoreConditions)
{ {
// Setup the DrawingVisual's size if (!layerModel.ConditionsMet<T>(dataModel))
c.PushClip(new RectangleGeometry(keyboardRect)); continue;
c.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, keyboardRect);
// Draw the layers
foreach (var layerModel in Layers.OrderByDescending(l => l.Order))
layerModel.Draw<T>(gameDataModel, c, preview);
// Remove the clip
c.Pop();
} }
bitmap = ImageUtilities.DrawinVisualToBitmap(visual, keyboardRect); layers.Add(layerModel);
}); layers.AddRange(layerModel.GetRenderLayers<T>(dataModel, includeMice, includeHeadsets, ignoreConditions));
return bitmap; }
return layers;
}
/// <summary>
/// Looks at all the layers wthin the profile and makes sure they are within boundaries of the given rectangle
/// </summary>
/// <param name="keyboardRectangle"></param>
public void FixBoundaries(Rect keyboardRectangle)
{
foreach (var layer in GetLayers())
{
if (layer.LayerType != LayerType.Keyboard && layer.LayerType != LayerType.KeyboardGif)
continue;
var props = (KeyboardPropertiesModel) layer.Properties;
var layerRect = new Rect(new Point(props.X, props.Y), new Size(props.Width, props.Height));
if (keyboardRectangle.Contains(layerRect))
continue;
props.X = 0;
props.Y = 0;
layer.Properties = props;
}
}
/// <summary>
/// Generates a bitmap showing all the provided layers of type Keyboard and KeyboardGif
/// </summary>
/// <param name="renderLayers">The layers to render</param>
/// <param name="dataModel">The data model to base the layer's properties on</param>
/// <param name="keyboardRect">A rectangle matching the current keyboard's size on a scale of 4, used for clipping</param>
/// <param name="preview">Indicates wheter the layer is drawn as a preview, ignoring dynamic properties</param>
/// <param name="updateAnimations">Wheter or not to update the layer's animations</param>
/// <returns>The generated bitmap</returns>
internal Bitmap GenerateBitmap(List<LayerModel> renderLayers, IDataModel dataModel, Rect keyboardRect,
bool preview,
bool updateAnimations)
{
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
{
// Setup the DrawingVisual's size
c.PushClip(new RectangleGeometry(keyboardRect));
c.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, keyboardRect);
// Draw the layers
foreach (var layerModel in renderLayers
.Where(l => l.LayerType == LayerType.Keyboard ||
l.LayerType == LayerType.KeyboardGif))
{
layerModel.Draw(dataModel, c, preview, updateAnimations);
}
// Remove the clip
c.Pop();
}
return ImageUtilities.DrawinVisualToBitmap(visual, keyboardRect);
}
/// <summary>
/// Generates a brush out of the given layer, for usage with mice and headsets
/// </summary>
/// <param name="layerModel">The layer to base the brush on</param>
/// <param name="dataModel">The game data model to base the layer's properties on</param>
/// <returns>The generated brush</returns>
public Brush GenerateBrush(LayerModel layerModel, IDataModel dataModel)
{
return layerModel?.Properties.GetAppliedProperties(dataModel).Brush;
} }
} }
} }

View File

@ -0,0 +1,120 @@
using System.ComponentModel;
using Artemis.Models.Interfaces;
using Artemis.Utilities;
using static System.Decimal;
namespace Artemis.Models.Profiles.Properties
{
public class DynamicPropertiesModel
{
/// <summary>
/// Property this dynamic property applies on
/// </summary>
public string LayerProperty { get; set; }
/// <summary>
/// Property to base the percentage upon
/// </summary>
public string GameProperty { get; set; }
/// <summary>
/// Percentage source, the number that defines 100%
/// </summary>
public double PercentageSource { get; set; }
/// <summary>
/// Percentage source property, the property that defines 100%
/// </summary>
public string PercentageProperty { get; set; }
/// <summary>
/// Type of property
/// </summary>
public LayerPropertyType LayerPropertyType { get; set; }
/// <summary>
/// Extra options on top of the selected properties
/// </summary>
public LayerPropertyOptions LayerPropertyOptions { get; set; }
internal void ApplyProperty(IDataModel dataModel, ref AppliedProperties properties)
{
if (LayerPropertyType == LayerPropertyType.PercentageOf)
ApplyPercentageOf(dataModel, ref properties, PercentageSource);
if (LayerPropertyType == LayerPropertyType.PercentageOfProperty)
ApplyPercentageOfProperty(dataModel, ref properties);
}
private void ApplyPercentageOf(IDataModel dataModel, ref AppliedProperties properties, double src)
{
if (GameProperty == null)
return;
var gameProperty = dataModel.GetPropValue<int>(GameProperty);
var percentage = ToDouble(gameProperty)/src;
if (LayerProperty == "Width")
ApplyWidth(ref properties, percentage);
else if (LayerProperty == "Height")
ApplyHeight(ref properties, percentage);
else if (LayerProperty == "Opacity")
ApplyOpacity(ref properties, percentage);
}
private void ApplyWidth(ref AppliedProperties properties, double percentage)
{
var newWidth = percentage*properties.Width;
var difference = properties.Width - newWidth;
properties.Width = newWidth;
// Apply the right to left option
if (LayerPropertyOptions == LayerPropertyOptions.RightToLeft)
properties.X = properties.X + difference;
}
private void ApplyHeight(ref AppliedProperties properties, double percentage)
{
var newHeight = percentage*properties.Height;
var difference = properties.Height - newHeight;
properties.Height = newHeight;
if (LayerPropertyOptions == LayerPropertyOptions.Downwards)
properties.Y = properties.Y + difference;
}
private void ApplyOpacity(ref AppliedProperties properties, double percentage)
{
properties.Opacity = percentage*properties.Opacity;
if (properties.Opacity < 0.0)
properties.Opacity = 0.0;
if (properties.Opacity > 1.0)
properties.Opacity = 1.0;
// Apply the inverse/decrease option
if (LayerPropertyOptions == LayerPropertyOptions.Decrease)
properties.Opacity = 1.0 - properties.Opacity;
}
private void ApplyPercentageOfProperty(IDataModel dataModel, ref AppliedProperties properties)
{
var value = dataModel.GetPropValue<int>(PercentageProperty);
ApplyPercentageOf(dataModel, ref properties, value);
}
}
public enum LayerPropertyType
{
[Description("% of")] PercentageOf,
[Description("% of property")] PercentageOfProperty
}
public enum LayerPropertyOptions
{
[Description("Left to right")] LeftToRight,
[Description("Right to left")] RightToLeft,
[Description("Downwards")] Downwards,
[Description("Upwards")] Upwards,
[Description("Increase")] Increase,
[Description("Decrease")] Decrease
}
}

View File

@ -0,0 +1,12 @@
using Artemis.Models.Interfaces;
namespace Artemis.Models.Profiles.Properties
{
public class FolderPropertiesModel : LayerPropertiesModel
{
public override AppliedProperties GetAppliedProperties(IDataModel dataModel, bool ignoreDynamic = false)
{
return new AppliedProperties();
}
}
}

View File

@ -0,0 +1,12 @@
using Artemis.Models.Interfaces;
namespace Artemis.Models.Profiles.Properties
{
public class HeadsetPropertiesModel : LayerPropertiesModel
{
public override AppliedProperties GetAppliedProperties(IDataModel dataModel, bool ignoreDynamic = false)
{
return new AppliedProperties {Brush = Brush};
}
}
}

View File

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Xml.Serialization;
using Artemis.Models.Interfaces;
namespace Artemis.Models.Profiles.Properties
{
public class KeyboardPropertiesModel : LayerPropertiesModel
{
public KeyboardPropertiesModel()
{
DynamicProperties = new List<DynamicPropertiesModel>();
}
public double X { get; set; }
public double Y { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double Opacity { get; set; }
public bool Contain { get; set; }
public LayerAnimation Animation { get; set; }
public double AnimationSpeed { get; set; }
public string GifFile { get; set; }
public List<DynamicPropertiesModel> DynamicProperties { get; set; }
[XmlIgnore]
public double AnimationProgress { get; set; }
public Rect GetRect(int scale = 4)
{
return new Rect(X*scale, Y*scale, Width*scale, Height*scale);
}
public override AppliedProperties GetAppliedProperties(IDataModel dataModel, bool ignoreDynamic = false)
{
var applied = new AppliedProperties
{
X = X,
Y = Y,
Width = Width,
Height = Height,
Opacity = Opacity,
Brush = Brush.CloneCurrentValue()
};
if (ignoreDynamic)
return applied;
foreach (var dynamicProperty in DynamicProperties)
dynamicProperty.ApplyProperty(dataModel, ref applied);
if (Math.Abs(applied.Opacity - 1) > 0.001)
{
applied.Brush = Brush.CloneCurrentValue();
applied.Brush.Opacity = applied.Opacity;
}
return applied;
}
}
public enum LayerAnimation
{
[Description("None")] None,
[Description("Slide left")] SlideLeft,
[Description("Slide right")] SlideRight,
[Description("Slide up")] SlideUp,
[Description("Slide down")] SlideDown,
[Description("Grow")] Grow,
[Description("Pulse")] Pulse
}
}

View File

@ -0,0 +1,63 @@
using System.Collections.Generic;
using System.Windows.Media;
using System.Xml.Serialization;
using Artemis.Models.Interfaces;
namespace Artemis.Models.Profiles.Properties
{
[XmlInclude(typeof(SolidColorBrush))]
[XmlInclude(typeof(LinearGradientBrush))]
[XmlInclude(typeof(RadialGradientBrush))]
[XmlInclude(typeof(MatrixTransform))]
[XmlInclude(typeof(KeyboardPropertiesModel))]
[XmlInclude(typeof(MousePropertiesModel))]
[XmlInclude(typeof(HeadsetPropertiesModel))]
[XmlInclude(typeof(FolderPropertiesModel))]
public abstract class LayerPropertiesModel
{
private Brush _brush;
protected LayerPropertiesModel()
{
Conditions = new List<LayerConditionModel>();
}
public List<LayerConditionModel> Conditions { get; set; }
public Brush Brush
{
get { return _brush; }
set
{
if (value == null)
{
_brush = null;
return;
}
if (value.IsFrozen)
{
_brush = value;
return;
}
// Clone the brush off of the UI thread and freeze it
var cloned = value.Dispatcher.Invoke(value.CloneCurrentValue);
cloned.Freeze();
_brush = cloned;
}
}
public abstract AppliedProperties GetAppliedProperties(IDataModel dataModel, bool ignoreDynamic = false);
}
public struct AppliedProperties
{
public double X { get; set; }
public double Y { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double Opacity { get; set; }
public Brush Brush { get; set; }
}
}

View File

@ -0,0 +1,12 @@
using Artemis.Models.Interfaces;
namespace Artemis.Models.Profiles.Properties
{
public class MousePropertiesModel : LayerPropertiesModel
{
public override AppliedProperties GetAppliedProperties(IDataModel dataModel, bool ignoreDynamic = false)
{
return new AppliedProperties {Brush = Brush};
}
}
}

View File

@ -1,14 +1,12 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.IO;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using Artemis.Managers; using Artemis.Managers;
using Artemis.Models; using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Utilities.Keyboard; using Artemis.Utilities.Keyboard;
using Kaliko.ImageLibrary;
using Kaliko.ImageLibrary.Filters;
namespace Artemis.Modules.Effects.AmbientLightning namespace Artemis.Modules.Effects.AmbientLightning
{ {
@ -21,7 +19,7 @@ namespace Artemis.Modules.Effects.AmbientLightning
private KeyboardRectangle _topRect; private KeyboardRectangle _topRect;
public AmbientLightningEffectModel(MainManager mainManager, AmbientLightningEffectSettings settings) public AmbientLightningEffectModel(MainManager mainManager, AmbientLightningEffectSettings settings)
: base(mainManager) : base(mainManager, null)
{ {
Name = "Ambient Lightning"; Name = "Ambient Lightning";
Settings = settings; Settings = settings;
@ -49,9 +47,9 @@ namespace Artemis.Modules.Effects.AmbientLightning
_colors = new List<Color>(); _colors = new List<Color>();
_screenCapturer = new ScreenCapture(); _screenCapturer = new ScreenCapture();
_topRect = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0, 0, new List<Color>(), _topRect = new KeyboardRectangle(MainManager.DeviceManager.ActiveKeyboard, 0, 0, new List<Color>(),
LinearGradientMode.Horizontal) {Height = MainManager.KeyboardManager.ActiveKeyboard.Height*Scale/2}; LinearGradientMode.Horizontal) {Height = MainManager.DeviceManager.ActiveKeyboard.Height*Scale/2};
_botRect = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0, 0, new List<Color>(), _botRect = new KeyboardRectangle(MainManager.DeviceManager.ActiveKeyboard, 0, 0, new List<Color>(),
LinearGradientMode.Horizontal); LinearGradientMode.Horizontal);
Initialized = true; Initialized = true;
@ -102,8 +100,8 @@ namespace Artemis.Modules.Effects.AmbientLightning
} }
// Put the resulting colors in 6 rectangles, their size differs per keyboard // Put the resulting colors in 6 rectangles, their size differs per keyboard
var rectWidth = MainManager.KeyboardManager.ActiveKeyboard.Width/3*Scale; var rectWidth = MainManager.DeviceManager.ActiveKeyboard.Width/3*Scale;
var rectHeight = MainManager.KeyboardManager.ActiveKeyboard.Height/2*Scale; var rectHeight = MainManager.DeviceManager.ActiveKeyboard.Height/2*Scale;
for (var row = 0; row < 2; row++) for (var row = 0; row < 2; row++)
{ {
for (var column = 0; column < 3; column++) for (var column = 0; column < 3; column++)
@ -114,25 +112,9 @@ namespace Artemis.Modules.Effects.AmbientLightning
} }
} }
public override Bitmap GenerateBitmap() public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{ {
var bitmap = MainManager.KeyboardManager.ActiveKeyboard.KeyboardBitmap(Scale); return null;
using (var g = Graphics.FromImage(bitmap))
{
var i = 0;
foreach (var rectangle in _rectangles)
{
g.FillRectangle(new SolidBrush(_colors[i]), rectangle);
i++;
}
}
var test = new KalikoImage(bitmap);
test.ApplyFilter(new GaussianBlurFilter(8f));
var ms = new MemoryStream();
test.SaveBmp(ms);
ms.Position = 0;
return new Bitmap(ms);
} }
} }
} }

View File

@ -5,25 +5,17 @@ using Caliburn.Micro;
namespace Artemis.Modules.Effects.AmbientLightning namespace Artemis.Modules.Effects.AmbientLightning
{ {
internal class AmbientLightningEffectViewModel : EffectViewModel, IHandle<ActiveEffectChanged> public sealed class AmbientLightningEffectViewModel : EffectViewModel, IHandle<ActiveEffectChanged>
{ {
public AmbientLightningEffectViewModel(MainManager mainManager) public AmbientLightningEffectViewModel(MainManager main, IEventAggregator events)
: base(main, new AmbientLightningEffectModel(main, new AmbientLightningEffectSettings()))
{ {
// Subscribe to main model DisplayName = "Ambient Lightning";
MainManager = mainManager;
MainManager.Events.Subscribe(this);
// Settings are loaded from file by class events.Subscribe(this);
EffectSettings = new AmbientLightningEffectSettings();
// Create effect model and add it to MainManager
EffectModel = new AmbientLightningEffectModel(mainManager, (AmbientLightningEffectSettings) EffectSettings);
MainManager.EffectManager.EffectModels.Add(EffectModel); MainManager.EffectManager.EffectModels.Add(EffectModel);
} }
public static string Name => "Ambient Lightning";
public void Handle(ActiveEffectChanged message) public void Handle(ActiveEffectChanged message)
{ {
NotifyOfPropertyChange(() => EffectEnabled); NotifyOfPropertyChange(() => EffectEnabled);

View File

@ -18,10 +18,10 @@ namespace Artemis.Modules.Effects.AmbientLightning
internal class ScreenCapture : IDisposable internal class ScreenCapture : IDisposable
{ {
private readonly Device _device; private readonly Device _device;
private readonly OutputDuplication _duplicatedOutput;
private readonly Factory1 _factory; private readonly Factory1 _factory;
private readonly Texture2D _screenTexture; private readonly Texture2D _screenTexture;
private DataStream _dataStream; private DataStream _dataStream;
private readonly OutputDuplication _duplicatedOutput;
private Resource _screenResource; private Resource _screenResource;
private Surface _screenSurface; private Surface _screenSurface;

View File

@ -5,11 +5,13 @@ using System.Drawing.Drawing2D;
using System.Linq; using System.Linq;
using Artemis.Managers; using Artemis.Managers;
using Artemis.Models; using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Modules.Effects.AudioVisualizer.Utilities; using Artemis.Modules.Effects.AudioVisualizer.Utilities;
using Artemis.Utilities; using Artemis.Utilities;
using Artemis.Utilities.Keyboard; using Artemis.Utilities.Keyboard;
using NAudio.CoreAudioApi; using NAudio.CoreAudioApi;
using NAudio.Wave; using NAudio.Wave;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Modules.Effects.AudioVisualizer namespace Artemis.Modules.Effects.AudioVisualizer
{ {
@ -22,7 +24,7 @@ namespace Artemis.Modules.Effects.AudioVisualizer
private int _sensitivity; private int _sensitivity;
private IWaveIn _waveIn; private IWaveIn _waveIn;
public AudioVisualizerModel(MainManager mainManager, AudioVisualizerSettings settings) : base(mainManager) public AudioVisualizerModel(MainManager mainManager, AudioVisualizerSettings settings) : base(mainManager, null)
{ {
Settings = settings; Settings = settings;
Name = "Audiovisualizer"; Name = "Audiovisualizer";
@ -49,6 +51,8 @@ namespace Artemis.Modules.Effects.AudioVisualizer
_sampleAggregator.PerformFFT = false; _sampleAggregator.PerformFFT = false;
_sampleAggregator.FftCalculated -= FftCalculated; _sampleAggregator.FftCalculated -= FftCalculated;
if (_waveIn == null)
return;
_waveIn.StopRecording(); _waveIn.StopRecording();
_waveIn.DataAvailable -= OnDataAvailable; _waveIn.DataAvailable -= OnDataAvailable;
_waveIn = null; _waveIn = null;
@ -57,7 +61,7 @@ namespace Artemis.Modules.Effects.AudioVisualizer
public override void Enable() public override void Enable()
{ {
Initialized = false; Initialized = false;
Lines = MainManager.KeyboardManager.ActiveKeyboard.Width; Lines = MainManager.DeviceManager.ActiveKeyboard.Width;
// TODO: Device selection // TODO: Device selection
SelectedDeviceId = new MMDeviceEnumerator() SelectedDeviceId = new MMDeviceEnumerator()
@ -69,7 +73,7 @@ namespace Artemis.Modules.Effects.AudioVisualizer
for (var i = 0; i < Lines; i++) for (var i = 0; i < Lines; i++)
{ {
SoundRectangles.Add(new KeyboardRectangle( SoundRectangles.Add(new KeyboardRectangle(
MainManager.KeyboardManager.ActiveKeyboard, MainManager.DeviceManager.ActiveKeyboard,
0, 0, new List<Color> 0, 0, new List<Color>
{ {
ColorHelpers.ToDrawingColor(Settings.TopColor), ColorHelpers.ToDrawingColor(Settings.TopColor),
@ -121,7 +125,7 @@ namespace Artemis.Modules.Effects.AudioVisualizer
// Apply Sensitivity setting // Apply Sensitivity setting
height = height*_sensitivity; height = height*_sensitivity;
var keyboardHeight = var keyboardHeight =
(int) Math.Round(MainManager.KeyboardManager.ActiveKeyboard.Height/100.00*height*Scale); (int) Math.Round(MainManager.DeviceManager.ActiveKeyboard.Height/100.00*height*Scale);
if (keyboardHeight > SoundRectangles[i].Height) if (keyboardHeight > SoundRectangles[i].Height)
SoundRectangles[i].Height = keyboardHeight; SoundRectangles[i].Height = keyboardHeight;
else else
@ -131,31 +135,12 @@ namespace Artemis.Modules.Effects.AudioVisualizer
SoundRectangles[i].Width = Scale; SoundRectangles[i].Width = Scale;
if (_fromBottom) if (_fromBottom)
SoundRectangles[i].Y = MainManager.KeyboardManager.ActiveKeyboard.Height*Scale - SoundRectangles[i].Y = MainManager.DeviceManager.ActiveKeyboard.Height*Scale -
SoundRectangles[i].Height; SoundRectangles[i].Height;
} }
_generating = false; _generating = false;
} }
public override Bitmap GenerateBitmap()
{
if (SpectrumData == null || SoundRectangles == null)
return null;
// Lock the _spectrumData array while busy with it
_generating = true;
var bitmap = MainManager.KeyboardManager.ActiveKeyboard.KeyboardBitmap(Scale);
using (var g = Graphics.FromImage(bitmap))
{
foreach (var soundRectangle in SoundRectangles)
soundRectangle.Draw(g);
}
_generating = false;
return bitmap;
}
private void OnDataAvailable(object sender, WaveInEventArgs e) private void OnDataAvailable(object sender, WaveInEventArgs e)
{ {
var buffer = e.Buffer; var buffer = e.Buffer;
@ -199,5 +184,33 @@ namespace Artemis.Modules.Effects.AudioVisualizer
SpectrumData.Add((byte) y); SpectrumData.Add((byte) y);
} }
} }
public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{
return null;
}
public override void Render(out Bitmap keyboard, out Brush mouse, out Brush headset, bool renderMice,
bool renderHeadsets)
{
keyboard = null;
mouse = null;
headset = null;
if (SpectrumData == null || SoundRectangles == null)
return;
// Lock the _spectrumData array while busy with it
_generating = true;
keyboard = MainManager.DeviceManager.ActiveKeyboard.KeyboardBitmap(Scale);
using (var g = Graphics.FromImage(keyboard))
{
foreach (var soundRectangle in SoundRectangles)
soundRectangle.Draw(g);
}
_generating = false;
}
} }
} }

View File

@ -22,7 +22,6 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
@ -80,38 +79,28 @@
Grid.Row="4" Grid.Column="1" HorizontalAlignment="Right" OnLabel="Yes" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Right" OnLabel="Yes"
OffLabel="No" Margin="0,0,-5,0" Width="114" /> OffLabel="No" Margin="0,0,-5,0" Width="114" />
<!-- Bars amount -->
<TextBlock Grid.Row="5" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,8">
Bars amount (less bars means thicker bars)
</TextBlock>
<Slider x:Name="Bars" Grid.Row="5" Grid.Column="1" VerticalAlignment="Center"
HorizontalAlignment="Right" Width="110" TickPlacement="BottomRight" TickFrequency="1"
Value="{Binding Path=EffectSettings.Bars, Mode=TwoWay}" Minimum="2" Maximum="21"
SmallChange="1" IsSnapToTickEnabled="True" />
<!-- Sensitivity --> <!-- Sensitivity -->
<TextBlock Grid.Row="6" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" <TextBlock Grid.Row="5" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,8"> Height="16" Margin="0,8">
Volume sensitivity multiplier Volume sensitivity multiplier
</TextBlock> </TextBlock>
<Slider x:Name="Sensitivity" Grid.Row="6" Grid.Column="1" VerticalAlignment="Center" <Slider x:Name="Sensitivity" Grid.Row="5" Grid.Column="1" VerticalAlignment="Center"
HorizontalAlignment="Right" Width="110" TickPlacement="BottomRight" TickFrequency="1" HorizontalAlignment="Right" Width="110" TickPlacement="BottomRight" TickFrequency="1"
Value="{Binding Path=EffectSettings.Sensitivity, Mode=TwoWay}" Minimum="1" Maximum="10" Value="{Binding Path=EffectSettings.Sensitivity, Mode=TwoWay}" Minimum="1" Maximum="10"
SmallChange="1" IsSnapToTickEnabled="True" /> SmallChange="1" IsSnapToTickEnabled="True" />
<!-- Fade speed --> <!-- Fade speed -->
<TextBlock Grid.Row="7" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" <TextBlock Grid.Row="6" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,8"> Height="16" Margin="0,8">
Bar fade-out speed Bar fade-out speed
</TextBlock> </TextBlock>
<Slider x:Name="FadeSpeed" Grid.Row="7" Grid.Column="1" VerticalAlignment="Center" <Slider x:Name="FadeSpeed" Grid.Row="6" Grid.Column="1" VerticalAlignment="Center"
HorizontalAlignment="Right" Width="110" TickPlacement="BottomRight" TickFrequency="1" HorizontalAlignment="Right" Width="110" TickPlacement="BottomRight" TickFrequency="1"
Value="{Binding Path=EffectSettings.FadeSpeed, Mode=TwoWay}" Minimum="1" Maximum="3" Value="{Binding Path=EffectSettings.FadeSpeed, Mode=TwoWay}" Minimum="1" Maximum="3"
SmallChange="1" IsSnapToTickEnabled="True" /> SmallChange="1" IsSnapToTickEnabled="True" />
<!-- Buttons --> <!-- Buttons -->
<StackPanel Grid.Column="0" Grid.Row="8" Orientation="Horizontal" VerticalAlignment="Bottom"> <StackPanel Grid.Column="0" Grid.Row="7" Orientation="Horizontal" VerticalAlignment="Bottom">
<Button x:Name="ResetSettings" Content="Reset effect" VerticalAlignment="Top" Width="100" <Button x:Name="ResetSettings" Content="Reset effect" VerticalAlignment="Top" Width="100"
Style="{DynamicResource SquareButtonStyle}" /> Style="{DynamicResource SquareButtonStyle}" />
<Button x:Name="SaveSettings" Content="Save changes" VerticalAlignment="Top" Width="100" <Button x:Name="SaveSettings" Content="Save changes" VerticalAlignment="Top" Width="100"

View File

@ -5,24 +5,18 @@ using Caliburn.Micro;
namespace Artemis.Modules.Effects.AudioVisualizer namespace Artemis.Modules.Effects.AudioVisualizer
{ {
public class AudioVisualizerViewModel : EffectViewModel, IHandle<ActiveEffectChanged> public sealed class AudioVisualizerViewModel : EffectViewModel, IHandle<ActiveEffectChanged>
{ {
public AudioVisualizerViewModel(MainManager mainManager) public AudioVisualizerViewModel(MainManager main, IEventAggregator events)
: base(main, new AudioVisualizerModel(main, new AudioVisualizerSettings()))
{ {
// Subscribe to main model DisplayName = "Audio Visualization";
MainManager = mainManager; events.Subscribe(this);
MainManager.Events.Subscribe(this);
// Settings are loaded from file by class
EffectSettings = new AudioVisualizerSettings();
// Create effect model and add it to MainManager
EffectModel = new AudioVisualizerModel(mainManager, (AudioVisualizerSettings) EffectSettings);
MainManager.EffectManager.EffectModels.Add(EffectModel); MainManager.EffectManager.EffectModels.Add(EffectModel);
EffectSettings = ((AudioVisualizerModel) EffectModel).Settings;
} }
public static string Name => "Audio Visualizer";
public void Handle(ActiveEffectChanged message) public void Handle(ActiveEffectChanged message)
{ {
NotifyOfPropertyChange(() => EffectEnabled); NotifyOfPropertyChange(() => EffectEnabled);

View File

@ -1,72 +0,0 @@
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Utilities.Keyboard;
namespace Artemis.Modules.Effects.Debug
{
// TODO: Remove
internal class DebugEffectModel : EffectModel
{
public DebugEffectModel(MainManager mainManager, DebugEffectSettings settings) : base(mainManager)
{
Name = "Debug Effect";
Settings = settings;
Scale = 4;
Initialized = false;
}
public int Scale { get; set; }
public DebugEffectSettings Settings { get; set; }
public KeyboardRectangle KeyboardRectangle { get; set; }
public override void Dispose()
{
Initialized = false;
}
public override void Enable()
{
Initialized = false;
KeyboardRectangle = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0, 0, new List<Color>
{
Color.Red,
Color.OrangeRed,
Color.Yellow,
Color.Green,
Color.Blue,
Color.Purple,
Color.DeepPink
}, LinearGradientMode.Horizontal);
Initialized = true;
}
public override void Update()
{
KeyboardRectangle.Height = Settings.Height;
KeyboardRectangle.Width = Settings.Width;
KeyboardRectangle.GradientMode = Settings.Type;
KeyboardRectangle.Rotate = Settings.Rotate;
KeyboardRectangle.Scale = Settings.Scale;
Scale = Settings.Scale;
}
public override Bitmap GenerateBitmap()
{
var bitmap = new Bitmap(21*Scale, 6*Scale);
using (var g = Graphics.FromImage(bitmap))
{
g.Clear(Color.Transparent);
KeyboardRectangle.Draw(g);
}
return bitmap;
}
}
}

View File

@ -1,37 +0,0 @@
using System.Drawing.Drawing2D;
using Artemis.Models;
namespace Artemis.Modules.Effects.Debug
{
internal class DebugEffectSettings : EffectSettings
{
public DebugEffectSettings()
{
Load();
}
public int Width { get; set; }
public int Height { get; set; }
public bool Rotate { get; set; }
public int Scale { get; set; }
public LinearGradientMode Type { get; set; }
public sealed override void Load()
{
ToDefault();
}
public sealed override void Save()
{
}
public sealed override void ToDefault()
{
Width = 84;
Height = 24;
Scale = 4;
Type = LinearGradientMode.Horizontal;
Rotate = true;
}
}
}

View File

@ -1,116 +0,0 @@
<UserControl x:Class="Artemis.Modules.Effects.Debug.DebugEffectView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:cal="http://www.caliburnproject.org"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
mc:Ignorable="d"
d:DesignHeight="476.986" d:DesignWidth="538.772">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid Margin="15, 5, 15, 5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,1,0">
<Label FontSize="20" MaxWidth="500" HorizontalAlignment="Left">
<Label.Content>
<AccessText TextWrapping="Wrap"
Text="A few debugging options, also lets you see what is being sent to the keyboard" />
</Label.Content>
</Label>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Label Content="Enable effect" Margin="0 3 0 0" HorizontalAlignment="Right" />
<ToggleButton x:Name="EffectEnabled" Margin="0 3 0 0" Width="25" Height="25"
Style="{DynamicResource MetroCircleToggleButtonStyle}"
cal:Message.Attach="[Event Click] = [Action ToggleEffect]"
ToolTip="Note: You can't enable an effect when Artemis is disabled"
ToolTipService.ShowOnDisabled="True" />
</StackPanel>
</StackPanel>
<!-- Direction -->
<TextBlock Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,8">
Color gradient direction
</TextBlock>
<ComboBox Grid.Row="1" Grid.Column="1" Width="110" HorizontalAlignment="Right" VerticalAlignment="Center"
x:Name="RectangleTypes" />
<!-- Width -->
<TextBlock Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,8">
Debug-rectangle width
</TextBlock>
<Slider x:Name="Width" Grid.Row="2" Grid.Column="1" VerticalAlignment="Center"
HorizontalAlignment="Right" Width="110" TickPlacement="None" TickFrequency="1"
Value="{Binding Path=EffectSettings.Width, Mode=TwoWay}" Minimum="0" Maximum="84"
SmallChange="1" IsSnapToTickEnabled="True" />
<!-- Height -->
<TextBlock Grid.Row="3" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,8">
Debug-rectangle height
</TextBlock>
<Slider x:Name="Height" Grid.Row="3" Grid.Column="1" VerticalAlignment="Center"
HorizontalAlignment="Right" Width="110" TickPlacement="None" TickFrequency="1"
Value="{Binding Path=EffectSettings.Height, Mode=TwoWay}" Minimum="0" Maximum="24"
SmallChange="1" IsSnapToTickEnabled="True" />
<!-- Scale -->
<TextBlock Grid.Row="4" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,8">
Debug-rectangle scale (higher means more fluent)
</TextBlock>
<Slider x:Name="Scale" Grid.Row="4" Grid.Column="1" VerticalAlignment="Center"
HorizontalAlignment="Right" Width="110" TickPlacement="BottomRight" TickFrequency="1"
Value="{Binding Path=EffectSettings.Scale, Mode=TwoWay}" Minimum="1" Maximum="4"
SmallChange="1" IsSnapToTickEnabled="True" />
<!-- Color rotation -->
<TextBlock Grid.Row="5" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,9,0,10">
Rotate colors on debug-rectangle
</TextBlock>
<controls:ToggleSwitch IsChecked="{Binding Path=EffectSettings.Rotate, Mode=TwoWay}"
Grid.Row="5" Grid.Column="1" HorizontalAlignment="Right" OnLabel="Yes"
OffLabel="No"
Margin="0,0,-5,0" Width="114" />
<!-- Preview panel -->
<StackPanel Grid.Row="6" Grid.Column="0" HorizontalAlignment="Left" Margin="0,25,0,0">
<TextBlock>
<InlineUIContainer>
<GroupBox Header="Preview" Margin="0" Height="70" Width="118">
<Image Source="{Binding ImageSource}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Stretch="Fill" />
</GroupBox>
</InlineUIContainer>
</TextBlock>
</StackPanel>
<!-- Buttons -->
<StackPanel Grid.Column="0" Grid.Row="8" Orientation="Horizontal" VerticalAlignment="Bottom">
<Button x:Name="ResetSettings" Content="Reset effect" VerticalAlignment="Top" Width="100"
Style="{DynamicResource SquareButtonStyle}" />
<Button x:Name="SaveSettings" Content="Save changes" VerticalAlignment="Top" Width="100"
Margin="10,0,0,0"
Style="{DynamicResource SquareButtonStyle}" />
</StackPanel>
</Grid>
</ScrollViewer>
</UserControl>

View File

@ -1,15 +0,0 @@
using System.Windows.Controls;
namespace Artemis.Modules.Effects.Debug
{
/// <summary>
/// Interaction logic for DebugEffectView.xaml
/// </summary>
public partial class DebugEffectView : UserControl
{
public DebugEffectView()
{
InitializeComponent();
}
}
}

View File

@ -1,85 +0,0 @@
using System;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Artemis.Events;
using Artemis.Managers;
using Artemis.ViewModels.Abstract;
using Caliburn.Micro;
namespace Artemis.Modules.Effects.Debug
{
internal class DebugEffectViewModel : EffectViewModel, IHandle<ChangeBitmap>, IHandle<ActiveEffectChanged>
{
private ImageSource _imageSource;
private string _selectedRectangleType;
public DebugEffectViewModel(MainManager mainManager)
{
// Subscribe to main model
MainManager = mainManager;
MainManager.Events.Subscribe(this);
// Settings are loaded from file by class
EffectSettings = new DebugEffectSettings();
// Create effect model and add it to MainManager
EffectModel = new DebugEffectModel(mainManager, (DebugEffectSettings) EffectSettings);
MainManager.EffectManager.EffectModels.Add(EffectModel);
}
public static string Name => "Debug Effect";
public BindableCollection<string> RectangleTypes
=> new BindableCollection<string>(Enum.GetNames(typeof (LinearGradientMode)));
public string SelectedRectangleType
{
get { return _selectedRectangleType; }
set
{
if (value == _selectedRectangleType) return;
_selectedRectangleType = value;
NotifyOfPropertyChange(() => SelectedRectangleType);
((DebugEffectSettings) EffectSettings).Type =
(LinearGradientMode) Enum.Parse(typeof (LinearGradientMode), value);
}
}
public ImageSource ImageSource
{
get { return _imageSource; }
set
{
_imageSource = value;
NotifyOfPropertyChange(() => ImageSource);
}
}
public void Handle(ActiveEffectChanged message)
{
NotifyOfPropertyChange(() => EffectEnabled);
}
public void Handle(ChangeBitmap message)
{
using (var memory = new MemoryStream())
{
message.Bitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
ImageSource = bitmapImage;
}
}
}
}

View File

@ -1,27 +1,24 @@
using System.Drawing; using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using Artemis.Managers; using Artemis.Managers;
using Artemis.Models; using Artemis.Models;
using Artemis.Models.Interfaces; using Artemis.Models.Interfaces;
using Artemis.Models.Profiles; using Artemis.Models.Profiles;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Modules.Effects.ProfilePreview namespace Artemis.Modules.Effects.ProfilePreview
{ {
public class ProfilePreviewModel : EffectModel public class ProfilePreviewModel : EffectModel
{ {
private readonly ProfilePreviewDataModel _previewDataModel; public ProfilePreviewModel(MainManager mainManager) : base(mainManager, new ProfilePreviewDataModel())
public ProfilePreviewModel(MainManager mainManager) : base(mainManager)
{ {
Name = "Profile Preview"; Name = "Profile Preview";
_previewDataModel = new ProfilePreviewDataModel();
} }
public ProfileModel SelectedProfile { get; set; }
public override void Dispose() public override void Dispose()
{ {
Initialized = false; Initialized = false;
SelectedProfile = null;
} }
public override void Enable() public override void Enable()
@ -31,32 +28,38 @@ namespace Artemis.Modules.Effects.ProfilePreview
public override void Update() public override void Update()
{ {
if (SelectedProfile == null)
return;
foreach (var layerModel in SelectedProfile.Layers)
layerModel.Update<ProfilePreviewDataModel>(_previewDataModel, true);
} }
public override Bitmap GenerateBitmap() public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{ {
var bitmap = MainManager.KeyboardManager.ActiveKeyboard.KeyboardBitmap(4); return Profile.GetRenderLayers<ProfilePreviewDataModel>(DataModel, renderMice, renderHeadsets, true);
}
if (SelectedProfile == null) public override void Render(out Bitmap keyboard, out Brush mouse, out Brush headset, bool renderMice,
return bitmap; bool renderHeadsets)
{
keyboard = null;
mouse = null;
headset = null;
var keyboardRect = MainManager.KeyboardManager.ActiveKeyboard.KeyboardRectangle(4); if (Profile == null || DataModel == null)
var image = SelectedProfile.GenerateBitmap<ProfilePreviewDataModel>(keyboardRect, _previewDataModel, true); return;
// Draw on top of everything else // Get all enabled layers who's conditions are met
using (var g = Graphics.FromImage(bitmap)) var renderLayers = GetRenderLayers(renderMice, renderHeadsets);
g.DrawImage(image, 0, 0);
return bitmap; // Render the keyboard layer-by-layer
keyboard = Profile?.GenerateBitmap(renderLayers, DataModel,
MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(4), true, true);
// Render the first enabled mouse (will default to null if renderMice was false)
mouse = Profile?.GenerateBrush(renderLayers.LastOrDefault(l => l.LayerType == LayerType.Mouse), DataModel);
// Render the first enabled headset (will default to null if renderHeadsets was false)
headset = Profile?.GenerateBrush(renderLayers.LastOrDefault(l => l.LayerType == LayerType.Headset),
DataModel);
} }
} }
public class ProfilePreviewDataModel : IGameDataModel public class ProfilePreviewDataModel : IDataModel
{ {
} }
} }

View File

@ -1,40 +0,0 @@
using System.Drawing;
using Artemis.Managers;
using Artemis.Models;
namespace Artemis.Modules.Effects.TypeHole
{
public class TypeHoleModel : EffectModel
{
public TypeHoleModel(MainManager mainManager) : base(mainManager)
{
Name = "TypeHole";
Initialized = false;
}
public override void Dispose()
{
Initialized = false;
// Disable logic
}
public override void Enable()
{
Initialized = false;
// Enable logic
Initialized = true;
}
public override void Update()
{
}
public override Bitmap GenerateBitmap()
{
return null;
}
}
}

View File

@ -1,15 +0,0 @@
using System.Windows.Controls;
namespace Artemis.Modules.Effects.TypeHole
{
/// <summary>
/// Interaction logic for TypeHoleView.xaml
/// </summary>
public partial class TypeHoleView : UserControl
{
public TypeHoleView()
{
InitializeComponent();
}
}
}

View File

@ -1,28 +0,0 @@
using Artemis.Events;
using Artemis.Managers;
using Artemis.ViewModels.Abstract;
using Caliburn.Micro;
namespace Artemis.Modules.Effects.TypeHole
{
public class TypeHoleViewModel : EffectViewModel, IHandle<ActiveEffectChanged>
{
public TypeHoleViewModel(MainManager mainManager)
{
// Subscribe to main model
MainManager = mainManager;
MainManager.Events.Subscribe(this);
// Create effect model and add it to MainManager
EffectModel = new TypeHoleModel(mainManager);
MainManager.EffectManager.EffectModels.Add(EffectModel);
}
public static string Name => "Type Holes (NYI)";
public void Handle(ActiveEffectChanged message)
{
NotifyOfPropertyChange(() => EffectEnabled);
}
}
}

View File

@ -3,11 +3,13 @@ using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using Artemis.KeyboardProviders.Corsair; using Artemis.DeviceProviders.Corsair;
using Artemis.KeyboardProviders.Logitech.Utilities; using Artemis.DeviceProviders.Logitech.Utilities;
using Artemis.Managers; using Artemis.Managers;
using Artemis.Models; using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Utilities; using Artemis.Utilities;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Modules.Effects.TypeWave namespace Artemis.Modules.Effects.TypeWave
{ {
@ -16,7 +18,7 @@ namespace Artemis.Modules.Effects.TypeWave
private readonly List<Wave> _waves; private readonly List<Wave> _waves;
private Color _randomColor; private Color _randomColor;
public TypeWaveModel(MainManager mainManager, TypeWaveSettings settings) : base(mainManager) public TypeWaveModel(MainManager mainManager, TypeWaveSettings settings) : base(mainManager, null)
{ {
Name = "TypeWave"; Name = "TypeWave";
_waves = new List<Wave>(); _waves = new List<Wave>();
@ -91,13 +93,23 @@ namespace Artemis.Modules.Effects.TypeWave
} }
} }
public override Bitmap GenerateBitmap() public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{ {
if (_waves.Count == 0) return null;
return null; }
var bitmap = MainManager.KeyboardManager.ActiveKeyboard.KeyboardBitmap(Scale); public override void Render(out Bitmap keyboard, out Brush mouse, out Brush headset, bool renderMice,
using (var g = Graphics.FromImage(bitmap)) bool renderHeadsets)
{
keyboard = null;
mouse = null;
headset = null;
if (_waves.Count == 0)
return;
keyboard = MainManager.DeviceManager.ActiveKeyboard.KeyboardBitmap(Scale);
using (var g = Graphics.FromImage(keyboard))
{ {
g.Clear(Color.Transparent); g.Clear(Color.Transparent);
g.SmoothingMode = SmoothingMode.HighQuality; g.SmoothingMode = SmoothingMode.HighQuality;
@ -113,7 +125,7 @@ namespace Artemis.Modules.Effects.TypeWave
_waves[i].Size, _waves[i].Size); _waves[i].Size, _waves[i].Size);
Color fillColor; Color fillColor;
if (MainManager.KeyboardManager.ActiveKeyboard is CorsairRGB) if (MainManager.DeviceManager.ActiveKeyboard is CorsairRGB)
fillColor = Color.Black; fillColor = Color.Black;
else else
fillColor = Color.Transparent; fillColor = Color.Transparent;
@ -132,7 +144,6 @@ namespace Artemis.Modules.Effects.TypeWave
_waves[i].Point.Y - _waves[i].Size/2, _waves[i].Size, _waves[i].Size); _waves[i].Point.Y - _waves[i].Size/2, _waves[i].Size, _waves[i].Size);
} }
} }
return bitmap;
} }
} }

View File

@ -5,24 +5,18 @@ using Caliburn.Micro;
namespace Artemis.Modules.Effects.TypeWave namespace Artemis.Modules.Effects.TypeWave
{ {
public class TypeWaveViewModel : EffectViewModel, IHandle<ActiveEffectChanged> public sealed class TypeWaveViewModel : EffectViewModel, IHandle<ActiveEffectChanged>
{ {
public TypeWaveViewModel(MainManager mainManager) public TypeWaveViewModel(MainManager main, IEventAggregator events)
: base(main, new TypeWaveModel(main, new TypeWaveSettings()))
{ {
// Subscribe to main model DisplayName = "Type Waves";
MainManager = mainManager; events.Subscribe(this);
MainManager.Events.Subscribe(this);
// Settings are loaded from file by class
EffectSettings = new TypeWaveSettings();
// Create effect model and add it to MainManager
EffectModel = new TypeWaveModel(mainManager, (TypeWaveSettings) EffectSettings);
MainManager.EffectManager.EffectModels.Add(EffectModel); MainManager.EffectManager.EffectModels.Add(EffectModel);
EffectSettings = ((TypeWaveModel) EffectModel).Settings;
} }
public static string Name => "Type Waves";
public void Handle(ActiveEffectChanged message) public void Handle(ActiveEffectChanged message)
{ {
NotifyOfPropertyChange(() => EffectEnabled); NotifyOfPropertyChange(() => EffectEnabled);

View File

@ -0,0 +1,38 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Artemis.Modules.Effects.WindowsProfile {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
internal sealed partial class WindowsProfile : global::System.Configuration.ApplicationSettingsBase {
private static WindowsProfile defaultInstance = ((WindowsProfile)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new WindowsProfile())));
public static WindowsProfile Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Demo (Duplicate to keep changes)")]
public string LastProfile {
get {
return ((string)(this["LastProfile"]));
}
set {
this["LastProfile"] = value;
}
}
}
}

View File

@ -0,0 +1,11 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)"
GeneratedClassNamespace="Artemis.Modules.Effects.WindowsProfile" GeneratedClassName="WindowsProfile">
<Profiles />
<Settings>
<Setting Name="LastProfile" Type="System.String" Scope="User">
<Value Profile="(Default)">Demo (Duplicate to keep changes)</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@ -0,0 +1,42 @@
using Artemis.Models.Interfaces;
namespace Artemis.Modules.Effects.WindowsProfile
{
public class WindowsProfileDataModel : IDataModel
{
public WindowsProfileDataModel()
{
Spotify = new Spotify();
Cpu = new CpuDataModel();
}
public CpuDataModel Cpu { get; set; }
public Spotify Spotify { get; set; }
}
public class CpuDataModel
{
public int Core1Usage { get; set; }
public int Core2Usage { get; set; }
public int Core3Usage { get; set; }
public int Core4Usage { get; set; }
public int Core5Usage { get; set; }
public int Core6Usage { get; set; }
public int Core7Usage { get; set; }
public int Core8Usage { get; set; }
}
public class Spotify
{
public bool Running { get; set; }
public string Artist { get; set; }
public string SongName { get; set; }
public int SongPercentCompleted { get; set; }
public int SpotifyVolume { get; set; }
public string Album { get; set; }
public bool Repeat { get; set; }
public bool Shuffle { get; set; }
public bool Playing { get; set; }
public int SongLength { get; set; }
}
}

View File

@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Profiles;
using SpotifyAPI.Local;
namespace Artemis.Modules.Effects.WindowsProfile
{
public class WindowsProfileModel : EffectModel
{
private List<PerformanceCounter> _cores;
private int _cpuFrames;
private SpotifyLocalAPI _spotify;
private bool _spotifySetupBusy;
public WindowsProfileModel(MainManager mainManager, WindowsProfileSettings settings)
: base(mainManager, new WindowsProfileDataModel())
{
Name = "WindowsProfile";
Settings = settings;
}
public WindowsProfileSettings Settings { get; set; }
public override void Dispose()
{
Initialized = false;
}
public override void Enable()
{
SetupCpu();
SetupSpotify();
Initialized = true;
}
public override void Update()
{
var dataModel = (WindowsProfileDataModel) DataModel;
UpdateCpu(dataModel);
UpdateSpotify(dataModel);
}
#region CPU
private void SetupCpu()
{
_cores = GetPerformanceCounters();
var coreCount = _cores.Count;
while (coreCount < 8)
{
_cores.Add(null);
coreCount++;
}
}
private void UpdateCpu(WindowsProfileDataModel dataModel)
{
// CPU is only updated every 15 frames, the performance counter gives 0 if updated too often
_cpuFrames++;
if (_cpuFrames < 16)
return;
_cpuFrames = 0;
// Update cores, not ideal but data models don't support lists.
if (_cores[0] != null)
dataModel.Cpu.Core1Usage = (int) _cores[0].NextValue();
if (_cores[1] != null)
dataModel.Cpu.Core2Usage = (int) _cores[1].NextValue();
if (_cores[2] != null)
dataModel.Cpu.Core3Usage = (int) _cores[2].NextValue();
if (_cores[3] != null)
dataModel.Cpu.Core4Usage = (int) _cores[3].NextValue();
if (_cores[4] != null)
dataModel.Cpu.Core5Usage = (int) _cores[4].NextValue();
if (_cores[5] != null)
dataModel.Cpu.Core6Usage = (int) _cores[5].NextValue();
if (_cores[6] != null)
dataModel.Cpu.Core7Usage = (int) _cores[6].NextValue();
if (_cores[7] != null)
dataModel.Cpu.Core8Usage = (int) _cores[7].NextValue();
}
public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{
return Profile.GetRenderLayers<WindowsProfileDataModel>(DataModel, renderMice, renderHeadsets, false);
}
public static List<PerformanceCounter> GetPerformanceCounters()
{
var performanceCounters = new List<PerformanceCounter>();
var procCount = Environment.ProcessorCount;
for (var i = 0; i < procCount; i++)
{
var pc = new PerformanceCounter("Processor", "% Processor Time", i.ToString());
performanceCounters.Add(pc);
}
return performanceCounters;
}
#endregion
#region Spotify
public void SetupSpotify()
{
if (_spotifySetupBusy)
return;
_spotifySetupBusy = true;
_spotify = new SpotifyLocalAPI {ListenForEvents = true};
_spotify.OnPlayStateChange += UpdateSpotifyPlayState;
_spotify.OnTrackChange += UpdateSpotifyTrack;
_spotify.OnTrackTimeChange += UpdateSpotifyTrackTime;
// Connecting can sometimes use a little bit more conviction
Task.Factory.StartNew(() =>
{
var tryCount = 0;
while (tryCount <= 10)
{
tryCount++;
var connected = _spotify.Connect();
if (connected)
break;
Thread.Sleep(1000);
}
_spotifySetupBusy = false;
});
}
public void UpdateSpotify(WindowsProfileDataModel dataModel)
{
if (!dataModel.Spotify.Running && SpotifyLocalAPI.IsSpotifyRunning())
SetupSpotify();
dataModel.Spotify.Running = SpotifyLocalAPI.IsSpotifyRunning();
}
private void UpdateSpotifyPlayState(object sender, PlayStateEventArgs e)
{
((WindowsProfileDataModel) DataModel).Spotify.Playing = e.Playing;
}
private void UpdateSpotifyTrack(object sender, TrackChangeEventArgs e)
{
var dataModel = (WindowsProfileDataModel) DataModel;
dataModel.Spotify.Artist = e.NewTrack.ArtistResource?.Name;
dataModel.Spotify.SongName = e.NewTrack.TrackResource?.Name;
dataModel.Spotify.Album = e.NewTrack.AlbumResource?.Name;
dataModel.Spotify.SongLength = e.NewTrack.Length;
}
private void UpdateSpotifyTrackTime(object sender, TrackTimeChangeEventArgs e)
{
var dataModel = (WindowsProfileDataModel) DataModel;
if (dataModel.Spotify.SongLength > 0)
dataModel.Spotify.SongPercentCompleted = (int) (e.TrackTime/dataModel.Spotify.SongLength*100.0);
}
#endregion
}
}

View File

@ -0,0 +1,28 @@
using Artemis.Models;
namespace Artemis.Modules.Effects.WindowsProfile
{
public class WindowsProfileSettings : GameSettings
{
public WindowsProfileSettings()
{
Load();
}
public sealed override void Load()
{
LastProfile = WindowsProfile.Default.LastProfile;
}
public sealed override void Save()
{
WindowsProfile.Default.LastProfile = LastProfile;
WindowsProfile.Default.Save();
}
public sealed override void ToDefault()
{
}
}
}

View File

@ -1,49 +1,56 @@
<UserControl x:Class="Artemis.Modules.Effects.TypeHole.TypeHoleView" <UserControl x:Class="Artemis.Modules.Effects.WindowsProfile.WindowsProfileView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:cal="http://www.caliburnproject.org" xmlns:cal="http://www.caliburnproject.org"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="407.812" d:DesignWidth="671.484" d:DesignHeight="476.986" d:DesignWidth="538.772">
cal:Bind.AtDesignTime="True">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"> <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid Margin="15, 5, 15, 5"> <Grid Margin="15, 5, 15, 5">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="320" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition /> <RowDefinition Height="Auto" />
<RowDefinition /> <RowDefinition Height="Auto" />
<RowDefinition /> <RowDefinition Height="Auto" />
<RowDefinition /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"> <StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,1,0">
<Label FontSize="20" HorizontalAlignment="Left"> <Label FontSize="20" HorizontalAlignment="Left">
<Label.Content> <Label.Content>
<AccessText TextWrapping="Wrap" <AccessText TextWrapping="Wrap"
Text="Creates holes in the keyboard's lightning as you press keys." /> Text="Allows you to create layers shown while not gaming" />
</Label.Content> </Label.Content>
</Label> </Label>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Label Content="Enable effect" Margin="0 3 0 0" HorizontalAlignment="Right" /> <Label Content="Enable effect" Margin="0 3 0 0" HorizontalAlignment="Right" />
<ToggleButton x:Name="EffectEnabled" Margin="0 3 0 0" Width="25" Height="25" <ToggleButton x:Name="EffectEnabled" Margin="0 3 0 0" Width="25" Height="25"
Style="{DynamicResource MetroCircleToggleButtonStyle}" Style="{DynamicResource MetroCircleToggleButtonStyle}"
cal:Message.Attach="[Event Click] = [Action ToggleEffect]" /> cal:Message.Attach="[Event Click] = [Action ToggleEffect]"
<Popup PlacementTarget="{Binding ElementName=EffectEnabled}" ToolTip="Note: You can't enable an effect when Artemis is disabled" />
IsOpen="{Binding Path=ShowDisabledPopup, Mode=TwoWay}" Placement="Left" VerticalOffset="-10"
PopupAnimation="Fade" StaysOpen="False">
<Border Margin="1">
<TextBlock Background="{DynamicResource AccentColorBrush}"
Foreground="{DynamicResource IdealForegroundColorBrush}"
Text="You can't enable an effect when Artemis is disabled" Padding="4" />
</Border>
</Popup>
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
<!-- Profile editor -->
<ContentControl Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" x:Name="ProfileEditor" Margin="0,0,-30,0" />
<!-- Buttons -->
<StackPanel Grid.Column="0" Grid.Row="9" Orientation="Horizontal" VerticalAlignment="Bottom">
<Button x:Name="ResetSettings" Content="Reset effect" VerticalAlignment="Top" Width="100"
Style="{DynamicResource SquareButtonStyle}" />
<Button x:Name="SaveSettings" Content="Save changes" VerticalAlignment="Top" Width="100"
Margin="10,0,0,0"
Style="{DynamicResource SquareButtonStyle}" />
</StackPanel>
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</UserControl> </UserControl>

View File

@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace Artemis.Modules.Effects.WindowsProfile
{
/// <summary>
/// Interaction logic for RocketLeagueView.xaml
/// </summary>
public partial class WindowsProfileView : UserControl
{
public WindowsProfileView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,68 @@
using System.ComponentModel;
using Artemis.Events;
using Artemis.InjectionFactories;
using Artemis.Managers;
using Artemis.Modules.Effects.ProfilePreview;
using Artemis.ViewModels.Abstract;
using Artemis.ViewModels.Profiles;
using Caliburn.Micro;
namespace Artemis.Modules.Effects.WindowsProfile
{
// TODO: This effect is a hybrid between a regular effect and a game, may want to clean this up
public sealed class WindowsProfileViewModel : EffectViewModel, IHandle<ActiveEffectChanged>
{
public WindowsProfileViewModel(MainManager main, IEventAggregator events, IProfileEditorVmFactory pFactory,
ProfilePreviewModel profilePreviewModel)
: base(main, new WindowsProfileModel(main, new WindowsProfileSettings()))
{
DisplayName = "Windows Profile";
PFactory = pFactory;
ProfilePreviewModel = profilePreviewModel;
EffectSettings = ((WindowsProfileModel) EffectModel).Settings;
ProfileEditor = PFactory.CreateProfileEditorVm(events, main, (WindowsProfileModel) EffectModel,
((WindowsProfileSettings) EffectSettings).LastProfile);
ProfilePreviewModel.Profile = ProfileEditor.SelectedProfile;
events.Subscribe(this);
ProfileEditor.PropertyChanged += ProfileUpdater;
MainManager.EffectManager.EffectModels.Add(EffectModel);
}
public ProfileEditorViewModel ProfileEditor { get; set; }
public IProfileEditorVmFactory PFactory { get; set; }
public ProfilePreviewModel ProfilePreviewModel { get; set; }
public void Handle(ActiveEffectChanged message)
{
NotifyOfPropertyChange(() => EffectEnabled);
}
private void ProfileUpdater(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName != "SelectedProfile" && IsActive)
return;
EffectModel.Profile = ProfileEditor.SelectedProfile;
ProfilePreviewModel.Profile = ProfileEditor.SelectedProfile;
if (e.PropertyName != "SelectedProfile" || !ProfileEditor.ProfileViewModel.Activated ||
ProfileEditor.ProfileViewModel.SelectedProfile == null)
return;
((WindowsProfileSettings) EffectSettings).LastProfile = ProfileEditor.ProfileViewModel.SelectedProfile.Name;
EffectSettings.Save();
}
protected override void OnActivate()
{
base.OnActivate();
ProfileEditor.ProfileViewModel.Activate();
}
protected override void OnDeactivate(bool close)
{
base.OnDeactivate(close);
ProfileEditor.ProfileViewModel.Deactivate();
}
}
}

View File

@ -130,5 +130,17 @@ namespace Artemis.Modules.Games.CounterStrike {
this["LowHpEnabled"] = value; this["LowHpEnabled"] = value;
} }
} }
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Default")]
public string LastProfile {
get {
return ((string)(this["LastProfile"]));
}
set {
this["LastProfile"] = value;
}
}
} }
} }

View File

@ -7,6 +7,9 @@
<Setting Name="Enabled" Type="System.Boolean" Scope="User"> <Setting Name="Enabled" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value> <Value Profile="(Default)">True</Value>
</Setting> </Setting>
<Setting Name="LastProfile" Type="System.String" Scope="User">
<Value Profile="(Default)">Default</Value>
</Setting>
<Setting Name="GameDirectory" Type="System.String" Scope="User"> <Setting Name="GameDirectory" Type="System.String" Scope="User">
<Value Profile="(Default)" /> <Value Profile="(Default)" />
</Setting> </Setting>

View File

@ -2,7 +2,7 @@
namespace Artemis.Modules.Games.CounterStrike namespace Artemis.Modules.Games.CounterStrike
{ {
public class CounterStrikeDataModel : IGameDataModel public class CounterStrikeDataModel : IDataModel
{ {
public Provider provider { get; set; } public Provider provider { get; set; }
public Map map { get; set; } public Map map { get; set; }

View File

@ -1,14 +1,18 @@
using System.Drawing; using System;
using System.Collections.Generic;
using Artemis.Managers; using Artemis.Managers;
using Artemis.Models; using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Utilities.GameState; using Artemis.Utilities.GameState;
using Newtonsoft.Json; using Newtonsoft.Json;
using Ninject.Extensions.Logging;
namespace Artemis.Modules.Games.CounterStrike namespace Artemis.Modules.Games.CounterStrike
{ {
public class CounterStrikeModel : GameModel public class CounterStrikeModel : GameModel
{ {
public CounterStrikeModel(MainManager mainManager, CounterStrikeSettings settings) : base(mainManager, settings) public CounterStrikeModel(MainManager mainManager, CounterStrikeSettings settings)
: base(mainManager, settings, new CounterStrikeDataModel())
{ {
Name = "CounterStrike"; Name = "CounterStrike";
ProcessName = "csgo"; ProcessName = "csgo";
@ -17,6 +21,7 @@ namespace Artemis.Modules.Games.CounterStrike
Initialized = false; Initialized = false;
} }
public ILogger Logger { get; set; }
public int Scale { get; set; } public int Scale { get; set; }
public override void Dispose() public override void Dispose()
@ -29,7 +34,6 @@ namespace Artemis.Modules.Games.CounterStrike
{ {
Initialized = false; Initialized = false;
GameDataModel = new CounterStrikeDataModel();
MainManager.GameStateWebServer.GameDataReceived += HandleGameData; MainManager.GameStateWebServer.GameDataReceived += HandleGameData;
Initialized = true; Initialized = true;
@ -37,20 +41,7 @@ namespace Artemis.Modules.Games.CounterStrike
public override void Update() public override void Update()
{ {
if (Profile == null || GameDataModel == null) // TODO: Set up active weapon in the datamodel
return;
foreach (var layerModel in Profile.Layers)
layerModel.Update<CounterStrikeDataModel>(GameDataModel);
}
public override Bitmap GenerateBitmap()
{
if (Profile == null || GameDataModel == null)
return null;
var keyboardRect = MainManager.KeyboardManager.ActiveKeyboard.KeyboardRectangle(Scale);
return Profile.GenerateBitmap<CounterStrikeDataModel>(keyboardRect, GameDataModel);
} }
public void HandleGameData(object sender, GameDataReceivedEventArgs e) public void HandleGameData(object sender, GameDataReceivedEventArgs e)
@ -62,7 +53,20 @@ namespace Artemis.Modules.Games.CounterStrike
return; return;
// Parse the JSON // Parse the JSON
GameDataModel = JsonConvert.DeserializeObject<CounterStrikeDataModel>(jsonString); try
{
DataModel = JsonConvert.DeserializeObject<CounterStrikeDataModel>(jsonString);
}
catch (Exception ex)
{
Logger?.Error(ex, "Failed to deserialize CS:GO JSON");
throw;
}
}
public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{
return Profile.GetRenderLayers<CounterStrikeDataModel>(DataModel, renderMice, renderHeadsets);
} }
} }
} }

View File

@ -24,6 +24,7 @@ namespace Artemis.Modules.Games.CounterStrike
public sealed override void Load() public sealed override void Load()
{ {
Enabled = CounterStrike.Default.Enabled; Enabled = CounterStrike.Default.Enabled;
LastProfile = CounterStrike.Default.LastProfile;
GameDirectory = CounterStrike.Default.GameDirectory; GameDirectory = CounterStrike.Default.GameDirectory;
AmmoEnabled = CounterStrike.Default.AmmoEnabled; AmmoEnabled = CounterStrike.Default.AmmoEnabled;

View File

@ -3,25 +3,23 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:cal="http://www.caliburnproject.org" xmlns:cal="http://www.caliburnproject.org"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="476.986" d:DesignWidth="538.772"> d:DesignHeight="476.986" d:DesignWidth="538.772">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"> <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid Margin="15, 5, 15, 5"> <Grid Margin="15,5,5,5">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="80" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,1,0"> <StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,1,0">
<Label FontSize="20" HorizontalAlignment="Left"> <Label FontSize="20" HorizontalAlignment="Left">
<Label.Content> <Label.Content>
@ -41,20 +39,20 @@
<StackPanel Grid.Row="1" <StackPanel Grid.Row="1"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="2" Margin="0,0,1,0"> Grid.ColumnSpan="2" Margin="0,0,1,0">
<Label FontSize="16" Content="CS:GO Directory" FontFamily="Segoe UI Semibold" Foreground="#535353"
Width="130" HorizontalAlignment="Left" /> <Label FontSize="20" HorizontalAlignment="Left" Content="CS:GO Directory" />
<Grid> <Grid>
<TextBox x:Name="GameDirectory" Height="23" TextWrapping="Wrap" Margin="5,0,30,0" <TextBox x:Name="GameDirectory" Height="23" TextWrapping="Wrap" Margin="5,0,30,0"
Text="{Binding Path=GameSettings.GameDirectory, Mode=TwoWay}" Text="{Binding Path=GameSettings.GameDirectory, Mode=TwoWay}"
cal:Message.Attach="[Event LostFocus] = [Action PlaceConfigFile]" /> cal:Message.Attach="[Event LostFocus] = [Action PlaceConfigFile]" />
<Button x:Name="BrowseDirectory" Content="..." RenderTransformOrigin="-0.039,-0.944" <Button x:Name="BrowseDirectory" Content="..." RenderTransformOrigin="-0.039,-0.944"
HorizontalAlignment="Right" Width="25" HorizontalAlignment="Right" Width="25"
Style="{DynamicResource SquareButtonStyle}" Height="25" /> Style="{DynamicResource SquareButtonStyle}" Height="26" Margin="0,-2,0,0" />
</Grid> </Grid>
</StackPanel> </StackPanel>
<!-- Profile editor --> <!-- Profile editor -->
<ContentControl Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" x:Name="ProfileEditor" Margin="0,0,-30,0" /> <ContentControl Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" x:Name="ProfileEditor" Margin="0,0,-20,0" />
<!-- Buttons --> <!-- Buttons -->
<StackPanel Grid.Column="0" Grid.Row="4" Orientation="Horizontal" VerticalAlignment="Bottom"> <StackPanel Grid.Column="0" Grid.Row="4" Orientation="Horizontal" VerticalAlignment="Bottom">

View File

@ -1,23 +1,38 @@
using System.IO; using System.IO;
using System.Windows.Forms; using System.Windows.Forms;
using Artemis.InjectionFactories;
using Artemis.Managers; using Artemis.Managers;
using Artemis.Properties; using Artemis.Properties;
using Artemis.Utilities;
using Artemis.ViewModels.Abstract; using Artemis.ViewModels.Abstract;
using Caliburn.Micro;
namespace Artemis.Modules.Games.CounterStrike namespace Artemis.Modules.Games.CounterStrike
{ {
public class CounterStrikeViewModel : GameViewModel<CounterStrikeDataModel> public sealed class CounterStrikeViewModel : GameViewModel
{ {
public CounterStrikeViewModel(MainManager mainManager) public CounterStrikeViewModel(MainManager main, IEventAggregator events, IProfileEditorVmFactory pFactory)
: base(mainManager, new CounterStrikeModel(mainManager, new CounterStrikeSettings())) : base(main, new CounterStrikeModel(main, new CounterStrikeSettings()), events, pFactory)
{ {
// Create effect model and add it to MainManager DisplayName = "CS:GO";
MainManager.EffectManager.EffectModels.Add(GameModel); MainManager.EffectManager.EffectModels.Add(GameModel);
FindGameDir();
PlaceConfigFile(); PlaceConfigFile();
} }
public static string Name => "CS:GO"; public void FindGameDir()
public string Content => "Counter-Strike: GO Content"; {
var gameSettings = (CounterStrikeSettings) GameSettings;
// If already propertly set up, don't do anything
if (gameSettings.GameDirectory != null && File.Exists(gameSettings.GameDirectory + "csgo.exe") &&
File.Exists(gameSettings.GameDirectory + "/csgo/cfg/gamestate_integration_artemis.cfg"))
return;
var dir = GeneralHelpers.FindSteamGame(@"\Counter-Strike Global Offensive\csgo.exe");
gameSettings.GameDirectory = dir ?? string.Empty;
gameSettings.Save();
}
public void BrowseDirectory() public void BrowseDirectory()
{ {
@ -26,7 +41,7 @@ namespace Artemis.Modules.Games.CounterStrike
if (result != DialogResult.OK) if (result != DialogResult.OK)
return; return;
((CounterStrikeSettings) GameSettings).GameDirectory = dialog.SelectedPath; ((CounterStrikeSettings) GameSettings).GameDirectory = Path.GetDirectoryName(dialog.SelectedPath);
NotifyOfPropertyChange(() => GameSettings); NotifyOfPropertyChange(() => GameSettings);
GameSettings.Save(); GameSettings.Save();
@ -37,22 +52,22 @@ namespace Artemis.Modules.Games.CounterStrike
{ {
if (((CounterStrikeSettings) GameSettings).GameDirectory == string.Empty) if (((CounterStrikeSettings) GameSettings).GameDirectory == string.Empty)
return; return;
if (Directory.Exists(((CounterStrikeSettings) GameSettings).GameDirectory + "/csgo/cfg"))
var path = ((CounterStrikeSettings) GameSettings).GameDirectory;
if (Directory.Exists(path + "/csgo/cfg"))
{ {
var cfgFile = Resources.csgoGamestateConfiguration.Replace("{{port}}", var cfgFile = Resources.csgoGamestateConfiguration.Replace("{{port}}",
MainManager.GameStateWebServer.Port.ToString()); MainManager.GameStateWebServer.Port.ToString());
File.WriteAllText( File.WriteAllText(path + "/csgo/cfg/gamestate_integration_artemis.cfg", cfgFile);
((CounterStrikeSettings) GameSettings).GameDirectory + "/csgo/cfg/gamestate_integration_artemis.cfg",
cfgFile);
return; return;
} }
MainManager.DialogService.ShowErrorMessageBox("Please select a valid CS:GO directory\n\n" + DialogService.ShowErrorMessageBox("Please select a valid CS:GO directory\n\n" +
@"By default CS:GO is in \SteamApps\common\Counter-Strike Global Offensive"); @"By default CS:GO is in \SteamApps\common\Counter-Strike Global Offensive");
((CounterStrikeSettings) GameSettings).GameDirectory = string.Empty; ((CounterStrikeSettings) GameSettings).GameDirectory = string.Empty;
NotifyOfPropertyChange(() => GameSettings); NotifyOfPropertyChange(() => GameSettings);
GameSettings.Save(); GameSettings.Save();
} }
} }

View File

@ -35,6 +35,18 @@ namespace Artemis.Modules.Games.Dota2 {
} }
} }
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Default")]
public string LastProfile {
get {
return ((string)(this["LastProfile"]));
}
set {
this["LastProfile"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()] [global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")] [global::System.Configuration.DefaultSettingValueAttribute("")]

View File

@ -7,6 +7,9 @@
<Setting Name="Enabled" Type="System.Boolean" Scope="User"> <Setting Name="Enabled" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value> <Value Profile="(Default)">True</Value>
</Setting> </Setting>
<Setting Name="LastProfile" Type="System.String" Scope="User">
<Value Profile="(Default)">Default</Value>
</Setting>
<Setting Name="GameDirectory" Type="System.String" Scope="User"> <Setting Name="GameDirectory" Type="System.String" Scope="User">
<Value Profile="(Default)" /> <Value Profile="(Default)" />
</Setting> </Setting>

View File

@ -1,228 +1,228 @@
namespace Artemis.Modules.Games.Dota2 using Artemis.Models.Interfaces;
namespace Artemis.Modules.Games.Dota2
{ {
public class Dota2DataModel public class Dota2DataModel : IDataModel
{ {
public class Rootobject public Provider provider { get; set; }
{ public Map map { get; set; }
public Provider provider { get; set; } public Player player { get; set; }
public Map map { get; set; } public Hero hero { get; set; }
public Player player { get; set; } public Abilities abilities { get; set; }
public Hero hero { get; set; } public Items items { get; set; }
public Abilities abilities { get; set; } public Previously previously { get; set; }
public Items items { get; set; } }
public Previously previously { get; set; }
}
public class Provider public class Provider
{ {
public string name { get; set; } public string name { get; set; }
public int appid { get; set; } public int appid { get; set; }
public int version { get; set; } public int version { get; set; }
public int timestamp { get; set; } public int timestamp { get; set; }
} }
public class Map public class Map
{ {
public string name { get; set; } public int dayCyclePercentage;
public long matchid { get; set; } public string name { get; set; }
public int game_time { get; set; } public long matchid { get; set; }
public int clock_time { get; set; } public int game_time { get; set; }
public bool daytime { get; set; } public int clock_time { get; set; }
public bool nightstalker_night { get; set; } public bool daytime { get; set; }
public string game_state { get; set; } public bool nightstalker_night { get; set; }
public string win_team { get; set; } public string game_state { get; set; }
public string customgamename { get; set; } public string win_team { get; set; }
public int ward_purchase_cooldown { get; set; } public string customgamename { get; set; }
} public int ward_purchase_cooldown { get; set; }
}
public class Player public class Player
{ {
public string steamid { get; set; } public string steamid { get; set; }
public string name { get; set; } public string name { get; set; }
public string activity { get; set; } public string activity { get; set; }
public int kills { get; set; } public int kills { get; set; }
public int deaths { get; set; } public int deaths { get; set; }
public int assists { get; set; } public int assists { get; set; }
public int last_hits { get; set; } public int last_hits { get; set; }
public int denies { get; set; } public int denies { get; set; }
public int kill_streak { get; set; } public int kill_streak { get; set; }
public string team_name { get; set; } public string team_name { get; set; }
public int gold { get; set; } public int gold { get; set; }
public int gold_reliable { get; set; } public int gold_reliable { get; set; }
public int gold_unreliable { get; set; } public int gold_unreliable { get; set; }
public int gpm { get; set; } public int gpm { get; set; }
public int xpm { get; set; } public int xpm { get; set; }
} }
public class Hero public class Hero
{ {
public int id { get; set; } public int id { get; set; }
public string name { get; set; } public string name { get; set; }
public int level { get; set; } public int level { get; set; }
public bool alive { get; set; } public bool alive { get; set; }
public int respawn_seconds { get; set; } public int respawn_seconds { get; set; }
public int buyback_cost { get; set; } public int buyback_cost { get; set; }
public int buyback_cooldown { get; set; } public int buyback_cooldown { get; set; }
public int health { get; set; } public int health { get; set; }
public int max_health { get; set; } public int max_health { get; set; }
public int health_percent { get; set; } public int health_percent { get; set; }
public int mana { get; set; } public int mana { get; set; }
public int max_mana { get; set; } public int max_mana { get; set; }
public int mana_percent { get; set; } public int mana_percent { get; set; }
public bool silenced { get; set; } public bool silenced { get; set; }
public bool stunned { get; set; } public bool stunned { get; set; }
public bool disarmed { get; set; } public bool disarmed { get; set; }
public bool magicimmune { get; set; } public bool magicimmune { get; set; }
public bool hexed { get; set; } public bool hexed { get; set; }
public bool muted { get; set; } public bool muted { get; set; }
public bool _break { get; set; } public bool _break { get; set; }
public bool has_debuff { get; set; } public bool has_debuff { get; set; }
} }
public class Abilities public class Abilities
{ {
public Ability0 ability0 { get; set; } public Ability0 ability0 { get; set; }
public Ability1 ability1 { get; set; } public Ability1 ability1 { get; set; }
public Ability2 ability2 { get; set; } public Ability2 ability2 { get; set; }
public Ability3 ability3 { get; set; } public Ability3 ability3 { get; set; }
public Attributes attributes { get; set; } public Attributes attributes { get; set; }
} }
public class Ability0 public class Ability0
{ {
public string name { get; set; } public string name { get; set; }
public int level { get; set; } public int level { get; set; }
public bool can_cast { get; set; } public bool can_cast { get; set; }
public bool passive { get; set; } public bool passive { get; set; }
public bool ability_active { get; set; } public bool ability_active { get; set; }
public int cooldown { get; set; } public int cooldown { get; set; }
public bool ultimate { get; set; } public bool ultimate { get; set; }
} }
public class Ability1 public class Ability1
{ {
public string name { get; set; } public string name { get; set; }
public int level { get; set; } public int level { get; set; }
public bool can_cast { get; set; } public bool can_cast { get; set; }
public bool passive { get; set; } public bool passive { get; set; }
public bool ability_active { get; set; } public bool ability_active { get; set; }
public int cooldown { get; set; } public int cooldown { get; set; }
public bool ultimate { get; set; } public bool ultimate { get; set; }
} }
public class Ability2 public class Ability2
{ {
public string name { get; set; } public string name { get; set; }
public int level { get; set; } public int level { get; set; }
public bool can_cast { get; set; } public bool can_cast { get; set; }
public bool passive { get; set; } public bool passive { get; set; }
public bool ability_active { get; set; } public bool ability_active { get; set; }
public int cooldown { get; set; } public int cooldown { get; set; }
public bool ultimate { get; set; } public bool ultimate { get; set; }
} }
public class Ability3 public class Ability3
{ {
public string name { get; set; } public string name { get; set; }
public int level { get; set; } public int level { get; set; }
public bool can_cast { get; set; } public bool can_cast { get; set; }
public bool passive { get; set; } public bool passive { get; set; }
public bool ability_active { get; set; } public bool ability_active { get; set; }
public int cooldown { get; set; } public int cooldown { get; set; }
public bool ultimate { get; set; } public bool ultimate { get; set; }
} }
public class Attributes public class Attributes
{ {
public int level { get; set; } public int level { get; set; }
} }
public class Items public class Items
{ {
public Slot0 slot0 { get; set; } public Slot0 slot0 { get; set; }
public Slot1 slot1 { get; set; } public Slot1 slot1 { get; set; }
public Slot2 slot2 { get; set; } public Slot2 slot2 { get; set; }
public Slot3 slot3 { get; set; } public Slot3 slot3 { get; set; }
public Slot4 slot4 { get; set; } public Slot4 slot4 { get; set; }
public Slot5 slot5 { get; set; } public Slot5 slot5 { get; set; }
public Stash0 stash0 { get; set; } public Stash0 stash0 { get; set; }
public Stash1 stash1 { get; set; } public Stash1 stash1 { get; set; }
public Stash2 stash2 { get; set; } public Stash2 stash2 { get; set; }
public Stash3 stash3 { get; set; } public Stash3 stash3 { get; set; }
public Stash4 stash4 { get; set; } public Stash4 stash4 { get; set; }
public Stash5 stash5 { get; set; } public Stash5 stash5 { get; set; }
} }
public class Slot0 public class Slot0
{ {
public string name { get; set; } public string name { get; set; }
} }
public class Slot1 public class Slot1
{ {
public string name { get; set; } public string name { get; set; }
} }
public class Slot2 public class Slot2
{ {
public string name { get; set; } public string name { get; set; }
} }
public class Slot3 public class Slot3
{ {
public string name { get; set; } public string name { get; set; }
} }
public class Slot4 public class Slot4
{ {
public string name { get; set; } public string name { get; set; }
} }
public class Slot5 public class Slot5
{ {
public string name { get; set; } public string name { get; set; }
} }
public class Stash0 public class Stash0
{ {
public string name { get; set; } public string name { get; set; }
} }
public class Stash1 public class Stash1
{ {
public string name { get; set; } public string name { get; set; }
} }
public class Stash2 public class Stash2
{ {
public string name { get; set; } public string name { get; set; }
} }
public class Stash3 public class Stash3
{ {
public string name { get; set; } public string name { get; set; }
} }
public class Stash4 public class Stash4
{ {
public string name { get; set; } public string name { get; set; }
} }
public class Stash5 public class Stash5
{ {
public string name { get; set; } public string name { get; set; }
} }
public class Previously public class Previously
{ {
public Player1 player { get; set; } public Player1 player { get; set; }
} }
public class Player1 public class Player1
{ {
public int gold { get; set; } public int gold { get; set; }
public int gold_unreliable { get; set; } public int gold_unreliable { get; set; }
}
} }
} }

View File

@ -1,25 +1,16 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using Artemis.KeyboardProviders;
using Artemis.Managers; using Artemis.Managers;
using Artemis.Models; using Artemis.Models;
using Artemis.Utilities; using Artemis.Models.Profiles;
using Artemis.Utilities.GameState; using Artemis.Utilities.GameState;
using Artemis.Utilities.Keyboard;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Artemis.Modules.Games.Dota2 namespace Artemis.Modules.Games.Dota2
{ {
internal class Dota2Model : GameModel internal class Dota2Model : GameModel
{ {
private KeyboardRegion _abilityKeys; public Dota2Model(MainManager mainManager, Dota2Settings settings)
private KeyboardRegion _keyPad; : base(mainManager, settings, new Dota2DataModel())
private KeyboardRegion _topRow;
public Dota2Model(MainManager mainManager, Dota2Settings settings) : base(mainManager, settings)
{ {
Name = "Dota2"; Name = "Dota2";
ProcessName = "dota2"; ProcessName = "dota2";
@ -29,6 +20,7 @@ namespace Artemis.Modules.Games.Dota2
Scale = 4; Scale = 4;
} }
public int Scale { get; set; }
public new Dota2Settings Settings { get; set; } public new Dota2Settings Settings { get; set; }
public override void Dispose() public override void Dispose()
@ -40,278 +32,26 @@ namespace Artemis.Modules.Games.Dota2
public override void Enable() public override void Enable()
{ {
Initialized = false; Initialized = false;
_topRow = MainManager.KeyboardManager.ActiveKeyboard.KeyboardRegions.First(r => r.RegionName == "TopRow");
_keyPad = MainManager.KeyboardManager.ActiveKeyboard.KeyboardRegions.First(r => r.RegionName == "NumPad");
_abilityKeys = MainManager.KeyboardManager.ActiveKeyboard.KeyboardRegions.First(r => r.RegionName == "QWER");
HealthRectangle = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard
, 0
, _topRow.BottomRight.Y*Scale
, new List<Color>()
, LinearGradientMode.Horizontal)
{Height = Scale, ContainedBrush = false};
ManaRectangle = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard
, 0
, (_topRow.BottomRight.Y + 1)*Scale
, new List<Color>()
, LinearGradientMode.Horizontal)
{Height = Scale, ContainedBrush = false};
EventRectangle = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard
, 0
, _topRow.TopLeft.X + 3
, new List<Color>()
, LinearGradientMode.Horizontal)
{
Height = MainManager.KeyboardManager.ActiveKeyboard.Height*Scale - Scale
,
Width = MainManager.KeyboardManager.ActiveKeyboard.Width*Scale - Scale - 12
};
DayCycleRectangle = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard
, _keyPad.TopLeft.X*Scale
, _keyPad.TopLeft.Y*Scale
, new List<Color>()
, LinearGradientMode.Horizontal)
{
Height = _keyPad.GetRectangle().Height*Scale,
Width = _keyPad.GetRectangle().Width*Scale
};
SetAbilityKeys();
MainManager.GameStateWebServer.GameDataReceived += HandleGameData; MainManager.GameStateWebServer.GameDataReceived += HandleGameData;
Initialized = true; Initialized = true;
} }
private void SetAbilityKeys()
{
#region Long Switch Statement for Keys
switch (Settings.KeyboardLayout)
{
case "0":
case "Default": //default
case "4": //Heroes of newearth
case "3": //League of Legends
for (var i = 0; i < AbilityKeysRectangles.Length; i++)
{
AbilityKeysRectangles[i] = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard,
(_abilityKeys.TopLeft.X + i)*Scale - 2,
_abilityKeys.TopLeft.Y*Scale,
new List<Color>(),
LinearGradientMode.Horizontal)
{
Height = Scale,
Width = Scale
};
}
break;
case "2":
AbilityKeysRectangles[0] = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard,
_abilityKeys.TopLeft.X*Scale - 2,
_abilityKeys.TopLeft.Y*Scale,
new List<Color>(),
LinearGradientMode.Horizontal)
{
Height = Scale,
Width = Scale
};
AbilityKeysRectangles[1] = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard,
(_abilityKeys.TopLeft.X + 2)*Scale - 2,
_abilityKeys.TopLeft.Y*Scale,
new List<Color>(),
LinearGradientMode.Horizontal)
{
Height = Scale,
Width = Scale
};
AbilityKeysRectangles[2] = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard,
(_abilityKeys.TopLeft.X + 3)*Scale - 2,
_abilityKeys.TopLeft.Y*Scale,
new List<Color>(),
LinearGradientMode.Horizontal)
{
Height = Scale,
Width = Scale
};
AbilityKeysRectangles[3] = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard,
(_abilityKeys.TopLeft.X + 3)*Scale - 2,
(_abilityKeys.TopLeft.Y + 1)*Scale,
new List<Color>(),
LinearGradientMode.Horizontal)
{
Height = Scale,
Width = Scale
};
break;
case "1": //MMO
case "5": //Smite
for (var i = 0; i < AbilityKeysRectangles.Length; i++)
{
AbilityKeysRectangles[i] = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard,
(_abilityKeys.TopLeft.X + i)*Scale - 3,
(_abilityKeys.TopLeft.Y - 1)*Scale,
new List<Color>(),
LinearGradientMode.Horizontal)
{
Height = Scale,
Width = Scale
};
}
break;
}
#endregion
}
public override void Update() public override void Update()
{ {
if (D2Json?.map == null) UpdateDay();
return;
UpdateMainColor();
if (Settings.ShowEvents)
UpdateEvents();
if (Settings.ShowDayCycle)
UpdateDay();
if (!D2Json.hero.alive)
return;
if (Settings.CanCastAbility)
UpdateAbilities();
if (Settings.ShowHealth)
UpdateHealth();
if (Settings.ShowMana)
UpdateMana();
}
private void UpdateMainColor()
{
var list = new List<Color> {ColorHelpers.ToDrawingColor(Settings.MainColor)};
EventRectangle.Colors = list;
DayCycleRectangle.Colors = list;
HealthRectangle.Colors = list;
ManaRectangle.Colors = list;
foreach (var key in AbilityKeysRectangles)
key.Colors = list;
}
private void UpdateEvents()
{
List<Color> list = null;
if (!D2Json.hero.alive)
list = new List<Color> {Color.LightGray};
else if (D2Json.hero.disarmed)
list = new List<Color> {Color.Yellow};
else if (D2Json.hero.hexed)
list = new List<Color> {Color.Yellow};
else if (D2Json.hero.silenced)
list = new List<Color> {Color.Yellow};
else if (D2Json.hero.stunned)
list = new List<Color> {Color.Yellow};
else if (D2Json.hero.magicimmune)
list = new List<Color> {Color.Lime};
if (list == null)
return;
EventRectangle.Colors = list;
DayCycleRectangle.Colors = list;
HealthRectangle.Colors = list;
ManaRectangle.Colors = list;
foreach (var item in AbilityKeysRectangles)
item.Colors = list;
} }
private void UpdateDay() private void UpdateDay()
{ {
if (D2Json?.map?.daytime == null) var dataModel = DataModel as Dota2DataModel;
if (dataModel?.map?.daytime == null)
return; return;
if (D2Json.map.nightstalker_night) var timeLeft = 240 - dataModel.map.clock_time%240;
{ dataModel.map.dayCyclePercentage = (int) (100.00/240*timeLeft);
DayCycleRectangle.Colors = new List<Color> {Color.Blue};
return;
}
var timeLeft = 240 - D2Json.map.clock_time%240;
var timePercentage = 100.00/240*timeLeft;
DayCycleRectangle.Width = (int) (_keyPad.GetRectangle().Width*Scale/100.00*timePercentage);
DayCycleRectangle.Colors = D2Json.map.daytime
? new List<Color> {Color.Yellow}
: new List<Color> {Color.Blue};
} }
private void UpdateMana()
{
if (D2Json?.hero == null || D2Json.hero.mana_percent == -1)
return;
var manaPercent = D2Json.hero.mana_percent;
ManaRectangle.Colors = new List<Color> {ColorHelpers.ToDrawingColor(Settings.ManaColor)};
ManaRectangle.Width = (int) Math.Floor(_topRow.GetRectangle().Width*Scale/100.00*manaPercent);
}
private void UpdateAbilities()
{
if (AbilityKeysRectangles == null)
return;
AbilityKeysRectangles[0].Colors = D2Json?.abilities?.ability0?.can_cast == true
? new List<Color>
{ColorHelpers.ToDrawingColor(Settings.AbilityReadyColor)}
: new List<Color> {ColorHelpers.ToDrawingColor(Settings.AbilityCooldownColor)};
AbilityKeysRectangles[1].Colors = D2Json?.abilities?.ability1?.can_cast == true
? new List<Color>
{ColorHelpers.ToDrawingColor(Settings.AbilityReadyColor)}
: new List<Color> {ColorHelpers.ToDrawingColor(Settings.AbilityCooldownColor)};
AbilityKeysRectangles[2].Colors = D2Json?.abilities?.ability2?.can_cast == true
? new List<Color>
{ColorHelpers.ToDrawingColor(Settings.AbilityReadyColor)}
: new List<Color> {ColorHelpers.ToDrawingColor(Settings.AbilityCooldownColor)};
AbilityKeysRectangles[3].Colors = D2Json?.abilities?.ability3?.can_cast == true
? new List<Color>
{ColorHelpers.ToDrawingColor(Settings.AbilityReadyColor)}
: new List<Color> {ColorHelpers.ToDrawingColor(Settings.AbilityCooldownColor)};
}
private void UpdateHealth()
{
if (D2Json?.hero == null || D2Json.hero.health_percent == -1)
return;
var healthPercent = D2Json.hero.health_percent;
if (healthPercent > 66)
HealthRectangle.Colors = new List<Color> {Color.Lime};
else if (healthPercent > 33)
HealthRectangle.Colors = new List<Color> {Color.Yellow};
else
HealthRectangle.Colors = new List<Color> {Color.Red};
HealthRectangle.Width = (int) Math.Floor(_topRow.GetRectangle().Width*Scale/100.00*healthPercent);
}
public override Bitmap GenerateBitmap()
{
var bitmap = MainManager.KeyboardManager.ActiveKeyboard.KeyboardBitmap(Scale);
using (var g = Graphics.FromImage(bitmap))
{
g.Clear(Color.Transparent);
EventRectangle.Draw(g);
HealthRectangle.Draw(g);
ManaRectangle.Draw(g);
foreach (var item in AbilityKeysRectangles)
{
item.Draw(g);
}
DayCycleRectangle.Draw(g);
}
return bitmap;
}
public void HandleGameData(object sender, GameDataReceivedEventArgs e) public void HandleGameData(object sender, GameDataReceivedEventArgs e)
{ {
var jsonString = e.Json.ToString(); var jsonString = e.Json.ToString();
@ -321,19 +61,12 @@ namespace Artemis.Modules.Games.Dota2
return; return;
// Parse the JSON // Parse the JSON
D2Json = JsonConvert.DeserializeObject<Dota2DataModel.Rootobject>(jsonString); DataModel = JsonConvert.DeserializeObject<Dota2DataModel>(jsonString);
} }
#region Variables public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{
public Dota2DataModel.Rootobject D2Json { get; set; } return Profile.GetRenderLayers<Dota2DataModel>(DataModel, renderMice, renderHeadsets);
public int Scale { get; set; } }
public KeyboardRectangle HealthRectangle { get; set; }
public KeyboardRectangle EventRectangle { get; set; }
public KeyboardRectangle DayCycleRectangle { get; set; }
public KeyboardRectangle ManaRectangle { get; set; }
public KeyboardRectangle[] AbilityKeysRectangles = new KeyboardRectangle[4];
#endregion
} }
} }

View File

@ -29,14 +29,16 @@ namespace Artemis.Modules.Games.Dota2
public override void Save() public override void Save()
{ {
Dota2.Default.Enabled = Enabled;
Dota2.Default.LastProfile = LastProfile;
Dota2.Default.GameDirectory = GameDirectory;
Dota2.Default.KeyboardLayout = KeyboardLayout; Dota2.Default.KeyboardLayout = KeyboardLayout;
Dota2.Default.MainColor = MainColor; Dota2.Default.MainColor = MainColor;
Dota2.Default.ManaColor = ManaColor; Dota2.Default.ManaColor = ManaColor;
Dota2.Default.ShowDayCycle = ShowDayCycle; Dota2.Default.ShowDayCycle = ShowDayCycle;
Dota2.Default.ShowHealth = ShowHealth; Dota2.Default.ShowHealth = ShowHealth;
Dota2.Default.CanCastAbility = CanCastAbility; Dota2.Default.CanCastAbility = CanCastAbility;
Dota2.Default.Enabled = Enabled;
Dota2.Default.GameDirectory = GameDirectory;
Dota2.Default.ShowMana = ShowMana; Dota2.Default.ShowMana = ShowMana;
Dota2.Default.ShowEvents = ShowEvents; Dota2.Default.ShowEvents = ShowEvents;
Dota2.Default.AbilityCooldownColor = AbilityCooldownColor; Dota2.Default.AbilityCooldownColor = AbilityCooldownColor;

View File

@ -4,36 +4,27 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:cal="http://www.caliburnproject.org" xmlns:cal="http://www.caliburnproject.org"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" mc:Ignorable="d"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" d:DesignHeight="476.986" d:DesignWidth="538.772">
mc:Ignorable="d" d:DesignWidth="635" Height="515.691"> <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Margin="0,0,0,-19"> <Grid Margin="15,5,5,5">
<Grid Margin="15, 5, 15, 5">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition /> <ColumnDefinition />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="80" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,1,0"> <StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,1,0">
<Label FontSize="20" HorizontalAlignment="Left"> <Label FontSize="20" HorizontalAlignment="Left">
<Label.Content> <Label.Content>
<AccessText TextWrapping="Wrap" <AccessText TextWrapping="Wrap"
Text="Shows game states and events from Dota 2." /> Text="Shows verious game states and events on the keyboard." />
</Label.Content> </Label.Content>
</Label> </Label>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
@ -45,130 +36,31 @@
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="1" <StackPanel Grid.Row="1"
Grid.Column="0" Grid.Column="0"
Grid.ColumnSpan="2" Margin="0,0,1,0"> Grid.ColumnSpan="2" Margin="0,0,1,0">
<Label FontSize="16" Content="Dota 2 Directory" FontFamily="Segoe UI Semibold" Foreground="#535353" <Label FontSize="20" HorizontalAlignment="Left" Content="Dota 2 Directory" />
Width="130" HorizontalAlignment="Left" />
<Grid> <Grid>
<TextBox x:Name="GameDirectory" Height="23" TextWrapping="Wrap" Margin="5,0,30,0" <TextBox x:Name="GameDirectory" Height="23" TextWrapping="Wrap" Margin="5,0,30,0"
Text="{Binding Path=GameSettings.GameDirectory, Mode=TwoWay}" Text="{Binding Path=GameSettings.GameDirectory, Mode=TwoWay}"
cal:Message.Attach="[Event LostFocus] = [Action PlaceConfigFile]" /> cal:Message.Attach="[Event LostFocus] = [Action PlaceConfigFile]" />
<Button x:Name="BrowseDirectory" Content="..." RenderTransformOrigin="-0.039,-0.944" <Button x:Name="BrowseDirectory" Content="..." RenderTransformOrigin="-0.039,-0.944"
HorizontalAlignment="Right" Width="25" HorizontalAlignment="Right" Width="25"
Style="{DynamicResource SquareButtonStyle}" Height="25" /> Style="{DynamicResource SquareButtonStyle}" Height="26" Margin="0,-2,0,0" />
</Grid> </Grid>
</StackPanel> </StackPanel>
<!-- Main Color --> <!-- Profile editor -->
<TextBlock Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left" Width="114" VerticalAlignment="Center" <ContentControl Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" x:Name="ProfileEditor" Margin="0,0,-20,0" />
Height="16" Margin="0,8">
Main keyboard color
</TextBlock>
<xctk:ColorPicker x:Name="MainColor"
SelectedColor="{Binding Path=GameSettings.MainColor, Mode=TwoWay}"
Grid.Row="2" Grid.Column="1" Width="110" HorizontalAlignment="Right"
VerticalAlignment="Center" Margin="0,5,-1,5" Height="22" />
<!-- Ability Ready Color --> <!-- Buttons -->
<TextBlock Grid.Row="3" Grid.Column="0" HorizontalAlignment="Left" Width="114" VerticalAlignment="Center" <StackPanel Grid.Column="0" Grid.Row="4" Orientation="Horizontal" VerticalAlignment="Bottom">
Height="16" Margin="0,8">
Ability Ready Color
</TextBlock>
<xctk:ColorPicker x:Name="AbilityReadyColor"
SelectedColor="{Binding Path=GameSettings.AbilityReadyColor, Mode=TwoWay}"
Grid.Row="3" Grid.Column="1" Width="110" HorizontalAlignment="Right"
VerticalAlignment="Center" Margin="0,5,-1,5" Height="22" />
<!-- Ability on Cooldown Color -->
<TextBlock Grid.Row="4" Grid.Column="0" HorizontalAlignment="Left" Width="147" VerticalAlignment="Center"
Height="16" Margin="0,8">
Ability on Cooldown Color
</TextBlock>
<xctk:ColorPicker x:Name="AbilityCooldownColor"
SelectedColor="{Binding Path=GameSettings.AbilityCooldownColor, Mode=TwoWay}"
Grid.Row="4" Grid.Column="1" Width="110" HorizontalAlignment="Right"
VerticalAlignment="Center" Margin="0,5,-1,5" Height="22" />
<!-- Abilities Display -->
<TextBlock Grid.Row="5" Grid.Column="0" HorizontalAlignment="Left" Width="168" VerticalAlignment="Center"
Height="16" Margin="0,10,0,9">
Keyboard Template
</TextBlock>
<ComboBox Grid.Row="5" Grid.Column="1" x:Name="KeyboardLayouts"
ItemsSource="{Binding Path=KeyboardLayouts}"
SelectedIndex="{Binding Path=GameSettings.KeyboardLayout}" VerticalAlignment="Center"
HorizontalAlignment="Right"
Width="109" Margin="0,6,0,7" />
<!-- Items Display -->
<TextBlock Grid.Row="6" Grid.Column="0" HorizontalAlignment="Left" Width="168" VerticalAlignment="Center"
Height="16" Margin="0,10,0,9">
Castable Abilities
</TextBlock>
<controls:ToggleSwitch IsChecked="{Binding Path=GameSettings.CanCastAbility, Mode=TwoWay}"
Grid.Row="6" Grid.Column="1" HorizontalAlignment="Right" OnLabel="Yes" OffLabel="No"
Margin="0,0,-5,0" Width="114" />
<!-- Health Display -->
<TextBlock Grid.Row="7" Grid.Column="0" HorizontalAlignment="Left" Width="168" VerticalAlignment="Center"
Height="16" Margin="0,10,0,9">
Display health
</TextBlock>
<controls:ToggleSwitch IsChecked="{Binding Path=GameSettings.ShowHealth, Mode=TwoWay}"
Grid.Row="7" Grid.Column="1" HorizontalAlignment="Right" OnLabel="Yes" OffLabel="No"
Margin="0,0,-5,0" Width="114" />
<!-- Mana Display-->
<TextBlock Grid.Row="8" Grid.Column="0" HorizontalAlignment="Left" Width="168" VerticalAlignment="Center"
Height="16" Margin="0,10,0,9">
Display mana
</TextBlock>
<controls:ToggleSwitch IsChecked="{Binding Path=GameSettings.ShowMana, Mode=TwoWay}"
Grid.Row="8" Grid.Column="1" HorizontalAlignment="Right" OnLabel="Yes" OffLabel="No"
Margin="0,0,-5,0" Width="114" />
<!-- Mana Color -->
<TextBlock Grid.Row="9" Grid.Column="0" HorizontalAlignment="Left" Width="114" VerticalAlignment="Center"
Height="16" Margin="0,8">
Mana color
</TextBlock>
<xctk:ColorPicker x:Name="ManaColor"
SelectedColor="{Binding Path=GameSettings.ManaColor, Mode=TwoWay}"
Grid.Row="9" Grid.Column="1" Width="110" HorizontalAlignment="Right"
VerticalAlignment="Center" Margin="0,5,-1,5" Height="22" />
<!-- Daytime Display -->
<TextBlock Grid.Row="10" Grid.Column="0" HorizontalAlignment="Left" Width="168" VerticalAlignment="Center"
Height="16" Margin="0,10,0,9">
Display day/night
</TextBlock>
<controls:ToggleSwitch IsChecked="{Binding Path=GameSettings.ShowDayCycle, Mode=TwoWay}"
Grid.Row="10" Grid.Column="1" HorizontalAlignment="Right" OnLabel="Yes"
OffLabel="No"
Margin="0,0,-5,0" Width="114" />
<!-- Dead Display -->
<TextBlock Grid.Row="11" Grid.Column="0" HorizontalAlignment="Left" Width="168" VerticalAlignment="Center"
Height="16" Margin="0,10,0,9">
Show events on the keyboard
</TextBlock>
<controls:ToggleSwitch IsChecked="{Binding Path=GameSettings.ShowEvents, Mode=TwoWay}"
Grid.Row="11" Grid.Column="1" HorizontalAlignment="Right" OnLabel="Yes"
OffLabel="No"
Margin="0,0,-5,0" Width="114" />
<StackPanel Grid.Column="0" Grid.Row="12" Orientation="Horizontal" VerticalAlignment="Bottom">
<Button x:Name="ResetSettings" Content="Reset effect" VerticalAlignment="Top" Width="100" <Button x:Name="ResetSettings" Content="Reset effect" VerticalAlignment="Top" Width="100"
Style="{DynamicResource SquareButtonStyle}" /> Style="{DynamicResource SquareButtonStyle}" />
<Button x:Name="SaveSettings" Content="Save changes" VerticalAlignment="Top" Width="100" <Button x:Name="SaveSettings" Content="Save changes" VerticalAlignment="Top" Width="100"
Margin="10,0,0,0" Margin="10,0,0,0"
Style="{DynamicResource SquareButtonStyle}" /> Style="{DynamicResource SquareButtonStyle}" />
</StackPanel> </StackPanel>
</Grid> </Grid>
</ScrollViewer> </ScrollViewer>
</UserControl> </UserControl>

View File

@ -1,33 +1,41 @@
using System.IO; using System.IO;
using System.Windows.Forms; using System.Windows.Forms;
using Artemis.InjectionFactories;
using Artemis.Managers; using Artemis.Managers;
using Artemis.Properties; using Artemis.Properties;
using Artemis.Utilities;
using Artemis.ViewModels.Abstract; using Artemis.ViewModels.Abstract;
using Caliburn.Micro; using Caliburn.Micro;
namespace Artemis.Modules.Games.Dota2 namespace Artemis.Modules.Games.Dota2
{ {
public class Dota2ViewModel : GameViewModel<Dota2DataModel> public sealed class Dota2ViewModel : GameViewModel
{ {
public Dota2ViewModel(MainManager mainManager) public Dota2ViewModel(MainManager main, IEventAggregator events, IProfileEditorVmFactory pFactory)
: base(mainManager, new Dota2Model(mainManager, new Dota2Settings())) : base(main, new Dota2Model(main, new Dota2Settings()), events, pFactory)
{ {
DisplayName = "Dota 2";
MainManager.EffectManager.EffectModels.Add(GameModel); MainManager.EffectManager.EffectModels.Add(GameModel);
FindGameDir();
PlaceConfigFile(); PlaceConfigFile();
} }
public BindableCollection<string> KeyboardLayouts => new BindableCollection<string>(new[] public void FindGameDir()
{ {
"Default", var gameSettings = (Dota2Settings) GameSettings;
"MMO", // If already propertly set up, don't do anything
"WASD", if (gameSettings.GameDirectory != null && File.Exists(gameSettings.GameDirectory + "csgo.exe") &&
"League of Legends", File.Exists(gameSettings.GameDirectory + "/csgo/cfg/gamestate_integration_artemis.cfg"))
"Heros of Newearth", return;
"Smite"
});
public static string Name => "Dota 2"; var dir = GeneralHelpers.FindSteamGame(@"\dota 2 beta\game\bin\win32\dota2.exe");
public string Content => "Dota 2 Content"; // Remove subdirectories where they stuck the executable
dir = dir?.Substring(0, dir.Length - 15);
gameSettings.GameDirectory = dir ?? string.Empty;
gameSettings.Save();
}
public void BrowseDirectory() public void BrowseDirectory()
{ {
@ -68,12 +76,11 @@ namespace Artemis.Modules.Games.Dota2
cfgFile); cfgFile);
} }
return; return;
} }
MainManager.DialogService.ShowErrorMessageBox("Please select a valid Dota 2 directory\n\n" + DialogService.ShowErrorMessageBox("Please select a valid Dota 2 directory\n\n" +
@"By default Dota 2 is in \SteamApps\common\dota 2 beta"); @"By default Dota 2 is in \SteamApps\common\dota 2 beta");
((Dota2Settings) GameSettings).GameDirectory = string.Empty; ((Dota2Settings) GameSettings).GameDirectory = string.Empty;
NotifyOfPropertyChange(() => GameSettings); NotifyOfPropertyChange(() => GameSettings);

View File

@ -0,0 +1,62 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Artemis.Modules.Games.Overwatch {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
internal sealed partial class Overwatch : global::System.Configuration.ApplicationSettingsBase {
private static Overwatch defaultInstance = ((Overwatch)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Overwatch())));
public static Overwatch Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool Enabled {
get {
return ((bool)(this["Enabled"]));
}
set {
this["Enabled"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Default")]
public string LastProfile {
get {
return ((string)(this["LastProfile"]));
}
set {
this["LastProfile"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string GameDirectory {
get {
return ((string)(this["GameDirectory"]));
}
set {
this["GameDirectory"] = value;
}
}
}
}

View File

@ -0,0 +1,17 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)"
GeneratedClassNamespace="Artemis.Modules.Games.Overwatch" GeneratedClassName="Overwatch">
<Profiles />
<Settings>
<Setting Name="Enabled" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="LastProfile" Type="System.String" Scope="User">
<Value Profile="(Default)">Default</Value>
</Setting>
<Setting Name="GameDirectory" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
</Settings>
</SettingsFile>

View File

@ -0,0 +1,46 @@
using Artemis.Models.Interfaces;
namespace Artemis.Modules.Games.Overwatch
{
public class OverwatchDataModel : IDataModel
{
public OverwatchStatus Status { get; set; }
public OverwatchCharacter Character { get; set; }
public bool UltimateReady { get; set; }
public bool Ability1Ready { get; set; }
public bool Ability2Ready { get; set; }
}
public enum OverwatchStatus
{
Unkown,
InMainMenu,
InGame
}
public enum OverwatchCharacter
{
None,
Genji,
Mccree,
Pharah,
Reaper,
Soldier76,
Tracer,
Bastion,
Hanzo,
Junkrat,
Mei,
Torbjörn,
Widowmaker,
Dva,
Reinhardt,
Roadhog,
Winston,
Zarya,
Lúcio,
Mercy,
Symmetra,
Zenyatta
}
}

View File

@ -0,0 +1,147 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using Artemis.Events;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles;
using Artemis.Utilities;
using Artemis.Utilities.DataReaders;
using Caliburn.Micro;
using Color = System.Windows.Media.Color;
namespace Artemis.Modules.Games.Overwatch
{
public class OverwatchModel : GameModel
{
private readonly IEventAggregator _events;
public OverwatchModel(IEventAggregator events, MainManager mainManager, OverwatchSettings settings)
: base(mainManager, settings, new OverwatchDataModel())
{
_events = events;
Name = "Overwatch";
ProcessName = "Overwatch";
Scale = 4;
Enabled = Settings.Enabled;
Initialized = false;
MmfReader = new MmfReader("overwatchMmf");
LoadOverwatchCharacters();
}
public OverwatchModel(MainManager mainManager, GameSettings settings, IDataModel dataModel)
: base(mainManager, settings, dataModel)
{
}
public List<CharacterColor> OverwatchCharacters { get; set; }
public MmfReader MmfReader { get; set; }
public int Scale { get; set; }
private void LoadOverwatchCharacters()
{
OverwatchCharacters = new List<CharacterColor>
{
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Genji, Color = Color.FromRgb(13, 61, 0)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Mccree, Color = Color.FromRgb(24, 1, 1)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Pharah, Color = Color.FromRgb(0, 6, 32)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Reaper, Color = Color.FromRgb(7, 0, 0)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Soldier76, Color = Color.FromRgb(3, 5, 11)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Tracer, Color = Color.FromRgb(46, 12, 0)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Bastion, Color = Color.FromRgb(6, 10, 5)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Hanzo, Color = Color.FromRgb(28, 24, 8)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Junkrat, Color = Color.FromRgb(59, 28, 0)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Mei, Color = Color.FromRgb(3, 20, 55)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Torbjörn, Color = Color.FromRgb(31, 4, 3)},
new CharacterColor
{
OverwatchCharacter = OverwatchCharacter.Widowmaker,
Color = Color.FromRgb(16, 3, 17)
},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Dva, Color = Color.FromRgb(62, 12, 32)},
new CharacterColor
{
OverwatchCharacter = OverwatchCharacter.Reinhardt,
Color = Color.FromRgb(12, 16, 16)
},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Roadhog, Color = Color.FromRgb(26, 10, 0)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Winston, Color = Color.FromRgb(17, 18, 26)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Zarya, Color = Color.FromRgb(58, 7, 24)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Lúcio, Color = Color.FromRgb(8, 35, 0)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Mercy, Color = Color.FromRgb(60, 56, 26)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Symmetra, Color = Color.FromRgb(11, 29, 37)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Zenyatta, Color = Color.FromRgb(62, 54, 6)}
};
}
public override void Dispose()
{
Initialized = false;
}
public override void Enable()
{
Initialized = true;
}
public override void Update()
{
var gameDataModel = (OverwatchDataModel) DataModel;
var colors = MmfReader.GetColorArray();
if (colors == null)
return;
var bitmap = new Bitmap(22, 6);
using (var g = Graphics.FromImage(bitmap))
{
for (var y = 0; y < 6; y++)
{
for (var x = 0; x < 22; x++)
{
g.DrawRectangle(new Pen(ColorHelpers.ToDrawingColor(colors[y, x])), y, x, 1, 1);
}
}
}
_events.PublishOnUIThread(new ChangeBitmap(bitmap));
// Determine general game state
gameDataModel.Status = colors[0, 0].Equals(Color.FromRgb(55, 30, 0))
? OverwatchStatus.InMainMenu
: OverwatchStatus.Unkown;
if (gameDataModel.Status == OverwatchStatus.InMainMenu)
return;
// If ingame, look for a character
var characterMatch = OverwatchCharacters.FirstOrDefault(c => c.Color == colors[0, 0]);
if (characterMatch.OverwatchCharacter == OverwatchCharacter.None)
return;
gameDataModel.Status = OverwatchStatus.InGame;
gameDataModel.Character = characterMatch.OverwatchCharacter;
// Ability1 is ready when LShift is lid
gameDataModel.Ability1Ready = colors[4, 1].Equals(Color.FromRgb(4, 141, 144));
// Ability2 is ready when E is lid
gameDataModel.Ability2Ready = colors[2, 4].Equals(Color.FromRgb(4, 141, 144));
// Ultimate is ready when Q is blinking
gameDataModel.UltimateReady = !characterMatch.Color.Equals(colors[2, 2]);
}
public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{
return Profile.GetRenderLayers<OverwatchDataModel>(DataModel, renderMice, renderHeadsets);
}
}
public struct CharacterColor
{
public OverwatchCharacter OverwatchCharacter { get; set; }
public Color Color { get; set; }
}
}

View File

@ -0,0 +1,36 @@
using Artemis.Models;
namespace Artemis.Modules.Games.Overwatch
{
public class OverwatchSettings : GameSettings
{
public OverwatchSettings()
{
Load();
}
public string GameDirectory { get; set; }
public sealed override void Load()
{
Enabled = Overwatch.Default.Enabled;
LastProfile = Overwatch.Default.LastProfile;
GameDirectory = Overwatch.Default.GameDirectory;
}
public sealed override void Save()
{
Overwatch.Default.Enabled = Enabled;
Overwatch.Default.LastProfile = LastProfile;
Overwatch.Default.GameDirectory = GameDirectory;
Overwatch.Default.Save();
}
public sealed override void ToDefault()
{
Enabled = true;
GameDirectory = string.Empty;
}
}
}

View File

@ -0,0 +1,66 @@
<UserControl x:Class="Artemis.Modules.Games.Overwatch.OverwatchView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:cal="http://www.caliburnproject.org"
mc:Ignorable="d"
d:DesignHeight="410.933" d:DesignWidth="732.154">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid Margin="15, 5, 15, 5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,1,0">
<Label FontSize="20" HorizontalAlignment="Left">
<Label.Content>
<AccessText TextWrapping="Wrap"
Text="Allows you to create layers based on ingame cooldown and your hero." />
</Label.Content>
</Label>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Label Content="Enable effect" Margin="0 3 0 0" HorizontalAlignment="Right" />
<ToggleButton x:Name="EffectEnabled" Margin="0 3 0 0" Width="25" Height="25"
IsChecked="{Binding Path=GameSettings.Enabled, Mode=TwoWay}"
Style="{DynamicResource MetroCircleToggleButtonStyle}"
cal:Message.Attach="[Event Click] = [Action ToggleEffect]" />
</StackPanel>
</StackPanel>
<StackPanel Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2" Margin="0,0,1,0">
<Label FontSize="20" HorizontalAlignment="Left" Content="Overwatch Directory" />
<Grid>
<TextBox x:Name="GameDirectory" Height="23" TextWrapping="Wrap" Margin="5,0,30,0"
Text="{Binding Path=GameSettings.GameDirectory, Mode=TwoWay}"
cal:Message.Attach="[Event LostFocus] = [Action PlaceDll]" />
<Button x:Name="BrowseDirectory" Content="..." RenderTransformOrigin="-0.039,-0.944"
HorizontalAlignment="Right" Width="25"
Style="{DynamicResource SquareButtonStyle}" Height="26" Margin="0,-2,0,0" />
</Grid>
</StackPanel>
<!-- Profile editor -->
<ContentControl Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" x:Name="ProfileEditor" Margin="0,0,-30,0" />
<!-- Buttons -->
<StackPanel Grid.Column="0" Grid.Row="3" Orientation="Horizontal" VerticalAlignment="Bottom">
<Button x:Name="ResetSettings" Content="Reset effect" VerticalAlignment="Top" Width="100"
Style="{DynamicResource SquareButtonStyle}" />
<Button x:Name="SaveSettings" Content="Save changes" VerticalAlignment="Top" Width="100"
Margin="10,0,0,0"
Style="{DynamicResource SquareButtonStyle}" />
</StackPanel>
</Grid>
</ScrollViewer>
</UserControl>

View File

@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace Artemis.Modules.Games.Overwatch
{
/// <summary>
/// Interaction logic for OverwatchView.xaml
/// </summary>
public partial class OverwatchView : UserControl
{
public OverwatchView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,85 @@
using System;
using System.IO;
using System.Windows.Forms;
using Artemis.InjectionFactories;
using Artemis.Managers;
using Artemis.Properties;
using Artemis.ViewModels.Abstract;
using Caliburn.Micro;
using Microsoft.Win32;
namespace Artemis.Modules.Games.Overwatch
{
public sealed class OverwatchViewModel : GameViewModel
{
public OverwatchViewModel(MainManager main, IEventAggregator events, IProfileEditorVmFactory pFactory)
: base(main, new OverwatchModel(events, main, new OverwatchSettings()), events, pFactory)
{
DisplayName = "Overwatch";
MainManager.EffectManager.EffectModels.Add(GameModel);
FindOverwatch();
}
public void FindOverwatch()
{
var gameSettings = (OverwatchSettings) GameSettings;
// If already propertly set up, don't do anything
if (gameSettings.GameDirectory != null && File.Exists(gameSettings.GameDirectory + "Overwatch.exe") &&
File.Exists(gameSettings.GameDirectory + "RzChromaSDK64.dll"))
return;
var key = Registry.LocalMachine.OpenSubKey(
@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Overwatch");
if (key == null)
return;
var path = key.GetValue("DisplayIcon").ToString();
if (!File.Exists(path))
return;
gameSettings.GameDirectory = path.Substring(0, path.Length - 14);
gameSettings.Save();
PlaceDll();
}
public void BrowseDirectory()
{
var dialog = new FolderBrowserDialog {SelectedPath = ((OverwatchSettings) GameSettings).GameDirectory};
var result = dialog.ShowDialog();
if (result != DialogResult.OK)
return;
((OverwatchSettings) GameSettings).GameDirectory = dialog.SelectedPath;
NotifyOfPropertyChange(() => GameSettings);
GameSettings.Save();
PlaceDll();
}
public void PlaceDll()
{
var path = ((OverwatchSettings) GameSettings).GameDirectory;
if (!File.Exists(path + @"\Overwatch.exe"))
{
DialogService.ShowErrorMessageBox("Please select a valid Overwatch directory\n\n" +
@"By default Overwatch is in C:\Program Files (x86)\Overwatch");
((OverwatchSettings) GameSettings).GameDirectory = string.Empty;
NotifyOfPropertyChange(() => GameSettings);
GameSettings.Save();
return;
}
try
{
File.WriteAllBytes(path + @"\RzChromaSDK64.dll", Resources.RzChromaSDK64);
}
catch (Exception e)
{
Logger?.Error(e, "Couldn't place Overwatch DLL, Overwatch support won't work.");
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More