1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +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
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis", "Artemis\Artemis.csproj", "{ED9997A2-E54C-4E9F-9350-62BE672C3ABE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Razer2Artemis", "Razer2Artemis\Razer2Artemis.vcxproj", "{39711909-C1D5-46CE-A9EA-2D561692EA47}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
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|x86.ActiveCfg = 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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -4,6 +4,12 @@
<configSections>
<sectionGroup name="userSettings"
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"
type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
allowExeDefinition="MachineToLocalUser" requirePermission="false" />
@ -53,6 +59,22 @@
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<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>
<setting name="Enabled" serializeAs="String">
<value>True</value>
@ -111,14 +133,8 @@
<setting name="Enabled" serializeAs="String">
<value>True</value>
</setting>
<setting name="MainColor" serializeAs="String">
<value>#FFFF5000</value>
</setting>
<setting name="SecondaryColor" serializeAs="String">
<value>#FFFF0000</value>
</setting>
<setting name="ContextualColor" serializeAs="String">
<value>False</value>
<setting name="LastProfile" serializeAs="String">
<value>Default</value>
</setting>
</Artemis.Modules.Games.RocketLeague.RocketLeague>
<Artemis.Settings.Offsets>
@ -185,6 +201,9 @@
<setting name="LowHpEnabled" serializeAs="String">
<value>True</value>
</setting>
<setting name="LastProfile" serializeAs="String">
<value>Default</value>
</setting>
</Artemis.Modules.Games.CounterStrike.CounterStrike>
<Artemis.Settings.CounterStrike>
<setting name="GameDirectory" serializeAs="String">
@ -293,6 +312,9 @@
<setting name="CheckForUpdates" serializeAs="String">
<value>True</value>
</setting>
<setting name="Theme" serializeAs="String">
<value>Light</value>
</setting>
</Artemis.Settings.General>
</userSettings>
<runtime>
@ -321,6 +343,10 @@
<assemblyIdentity name="SharpDX" publicKeyToken="b4dcf0f35e5521f1" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.0.2.0" newVersion="3.0.2.0" />
</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>
</runtime>

View File

@ -1,7 +1,8 @@
using System;
using System.Security.Principal;
using System.Windows;
using System.Windows.Threading;
using Artemis.Utilities;
using NLog;
using WpfExceptionViewer;
namespace Artemis
@ -13,14 +14,22 @@ namespace Artemis
{
public App()
{
if (!GeneralHelpers.IsRunAsAdministrator())
GeneralHelpers.RunAsAdministrator();
//if (!IsRunAsAdministrator())
// GeneralHelpers.RunAsAdministrator();
InitializeComponent();
}
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)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
@ -40,7 +49,6 @@ namespace Artemis
}
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var ex = e.ExceptionObject as Exception;
@ -49,6 +57,8 @@ namespace Artemis
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)
{
Title = "Artemis - Exception :c",

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -120,20 +120,20 @@
</PropertyGroup>
<PropertyGroup />
<ItemGroup>
<Reference Include="Autofac, Version=4.0.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
<HintPath>..\packages\Autofac.4.0.0-rc1-177\lib\net45\Autofac.dll</HintPath>
<Reference Include="Caliburn.Micro, Version=3.0.1.0, Culture=neutral, PublicKeyToken=8e5891231f2ed21f, processorArchitecture=MSIL">
<HintPath>..\packages\Caliburn.Micro.Core.3.0.1\lib\net45\Caliburn.Micro.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Caliburn.Micro, Version=2.0.2.0, Culture=neutral, PublicKeyToken=8e5891231f2ed21f, processorArchitecture=MSIL">
<HintPath>..\packages\Caliburn.Micro.Core.2.0.2\lib\net45\Caliburn.Micro.dll</HintPath>
<Reference Include="Caliburn.Micro.Platform, Version=3.0.1.0, Culture=neutral, PublicKeyToken=8e5891231f2ed21f, processorArchitecture=MSIL">
<HintPath>..\packages\Caliburn.Micro.3.0.1\lib\net45\Caliburn.Micro.Platform.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Caliburn.Micro.Autofac, Version=2.0.9.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Caliburn.Micro.AutofacBootstrap.2.0.9-beta\lib\net40\Caliburn.Micro.Autofac.dll</HintPath>
<Reference Include="Caliburn.Micro.Platform.Core, Version=3.0.1.0, Culture=neutral, PublicKeyToken=8e5891231f2ed21f, processorArchitecture=MSIL">
<HintPath>..\packages\Caliburn.Micro.3.0.1\lib\net45\Caliburn.Micro.Platform.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Caliburn.Micro.Platform, Version=2.0.2.0, Culture=neutral, PublicKeyToken=8e5891231f2ed21f, processorArchitecture=MSIL">
<HintPath>..\packages\Caliburn.Micro.2.0.2\lib\net45\Caliburn.Micro.Platform.dll</HintPath>
<Reference Include="Castle.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<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>
<Private>True</Private>
</Reference>
<Reference Include="CUE.NET, Version=1.0.2.2, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\CUE.NET.1.0.2.2\lib\net45\CUE.NET.dll</HintPath>
<Reference Include="CUE.NET, Version=1.0.3.0, Culture=neutral, processorArchitecture=MSIL">
<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>
</Reference>
<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>
<Private>True</Private>
</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">
<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>
</Reference>
<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>
<Private>True</Private>
</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.ComponentModel.DataAnnotations" />
<Reference Include="System.Data" />
<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">
<HintPath>..\packages\System.Linq.Dynamic.1.0.6\lib\net40\System.Linq.Dynamic.dll</HintPath>
<Private>True</Private>
@ -202,7 +228,10 @@
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Web" />
<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="Microsoft.CSharp" />
<Reference Include="System.Core" />
@ -259,34 +288,44 @@
</Compile>
<Compile Include="ArtemisBootstrapper.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\ToggleEnabled.cs" />
<Compile Include="Events\ActiveEffectChanged.cs" />
<Compile Include="Events\ChangeBitmap.cs" />
<Compile Include="InjectionFactories\ILayerEditorVmFactory.cs" />
<Compile Include="InjectionFactories\IProfileEditorVmFactory.cs" />
<Compile Include="ItemBehaviours\BindableSelectedItemBehavior.cs" />
<Compile Include="KeyboardProviders\Corsair\CorsairRGB.cs" />
<Compile Include="KeyboardProviders\KeyboardProvider.cs" />
<Compile Include="KeyboardProviders\KeyboardRegion.cs" />
<Compile Include="KeyboardProviders\Logitech\Orion.cs" />
<Compile Include="KeyboardProviders\Logitech\Utilities\KeyboardNames.cs" />
<Compile Include="KeyboardProviders\Logitech\Utilities\KeyMap.cs" />
<Compile Include="KeyboardProviders\Logitech\Utilities\LogitechGSDK.cs" />
<Compile Include="KeyboardProviders\Logitech\Utilities\OrionUtilities.cs" />
<Compile Include="KeyboardProviders\ProviderHelper.cs" />
<Compile Include="KeyboardProviders\Razer\BlackWidow.cs" />
<Compile Include="KeyboardProviders\Razer\Utilities\RazerUtilities.cs" />
<Compile Include="DeviceProviders\Corsair\CorsairRGB.cs" />
<Compile Include="DeviceProviders\KeyboardProvider.cs" />
<Compile Include="DeviceProviders\Logitech\Orion.cs" />
<Compile Include="DeviceProviders\Logitech\Utilities\KeyboardNames.cs" />
<Compile Include="DeviceProviders\Logitech\Utilities\KeyMap.cs" />
<Compile Include="DeviceProviders\Logitech\Utilities\LogitechGSDK.cs" />
<Compile Include="DeviceProviders\Logitech\Utilities\OrionUtilities.cs" />
<Compile Include="DeviceProviders\Razer\BlackWidow.cs" />
<Compile Include="DeviceProviders\Razer\Utilities\RazerUtilities.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\ProfileManager.cs" />
<Compile Include="Models\EffectModel.cs" />
<Compile Include="Models\EffectSettings.cs" />
<Compile Include="Models\GameSettings.cs" />
<Compile Include="Models\Interfaces\GameDataModel.cs" />
<Compile Include="Models\OverlaySettings.cs" />
<Compile Include="Models\Profiles\LayerConditionModel.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\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\AmbientLightningEffectSettings.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\Utilities\FftEventArgs.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\TypeHole\TypeHoleModel.cs" />
<Compile Include="Modules\Effects\TypeWave\TypeWave.Designer.cs">
<DependentUpon>TypeWave.settings</DependentUpon>
<AutoGen>True</AutoGen>
@ -328,6 +377,9 @@
<Compile Include="Modules\Games\Dota2\Dota2DataModel.cs" />
<Compile Include="Modules\Games\Dota2\Dota2Model.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">
<DependentUpon>RocketLeague.settings</DependentUpon>
<AutoGen>True</AutoGen>
@ -347,6 +399,16 @@
<DependentUpon>TheDivisionView.xaml</DependentUpon>
</Compile>
<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\Witcher3.Designer.cs">
<AutoGen>True</AutoGen>
@ -363,10 +425,12 @@
</Compile>
<Compile Include="Modules\Overlays\VolumeDisplay\VolumeDisplayModel.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\Games\RocketLeague\RocketLeagueSettings.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\Resources.Designer.cs">
<AutoGen>True</AutoGen>
@ -386,14 +450,19 @@
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<DependentUpon>Offsets.settings</DependentUpon>
</Compile>
<Compile Include="Styles\DropTargetAdorners\DropTargetMetroHighlightAdorner.cs" />
<Compile Include="Styles\DropTargetAdorners\DropTargetMetroInsertionAdorner.cs" />
<Compile Include="Utilities\ColorHelpers.cs" />
<Compile Include="Utilities\DataReaders\MmfReader.cs" />
<Compile Include="Utilities\ExtensionMethods.cs" />
<Compile Include="Utilities\GameState\GameDataReceivedEventArgs.cs" />
<Compile Include="Utilities\GameState\GameStateWebServer.cs" />
<Compile Include="Utilities\GeneralHelpers.cs" />
<Compile Include="Utilities\GifImage.cs" />
<Compile Include="Utilities\ImageUtilities.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\NamedPipeServer.cs" />
<Compile Include="Utilities\LogitechDll\PipeServer.cs" />
@ -409,12 +478,12 @@
<Compile Include="Utilities\StickyValue.cs" />
<Compile Include="Utilities\Updater.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\GameViewModel.cs" />
<Compile Include="ViewModels\EffectsViewModel.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="ViewModels\FlyoutBaseViewModel.cs" />
<Compile Include="ViewModels\Flyouts\FlyoutSettingsViewModel.cs" />
@ -423,12 +492,18 @@
<Compile Include="Modules\Games\Dota2\Dota2ViewModel.cs" />
<Compile Include="Modules\Games\RocketLeague\RocketLeagueViewModel.cs" />
<Compile Include="Modules\Games\Witcher3\Witcher3ViewModel.cs" />
<Compile Include="ViewModels\LayerEditor\LayerConditionViewModel.cs" />
<Compile Include="ViewModels\LayerEditor\LayerDynamicPropertiesViewModel.cs" />
<Compile Include="ViewModels\LayerEditor\LayerEditorViewModel.cs" />
<Compile Include="ViewModels\Profiles\ProfileViewModel.cs" />
<Compile Include="ViewModels\Profiles\Properties\KeyboardPropertiesViewModel.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="Modules\Overlays\VolumeDisplay\VolumeDisplayViewModel.cs" />
<Compile Include="ViewModels\ProfileEditorViewModel.cs" />
<Compile Include="ViewModels\Profiles\ProfileEditorViewModel.cs" />
<Compile Include="ViewModels\ShellViewModel.cs" />
<Compile Include="ViewModels\SystemTrayViewModel.cs" />
<Compile Include="ViewModels\WelcomeViewModel.cs" />
@ -438,15 +513,9 @@
<Compile Include="Views\Flyouts\FlyoutSettingsView.xaml.cs">
<DependentUpon>FlyoutSettingsView.xaml</DependentUpon>
</Compile>
<Compile Include="Modules\Effects\Debug\DebugEffectView.xaml.cs">
<DependentUpon>DebugEffectView.xaml</DependentUpon>
</Compile>
<Compile Include="Modules\Effects\AudioVisualizer\AudioVisualizerView.xaml.cs">
<DependentUpon>AudioVisualizerView.xaml</DependentUpon>
</Compile>
<Compile Include="Modules\Effects\TypeHole\TypeHoleView.xaml.cs">
<DependentUpon>TypeHoleView.xaml</DependentUpon>
</Compile>
<Compile Include="Modules\Effects\TypeWave\TypeWaveView.xaml.cs">
<DependentUpon>TypeWaveView.xaml</DependentUpon>
</Compile>
@ -465,22 +534,34 @@
<Compile Include="Modules\Games\Witcher3\Witcher3View.xaml.cs">
<DependentUpon>Witcher3View.xaml</DependentUpon>
</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>
</Compile>
<Compile Include="Views\LayerEditor\LayerDynamicPropertiesView.xaml.cs">
<Compile Include="Views\Profiles\LayerDynamicPropertiesView.xaml.cs">
<DependentUpon>LayerDynamicPropertiesView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\LayerEditor\LayerEditorView.xaml.cs">
<Compile Include="Views\Profiles\LayerEditorView.xaml.cs">
<DependentUpon>LayerEditorView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Profiles\Properties\MousePropertiesView.xaml.cs">
<DependentUpon>MousePropertiesView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\OverlaysView.xaml.cs">
<DependentUpon>OverlaysView.xaml</DependentUpon>
</Compile>
<Compile Include="Modules\Overlays\VolumeDisplay\VolumeDisplayView.xaml.cs">
<DependentUpon>VolumeDisplayView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ProfileEditorView.xaml.cs">
<Compile Include="Views\Profiles\ProfileEditorView.xaml.cs">
<DependentUpon>ProfileEditorView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ShellView.xaml.cs">
@ -510,6 +591,10 @@
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>TypeWave.Designer.cs</LastGenOutput>
</None>
<None Include="Modules\Effects\WindowsProfile\WindowsProfile.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>WindowsProfile.Designer.cs</LastGenOutput>
</None>
<None Include="Modules\Games\CounterStrike\CounterStrike.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>CounterStrike.Designer.cs</LastGenOutput>
@ -526,6 +611,10 @@
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>TheDivision.Designer.cs</LastGenOutput>
</None>
<None Include="Modules\Games\Overwatch\Overwatch.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Overwatch.Designer.cs</LastGenOutput>
</None>
<None Include="Modules\Games\Witcher3\Witcher3.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Witcher3.Designer.cs</LastGenOutput>
@ -540,7 +629,9 @@
<None Include="NLog.xsd">
<SubType>Designer</SubType>
</None>
<None Include="packages.config" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
<AppDesigner Include="Properties\" />
<Resource Include="Resources\bow.png" />
<Content Include="logo.ico">
@ -550,15 +641,23 @@
<Resource Include="Resources\logo-disabled.ico" />
<Resource Include="Resources\Dota2\dotaGamestateConfiguration.txt" />
<Resource Include="Resources\Entypo.ttf" />
<EmbeddedResource Include="Resources\Keyboards\default-profiles.zip" />
<None Include="Resources\LogitechLED.dll" />
<None Include="Resources\folder.png" />
<Resource Include="Resources\Keyboards\k65.png" />
<Resource Include="Resources\Keyboards\k70.png" />
<Resource Include="Resources\Keyboards\k95.png" />
<Resource Include="Resources\Keyboards\strafe.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\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\artemis.txt" />
<None Include="Settings\Offsets.settings">
@ -578,6 +677,14 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</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">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -586,10 +693,14 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</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>
<Generator>MSBuild:Compile</Generator>
</Page>
</Resource>
<Page Include="Styles\ColorBox.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -598,18 +709,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Modules\Effects\Debug\DebugEffectView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Modules\Effects\AudioVisualizer\AudioVisualizerView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Modules\Effects\TypeHole\TypeHoleView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Modules\Effects\TypeWave\TypeWaveView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -638,18 +741,34 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\LayerEditor\LayerConditionView.xaml">
<Page Include="Views\Profiles\Properties\FolderPropertiesView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\LayerEditor\LayerDynamicPropertiesView.xaml">
<Page Include="Views\Profiles\Properties\HeadsetPropertiesView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</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>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\Profiles\Properties\MousePropertiesView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\OverlaysView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -658,7 +777,7 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ProfileEditorView.xaml">
<Page Include="Views\Profiles\ProfileEditorView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
@ -695,12 +814,12 @@
</ItemGroup>
<ItemGroup />
<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">
<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>
</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>
<!-- 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.

View File

@ -1,27 +1,34 @@
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using Artemis.InjectionModules;
using Artemis.ViewModels;
using Autofac;
using Caliburn.Micro;
using Caliburn.Micro.Autofac;
using Ninject;
using Application = System.Windows.Application;
using MessageBox = System.Windows.Forms.MessageBox;
using MouseEventArgs = System.Windows.Input.MouseEventArgs;
namespace Artemis
{
public class ArtemisBootstrapper : AutofacBootstrapper<SystemTrayViewModel>
public class ArtemisBootstrapper : BootstrapperBase
{
private IKernel _kernel;
public ArtemisBootstrapper()
{
CheckDuplicateInstances();
Initialize();
BindSpecialValues();
}
public Mutex Mutex { get; set; }
private void BindSpecialValues()
{
MessageBinder.SpecialValues.Add("$scaledmousex", ctx =>
{
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)
builder.RegisterInstance<IWindowManager>(new WindowManager());
builder.RegisterType<SystemTrayViewModel>();
builder.RegisterType<ShellViewModel>();
protected override void OnExit(object sender, EventArgs e)
{
_kernel.Dispose();
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)
@ -81,8 +109,9 @@ namespace Artemis
private void CheckDuplicateInstances()
{
if (Process.GetProcesses().Count(p => p.ProcessName.Contains(Assembly.GetExecutingAssembly()
.FullName.Split(',')[0]) && !p.Modules[0].FileName.Contains("vshost")) < 2)
bool aIsNewInstance;
Mutex = new Mutex(true, "ArtemisMutex", out aIsNewInstance);
if (aIsNewInstance)
return;
MessageBox.Show("An instance of Artemis is already running (check your system tray).",

View File

@ -1,18 +1,28 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Xml.Serialization;
using Artemis.DeviceProviders;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Models.Profiles.Properties;
using Artemis.Properties;
using Artemis.Utilities;
using NLog;
namespace Artemis.DAL
{
public static class ProfileProvider
{
private static readonly string ProfileFolder =
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\profiles";
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static readonly string ProfileFolder = Environment
.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\profiles";
private static bool _installedDefaults;
/// <summary>
/// Get all profiles
@ -27,10 +37,16 @@ namespace Artemis.DAL
/// Get all profiles matching the provided game
/// </summary>
/// <param name="game">The game to match</param>
/// <param name="keyboard">The keyboard to match</param>
/// <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>
@ -40,44 +56,100 @@ namespace Artemis.DAL
/// <param name="prof">The profile to add or update</param>
public static void AddOrUpdate(ProfileModel prof)
{
if (!(prof.GameName?.Length > 1) || !(prof.KeyboardName?.Length > 1) || !(prof.Name?.Length > 1))
throw new ArgumentException("Profile is invalid. Name, GameName and KeyboardName are required");
if (prof == null)
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))
Directory.CreateDirectory(path);
var serializer = new XmlSerializer(typeof (ProfileModel));
using (var file = new StreamWriter(path + $@"\{prof.Name}.xml"))
var serializer = new XmlSerializer(typeof(ProfileModel));
// 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()
{
CheckProfiles();
InstallDefaults();
var profiles = new List<ProfileModel>();
// Create the directory structure
var profilePaths = Directory.GetFiles(ProfileFolder, "*.xml", SearchOption.AllDirectories);
// 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)
{
using (var file = new StreamReader(path))
try
{
var prof = (ProfileModel) deserializer.Deserialize(file);
if (prof.GameName?.Length > 1 && prof.KeyboardName?.Length > 1 && prof.Name?.Length > 1)
profiles.Add(prof);
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)
profiles.Add(prof);
}
}
catch (InvalidOperationException e)
{
Logger.Error("Failed to load profile: {0} - {1}", path, e.InnerException.Message);
}
}
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()
{
// Create the directory structure
@ -85,7 +157,72 @@ namespace Artemis.DAL
return;
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,54 +1,68 @@
using System.Collections.Generic;
using System.Drawing;
using System.Windows;
using Size = System.Windows.Size;
namespace Artemis.KeyboardProviders
{
public abstract class KeyboardProvider
{
public string Name { get; set; }
public int Height { get; set; }
public int Width { get; set; }
public string CantEnableText { get; set; }
public List<KeyboardRegion> KeyboardRegions { get; set; }
public PreviewSettings PreviewSettings { get; set; }
public abstract bool CanEnable();
public abstract void Enable();
public abstract void Disable();
public abstract void DrawBitmap(Bitmap bitmap);
/// <summary>
/// Returns a bitmap matching the keyboard's dimensions
/// </summary>
/// <returns></returns>
public Bitmap KeyboardBitmap() => new Bitmap(Width, Height);
/// <summary>
/// Returns a bitmap matching the keyboard's dimensions using the provided scale
/// </summary>
/// <returns></returns>
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 struct PreviewSettings
{
public int Width { get; set; }
public int Height { get; set; }
public Thickness Margin { get; set; }
public Bitmap Image { get; set; }
public PreviewSettings(int width, int height, Thickness margin, Bitmap image)
{
Width = width;
Height = height;
Margin = margin;
Image = image;
}
}
using System;
using System.Drawing;
using System.Windows;
using Brush = System.Windows.Media.Brush;
using Size = System.Windows.Size;
namespace Artemis.DeviceProviders
{
public abstract class KeyboardProvider : DeviceProvider
{
protected KeyboardProvider()
{
Type = DeviceType.Keyboard;
}
public string Name { get; set; }
public string Slug { get; set; }
public int Height { get; set; }
public int Width { get; set; }
public string CantEnableText { get; set; }
public PreviewSettings PreviewSettings { get; set; }
public abstract bool CanEnable();
public abstract void Enable();
public abstract void DrawBitmap(Bitmap bitmap);
/// <summary>
/// Returns a bitmap matching the keyboard's dimensions
/// </summary>
/// <returns></returns>
public Bitmap KeyboardBitmap() => new Bitmap(Width, Height);
/// <summary>
/// Returns a bitmap matching the keyboard's dimensions using the provided scale
/// </summary>
/// <returns></returns>
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 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 int Width { get; set; }
public int Height { get; set; }
public Thickness Margin { get; set; }
public Bitmap Image { get; set; }
public PreviewSettings(int width, int height, Thickness margin, Bitmap image)
{
Width = width;
Height = height;
Margin = margin;
Image = image;
}
}
}

View File

@ -1,90 +1,98 @@
using System.Collections.Generic;
using System.Drawing;
using System.Threading;
using System.Windows;
using Artemis.KeyboardProviders.Logitech.Utilities;
using Artemis.Properties;
using Artemis.Utilities;
using Point = System.Drawing.Point;
namespace Artemis.KeyboardProviders.Logitech
{
internal class Orion : KeyboardProvider
{
public Orion()
{
Name = "Logitech G910 RGB";
CantEnableText = "Couldn't connect to your Logitech G910.\n" +
"Please check your cables and updating the Logitech Gaming Software\n" +
"A minimum version of 8.81.15 is required.\n\n" +
"If needed, you can select a different keyboard in Artemis under settings.";
Height = 6;
Width = 21;
PreviewSettings = new PreviewSettings(626, 175, new Thickness(0, -15, 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()
{
//if (DllManager.RestoreDll())
// RestoreDll();
int majorNum = 0, minorNum = 0, buildNum = 0;
LogitechGSDK.LogiLedInit();
LogitechGSDK.LogiLedGetSdkVersion(ref majorNum, ref minorNum, ref buildNum);
LogitechGSDK.LogiLedShutdown();
// Turn it into one long number...
var version = int.Parse($"{majorNum}{minorNum}{buildNum}");
CantEnableText = "Couldn't connect to your Logitech G910.\n" +
"Please check your cables and updating the Logitech Gaming Software\n" +
$"A minimum version of 8.81.15 is required (detected {majorNum}.{minorNum}.{buildNum}).\n\n" +
"If the detected version differs from the version LGS is reporting, reinstall LGS or see the FAQ.\n\n" +
"If needed, you can select a different keyboard in Artemis under settings.";
return version >= 88115;
}
private void RestoreDll()
{
MessageBox.Show(
"Artemis couldn't enable your Logitech keyboard, because the required files are not in place.\n\n" +
"This happens when you run The Division and shut down Artemis before shutting down The Division\n" +
"It can be fixed automatically by clicking OK, but to avoid this message in the future please\n" +
"shut down The Division before shutting down Artemis.\n\n" +
"Click OK to fix the issue and restart Artemis");
GeneralHelpers.RunAsAdministrator();
}
public override void Enable()
{
// Initialize the SDK
LogitechGSDK.LogiLedInit();
Thread.Sleep(200);
LogitechGSDK.LogiLedSaveCurrentLighting();
LogitechGSDK.LogiLedSetTargetDevice(LogitechGSDK.LOGI_DEVICETYPE_PERKEY_RGB);
// Disable keys we can't color
LogitechGSDK.LogiLedSetLighting(0, 0, 0);
}
public override void Disable()
{
// Shutdown the SDK
LogitechGSDK.LogiLedRestoreLighting();
LogitechGSDK.LogiLedShutdown();
}
public override void DrawBitmap(Bitmap bitmap)
{
LogitechGSDK.LogiLedSetLightingFromBitmap(OrionUtilities.BitmapToByteArray(bitmap));
}
}
using System.Drawing;
using System.Threading;
using System.Windows;
using Artemis.DeviceProviders.Logitech.Utilities;
using Artemis.Properties;
using Artemis.Utilities;
using Artemis.Utilities.LogitechDll;
using Microsoft.Win32;
namespace Artemis.DeviceProviders.Logitech
{
internal class Orion : KeyboardProvider
{
public Orion()
{
Name = "Logitech G910 RGB";
Slug = "logitech-g910";
CantEnableText = "Couldn't connect to your Logitech G910.\n" +
"Please check your cables and updating the Logitech Gaming Software\n" +
"A minimum version of 8.81.15 is required.\n\n" +
"If needed, you can select a different keyboard in Artemis under settings.";
Height = 6;
Width = 21;
PreviewSettings = new PreviewSettings(540, 154, new Thickness(25, -80, 0, 0), Resources.g910);
}
public override bool CanEnable()
{
//Check to see if VC++ 2012 x64 is installed.
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;
LogitechGSDK.LogiLedInit();
LogitechGSDK.LogiLedGetSdkVersion(ref majorNum, ref minorNum, ref buildNum);
LogitechGSDK.LogiLedShutdown();
// Turn it into one long number...
var version = int.Parse($"{majorNum}{minorNum}{buildNum}");
CantEnableText = "Couldn't connect to your Logitech G910.\n" +
"Please check your cables and updating the Logitech Gaming Software\n" +
$"A minimum version of 8.81.15 is required (detected {majorNum}.{minorNum}.{buildNum}).\n\n" +
"If the detected version differs from the version LGS is reporting, reinstall LGS or see the FAQ.\n\n" +
"If needed, you can select a different keyboard in Artemis under settings.";
return version >= 88115;
}
private void RestoreDll()
{
MessageBox.Show(
"Artemis couldn't enable your Logitech keyboard, because the required files are not in place.\n\n" +
"This happens when you run The Division and shut down Artemis before shutting down The Division\n" +
"It can be fixed automatically by clicking OK, but to avoid this message in the future please\n" +
"shut down The Division before shutting down Artemis.\n\n" +
"Click OK to fix the issue and restart Artemis");
GeneralHelpers.RunAsAdministrator();
}
public override void Enable()
{
// Initialize the SDK
LogitechGSDK.LogiLedInit();
Thread.Sleep(200);
LogitechGSDK.LogiLedSaveCurrentLighting();
LogitechGSDK.LogiLedSetTargetDevice(LogitechGSDK.LOGI_DEVICETYPE_PERKEY_RGB);
// Disable keys we can't color
LogitechGSDK.LogiLedSetLighting(0, 0, 0);
}
public override void Disable()
{
// Shutdown the SDK
LogitechGSDK.LogiLedRestoreLighting();
LogitechGSDK.LogiLedShutdown();
}
public override void DrawBitmap(Bitmap bitmap)
{
LogitechGSDK.LogiLedSetLightingFromBitmap(OrionUtilities.BitmapToByteArray(bitmap));
}
}
}

View File

@ -1,137 +1,137 @@
using System.Collections.Generic;
using System.Windows.Forms;
using Artemis.Utilities.Keyboard;
namespace Artemis.KeyboardProviders.Logitech.Utilities
{
public static class KeyMap
{
static KeyMap()
{
// There are several keyboard layouts
// TODO: Implemented more layouts and an option to select them
UsEnglishOrionKeys = new List<Key>
{
// Row 1
new Key(Keys.Escape, 0, 0),
new Key(Keys.F1, 1, 0),
new Key(Keys.F2, 2, 0),
new Key(Keys.F3, 3, 0),
new Key(Keys.F4, 4, 0),
new Key(Keys.F5, 5, 0),
new Key(Keys.F6, 6, 0),
new Key(Keys.F7, 7, 0),
new Key(Keys.F8, 8, 0),
new Key(Keys.F9, 9, 0),
new Key(Keys.F10, 10, 0),
new Key(Keys.F11, 11, 0),
new Key(Keys.F12, 12, 0),
new Key(Keys.PrintScreen, 13, 0),
new Key(Keys.Scroll, 14, 0),
new Key(Keys.Pause, 15, 0),
// Row 2
new Key(Keys.Oemtilde, 0, 1),
new Key(Keys.D1, 1, 1),
new Key(Keys.D2, 2, 1),
new Key(Keys.D3, 3, 1),
new Key(Keys.D4, 4, 1),
new Key(Keys.D5, 5, 1),
new Key(Keys.D6, 6, 1),
new Key(Keys.D7, 7, 1),
new Key(Keys.D8, 8, 1),
new Key(Keys.D9, 9, 1),
new Key(Keys.D0, 10, 1),
new Key(Keys.OemMinus, 11, 1),
new Key(Keys.Oemplus, 12, 1),
new Key(Keys.Back, 13, 1),
new Key(Keys.Insert, 14, 1),
new Key(Keys.Home, 15, 1),
new Key(Keys.PageUp, 16, 1),
new Key(Keys.NumLock, 17, 1),
new Key(Keys.Divide, 18, 1),
new Key(Keys.Multiply, 19, 1),
new Key(Keys.Subtract, 20, 1),
// Row 3
new Key(Keys.Tab, 0, 2),
new Key(Keys.Q, 1, 2),
new Key(Keys.W, 2, 2),
new Key(Keys.E, 3, 2),
new Key(Keys.R, 4, 2),
new Key(Keys.T, 5, 2),
new Key(Keys.Y, 6, 2),
new Key(Keys.U, 7, 2),
new Key(Keys.I, 8, 2),
new Key(Keys.O, 9, 2),
new Key(Keys.P, 10, 2),
new Key(Keys.OemOpenBrackets, 11, 2),
new Key(Keys.Oem6, 12, 2),
new Key(Keys.Delete, 14, 2),
new Key(Keys.End, 15, 2),
new Key(Keys.Next, 16, 2),
new Key(Keys.NumPad7, 17, 2),
new Key(Keys.NumPad8, 18, 2),
new Key(Keys.NumPad9, 19, 2),
new Key(Keys.Add, 20, 2),
// Row 4
new Key(Keys.Capital, 0, 3),
new Key(Keys.A, 1, 3),
new Key(Keys.S, 2, 3),
new Key(Keys.D, 3, 3),
new Key(Keys.F, 4, 3),
new Key(Keys.G, 5, 3),
new Key(Keys.H, 6, 3),
new Key(Keys.J, 7, 3),
new Key(Keys.K, 8, 3),
new Key(Keys.L, 9, 3),
new Key(Keys.Oem1, 10, 3),
new Key(Keys.Oem7, 11, 3),
new Key(Keys.Oem5, 12, 3),
new Key(Keys.Return, 13, 3),
new Key(Keys.NumPad4, 17, 3),
new Key(Keys.NumPad5, 18, 3),
new Key(Keys.NumPad6, 19, 3),
// Row 5
new Key(Keys.LShiftKey, 1, 4),
new Key(Keys.OemBackslash, 2, 4),
new Key(Keys.Z, 2, 4),
new Key(Keys.X, 3, 4),
new Key(Keys.C, 4, 4),
new Key(Keys.V, 5, 4),
new Key(Keys.B, 6, 4),
new Key(Keys.N, 7, 4),
new Key(Keys.M, 8, 4),
new Key(Keys.Oemcomma, 9, 4),
new Key(Keys.OemPeriod, 10, 4),
new Key(Keys.OemQuestion, 11, 4),
new Key(Keys.RShiftKey, 13, 4),
new Key(Keys.Up, 15, 4),
new Key(Keys.NumPad1, 17, 4),
new Key(Keys.NumPad2, 18, 4),
new Key(Keys.NumPad3, 19, 4),
// Both returns return "Return" (Yes...)
// new OrionKey(System.Windows.Forms.Keys.Return, 20, 4),
// Row 6
new Key(Keys.LControlKey, 0, 5),
new Key(Keys.LWin, 1, 5),
new Key(Keys.LMenu, 2, 5),
new Key(Keys.Space, 5, 5),
new Key(Keys.RMenu, 11, 5),
new Key(Keys.RWin, 12, 5),
new Key(Keys.Apps, 13, 5),
new Key(Keys.RControlKey, 14, 5),
new Key(Keys.Left, 15, 5),
new Key(Keys.Down, 16, 5),
new Key(Keys.Right, 17, 5),
new Key(Keys.NumPad0, 18, 5),
new Key(Keys.Decimal, 19, 5)
};
}
public static List<Key> UsEnglishOrionKeys { get; set; }
}
using System.Collections.Generic;
using System.Windows.Forms;
using Artemis.Utilities.Keyboard;
namespace Artemis.DeviceProviders.Logitech.Utilities
{
public static class KeyMap
{
static KeyMap()
{
// There are several keyboard layouts
// TODO: Implemented more layouts and an option to select them
UsEnglishOrionKeys = new List<Key>
{
// Row 1
new Key(Keys.Escape, 0, 0),
new Key(Keys.F1, 1, 0),
new Key(Keys.F2, 2, 0),
new Key(Keys.F3, 3, 0),
new Key(Keys.F4, 4, 0),
new Key(Keys.F5, 5, 0),
new Key(Keys.F6, 6, 0),
new Key(Keys.F7, 7, 0),
new Key(Keys.F8, 8, 0),
new Key(Keys.F9, 9, 0),
new Key(Keys.F10, 10, 0),
new Key(Keys.F11, 11, 0),
new Key(Keys.F12, 12, 0),
new Key(Keys.PrintScreen, 13, 0),
new Key(Keys.Scroll, 14, 0),
new Key(Keys.Pause, 15, 0),
// Row 2
new Key(Keys.Oemtilde, 0, 1),
new Key(Keys.D1, 1, 1),
new Key(Keys.D2, 2, 1),
new Key(Keys.D3, 3, 1),
new Key(Keys.D4, 4, 1),
new Key(Keys.D5, 5, 1),
new Key(Keys.D6, 6, 1),
new Key(Keys.D7, 7, 1),
new Key(Keys.D8, 8, 1),
new Key(Keys.D9, 9, 1),
new Key(Keys.D0, 10, 1),
new Key(Keys.OemMinus, 11, 1),
new Key(Keys.Oemplus, 12, 1),
new Key(Keys.Back, 13, 1),
new Key(Keys.Insert, 14, 1),
new Key(Keys.Home, 15, 1),
new Key(Keys.PageUp, 16, 1),
new Key(Keys.NumLock, 17, 1),
new Key(Keys.Divide, 18, 1),
new Key(Keys.Multiply, 19, 1),
new Key(Keys.Subtract, 20, 1),
// Row 3
new Key(Keys.Tab, 0, 2),
new Key(Keys.Q, 1, 2),
new Key(Keys.W, 2, 2),
new Key(Keys.E, 3, 2),
new Key(Keys.R, 4, 2),
new Key(Keys.T, 5, 2),
new Key(Keys.Y, 6, 2),
new Key(Keys.U, 7, 2),
new Key(Keys.I, 8, 2),
new Key(Keys.O, 9, 2),
new Key(Keys.P, 10, 2),
new Key(Keys.OemOpenBrackets, 11, 2),
new Key(Keys.Oem6, 12, 2),
new Key(Keys.Delete, 14, 2),
new Key(Keys.End, 15, 2),
new Key(Keys.Next, 16, 2),
new Key(Keys.NumPad7, 17, 2),
new Key(Keys.NumPad8, 18, 2),
new Key(Keys.NumPad9, 19, 2),
new Key(Keys.Add, 20, 2),
// Row 4
new Key(Keys.Capital, 0, 3),
new Key(Keys.A, 1, 3),
new Key(Keys.S, 2, 3),
new Key(Keys.D, 3, 3),
new Key(Keys.F, 4, 3),
new Key(Keys.G, 5, 3),
new Key(Keys.H, 6, 3),
new Key(Keys.J, 7, 3),
new Key(Keys.K, 8, 3),
new Key(Keys.L, 9, 3),
new Key(Keys.Oem1, 10, 3),
new Key(Keys.Oem7, 11, 3),
new Key(Keys.Oem5, 12, 3),
new Key(Keys.Return, 13, 3),
new Key(Keys.NumPad4, 17, 3),
new Key(Keys.NumPad5, 18, 3),
new Key(Keys.NumPad6, 19, 3),
// Row 5
new Key(Keys.LShiftKey, 1, 4),
new Key(Keys.OemBackslash, 2, 4),
new Key(Keys.Z, 2, 4),
new Key(Keys.X, 3, 4),
new Key(Keys.C, 4, 4),
new Key(Keys.V, 5, 4),
new Key(Keys.B, 6, 4),
new Key(Keys.N, 7, 4),
new Key(Keys.M, 8, 4),
new Key(Keys.Oemcomma, 9, 4),
new Key(Keys.OemPeriod, 10, 4),
new Key(Keys.OemQuestion, 11, 4),
new Key(Keys.RShiftKey, 13, 4),
new Key(Keys.Up, 15, 4),
new Key(Keys.NumPad1, 17, 4),
new Key(Keys.NumPad2, 18, 4),
new Key(Keys.NumPad3, 19, 4),
// Both returns return "Return" (Yes...)
// new OrionKey(System.Windows.Forms.Keys.Return, 20, 4),
// Row 6
new Key(Keys.LControlKey, 0, 5),
new Key(Keys.LWin, 1, 5),
new Key(Keys.LMenu, 2, 5),
new Key(Keys.Space, 5, 5),
new Key(Keys.RMenu, 11, 5),
new Key(Keys.RWin, 12, 5),
new Key(Keys.Apps, 13, 5),
new Key(Keys.RControlKey, 14, 5),
new Key(Keys.Left, 15, 5),
new Key(Keys.Down, 16, 5),
new Key(Keys.Right, 17, 5),
new Key(Keys.NumPad0, 18, 5),
new Key(Keys.Decimal, 19, 5)
};
}
public static List<Key> UsEnglishOrionKeys { get; set; }
}
}

View File

@ -1,111 +1,111 @@
namespace Artemis.KeyboardProviders.Logitech.Utilities
{
public enum KeyboardNames
{
ESC = 0x01,
F1 = 0x3b,
F2 = 0x3c,
F3 = 0x3d,
F4 = 0x3e,
F5 = 0x3f,
F6 = 0x40,
F7 = 0x41,
F8 = 0x42,
F9 = 0x43,
F10 = 0x44,
F11 = 0x57,
F12 = 0x58,
PRINT_SCREEN = 0x137,
SCROLL_LOCK = 0x46,
PAUSE_BREAK = 0x45,
TILDE = 0x29,
ONE = 0x02,
TWO = 0x03,
THREE = 0x04,
FOUR = 0x05,
FIVE = 0x06,
SIX = 0x07,
SEVEN = 0x08,
EIGHT = 0x09,
NINE = 0x0A,
ZERO = 0x0B,
MINUS = 0x0C,
EQUALS = 0x0D,
BACKSPACE = 0x0E,
INSERT = 0x152,
HOME = 0x147,
PAGE_UP = 0x149,
NUM_LOCK = 0x145,
NUM_SLASH = 0x135,
NUM_ASTERISK = 0x37,
NUM_MINUS = 0x4A,
TAB = 0x0F,
Q = 0x10,
W = 0x11,
E = 0x12,
R = 0x13,
T = 0x14,
Y = 0x15,
U = 0x16,
I = 0x17,
O = 0x18,
P = 0x19,
OPEN_BRACKET = 0x1A,
CLOSE_BRACKET = 0x1B,
BACKSLASH = 0x2B,
KEYBOARD_DELETE = 0x153,
END = 0x14F,
PAGE_DOWN = 0x151,
NUM_SEVEN = 0x47,
NUM_EIGHT = 0x48,
NUM_NINE = 0x49,
NUM_PLUS = 0x4E,
CAPS_LOCK = 0x3A,
A = 0x1E,
S = 0x1F,
D = 0x20,
F = 0x21,
G = 0x22,
H = 0x23,
J = 0x24,
K = 0x25,
L = 0x26,
SEMICOLON = 0x27,
APOSTROPHE = 0x28,
ENTER = 0x1C,
NUM_FOUR = 0x4B,
NUM_FIVE = 0x4C,
NUM_SIX = 0x4D,
LEFT_SHIFT = 0x2A,
Z = 0x2C,
X = 0x2D,
C = 0x2E,
V = 0x2F,
B = 0x30,
N = 0x31,
M = 0x32,
COMMA = 0x33,
PERIOD = 0x34,
FORWARD_SLASH = 0x35,
RIGHT_SHIFT = 0x36,
ARROW_UP = 0x148,
NUM_ONE = 0x4F,
NUM_TWO = 0x50,
NUM_THREE = 0x51,
NUM_ENTER = 0x11C,
LEFT_CONTROL = 0x1D,
LEFT_WINDOWS = 0x15B,
LEFT_ALT = 0x38,
SPACE = 0x39,
RIGHT_ALT = 0x138,
RIGHT_WINDOWS = 0x15C,
APPLICATION_SELECT = 0x15D,
RIGHT_CONTROL = 0x11D,
ARROW_LEFT = 0x14B,
ARROW_DOWN = 0x150,
ARROW_RIGHT = 0x14D,
NUM_ZERO = 0x52,
NUM_PERIOD = 0x53,
TEST = 0x1
}
namespace Artemis.DeviceProviders.Logitech.Utilities
{
public enum KeyboardNames
{
ESC = 0x01,
F1 = 0x3b,
F2 = 0x3c,
F3 = 0x3d,
F4 = 0x3e,
F5 = 0x3f,
F6 = 0x40,
F7 = 0x41,
F8 = 0x42,
F9 = 0x43,
F10 = 0x44,
F11 = 0x57,
F12 = 0x58,
PRINT_SCREEN = 0x137,
SCROLL_LOCK = 0x46,
PAUSE_BREAK = 0x45,
TILDE = 0x29,
ONE = 0x02,
TWO = 0x03,
THREE = 0x04,
FOUR = 0x05,
FIVE = 0x06,
SIX = 0x07,
SEVEN = 0x08,
EIGHT = 0x09,
NINE = 0x0A,
ZERO = 0x0B,
MINUS = 0x0C,
EQUALS = 0x0D,
BACKSPACE = 0x0E,
INSERT = 0x152,
HOME = 0x147,
PAGE_UP = 0x149,
NUM_LOCK = 0x145,
NUM_SLASH = 0x135,
NUM_ASTERISK = 0x37,
NUM_MINUS = 0x4A,
TAB = 0x0F,
Q = 0x10,
W = 0x11,
E = 0x12,
R = 0x13,
T = 0x14,
Y = 0x15,
U = 0x16,
I = 0x17,
O = 0x18,
P = 0x19,
OPEN_BRACKET = 0x1A,
CLOSE_BRACKET = 0x1B,
BACKSLASH = 0x2B,
KEYBOARD_DELETE = 0x153,
END = 0x14F,
PAGE_DOWN = 0x151,
NUM_SEVEN = 0x47,
NUM_EIGHT = 0x48,
NUM_NINE = 0x49,
NUM_PLUS = 0x4E,
CAPS_LOCK = 0x3A,
A = 0x1E,
S = 0x1F,
D = 0x20,
F = 0x21,
G = 0x22,
H = 0x23,
J = 0x24,
K = 0x25,
L = 0x26,
SEMICOLON = 0x27,
APOSTROPHE = 0x28,
ENTER = 0x1C,
NUM_FOUR = 0x4B,
NUM_FIVE = 0x4C,
NUM_SIX = 0x4D,
LEFT_SHIFT = 0x2A,
Z = 0x2C,
X = 0x2D,
C = 0x2E,
V = 0x2F,
B = 0x30,
N = 0x31,
M = 0x32,
COMMA = 0x33,
PERIOD = 0x34,
FORWARD_SLASH = 0x35,
RIGHT_SHIFT = 0x36,
ARROW_UP = 0x148,
NUM_ONE = 0x4F,
NUM_TWO = 0x50,
NUM_THREE = 0x51,
NUM_ENTER = 0x11C,
LEFT_CONTROL = 0x1D,
LEFT_WINDOWS = 0x15B,
LEFT_ALT = 0x38,
SPACE = 0x39,
RIGHT_ALT = 0x138,
RIGHT_WINDOWS = 0x15C,
APPLICATION_SELECT = 0x15D,
RIGHT_CONTROL = 0x11D,
ARROW_LEFT = 0x14B,
ARROW_DOWN = 0x150,
ARROW_RIGHT = 0x14D,
NUM_ZERO = 0x52,
NUM_PERIOD = 0x53,
TEST = 0x1
}
}

View File

@ -1,95 +1,95 @@
using System.Runtime.InteropServices;
// ReSharper disable InconsistentNaming
namespace Artemis.KeyboardProviders.Logitech.Utilities
{
public class LogitechGSDK
{
//LED SDK
private const int LOGI_DEVICETYPE_MONOCHROME_ORD = 0;
private const int LOGI_DEVICETYPE_RGB_ORD = 1;
private const int LOGI_DEVICETYPE_PERKEY_RGB_ORD = 2;
public const int LOGI_DEVICETYPE_MONOCHROME = 1 << LOGI_DEVICETYPE_MONOCHROME_ORD;
public const int LOGI_DEVICETYPE_RGB = 1 << LOGI_DEVICETYPE_RGB_ORD;
public const int LOGI_DEVICETYPE_PERKEY_RGB = 1 << LOGI_DEVICETYPE_PERKEY_RGB_ORD;
public const int LOGI_LED_BITMAP_WIDTH = 21;
public const int LOGI_LED_BITMAP_HEIGHT = 6;
public const int LOGI_LED_BITMAP_BYTES_PER_KEY = 4;
public const int LOGI_LED_BITMAP_SIZE =
LOGI_LED_BITMAP_WIDTH*LOGI_LED_BITMAP_HEIGHT*LOGI_LED_BITMAP_BYTES_PER_KEY;
public const int LOGI_LED_DURATION_INFINITE = 0;
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedInit();
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSetTargetDevice(int targetDevice);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedGetSdkVersion(ref int majorNum, ref int minorNum, ref int buildNum);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSaveCurrentLighting();
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSetLighting(int redPercentage, int greenPercentage, int bluePercentage);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedRestoreLighting();
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedFlashLighting(int redPercentage, int greenPercentage, int bluePercentage,
int milliSecondsDuration, int milliSecondsInterval);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedPulseLighting(int redPercentage, int greenPercentage, int bluePercentage,
int milliSecondsDuration, int milliSecondsInterval);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedStopEffects();
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSetLightingFromBitmap(byte[] bitmap);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSetLightingForKeyWithScanCode(int keyCode, int redPercentage,
int greenPercentage, int bluePercentage);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSetLightingForKeyWithHidCode(int keyCode, int redPercentage,
int greenPercentage, int bluePercentage);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSetLightingForKeyWithQuartzCode(int keyCode, int redPercentage,
int greenPercentage, int bluePercentage);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSetLightingForKeyWithKeyName(int keyCode, int redPercentage,
int greenPercentage, int bluePercentage);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSaveLightingForKey(KeyboardNames keyName);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedRestoreLightingForKey(KeyboardNames keyName);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedFlashSingleKey(KeyboardNames keyName, int redPercentage, int greenPercentage,
int bluePercentage, int msDuration, int msInterval);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedPulseSingleKey(KeyboardNames keyName, int startRedPercentage,
int startGreenPercentage, int startBluePercentage, int finishRedPercentage, int finishGreenPercentage,
int finishBluePercentage, int msDuration, bool isInfinite);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedStopEffectsOnKey(KeyboardNames keyName);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern void LogiLedShutdown();
}
using System.Runtime.InteropServices;
// ReSharper disable InconsistentNaming
namespace Artemis.DeviceProviders.Logitech.Utilities
{
public class LogitechGSDK
{
//LED SDK
private const int LOGI_DEVICETYPE_MONOCHROME_ORD = 0;
private const int LOGI_DEVICETYPE_RGB_ORD = 1;
private const int LOGI_DEVICETYPE_PERKEY_RGB_ORD = 2;
public const int LOGI_DEVICETYPE_MONOCHROME = 1 << LOGI_DEVICETYPE_MONOCHROME_ORD;
public const int LOGI_DEVICETYPE_RGB = 1 << LOGI_DEVICETYPE_RGB_ORD;
public const int LOGI_DEVICETYPE_PERKEY_RGB = 1 << LOGI_DEVICETYPE_PERKEY_RGB_ORD;
public const int LOGI_LED_BITMAP_WIDTH = 21;
public const int LOGI_LED_BITMAP_HEIGHT = 6;
public const int LOGI_LED_BITMAP_BYTES_PER_KEY = 4;
public const int LOGI_LED_BITMAP_SIZE =
LOGI_LED_BITMAP_WIDTH*LOGI_LED_BITMAP_HEIGHT*LOGI_LED_BITMAP_BYTES_PER_KEY;
public const int LOGI_LED_DURATION_INFINITE = 0;
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedInit();
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSetTargetDevice(int targetDevice);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedGetSdkVersion(ref int majorNum, ref int minorNum, ref int buildNum);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSaveCurrentLighting();
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSetLighting(int redPercentage, int greenPercentage, int bluePercentage);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedRestoreLighting();
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedFlashLighting(int redPercentage, int greenPercentage, int bluePercentage,
int milliSecondsDuration, int milliSecondsInterval);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedPulseLighting(int redPercentage, int greenPercentage, int bluePercentage,
int milliSecondsDuration, int milliSecondsInterval);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedStopEffects();
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSetLightingFromBitmap(byte[] bitmap);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSetLightingForKeyWithScanCode(int keyCode, int redPercentage,
int greenPercentage, int bluePercentage);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSetLightingForKeyWithHidCode(int keyCode, int redPercentage,
int greenPercentage, int bluePercentage);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSetLightingForKeyWithQuartzCode(int keyCode, int redPercentage,
int greenPercentage, int bluePercentage);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSetLightingForKeyWithKeyName(int keyCode, int redPercentage,
int greenPercentage, int bluePercentage);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedSaveLightingForKey(KeyboardNames keyName);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedRestoreLightingForKey(KeyboardNames keyName);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedFlashSingleKey(KeyboardNames keyName, int redPercentage, int greenPercentage,
int bluePercentage, int msDuration, int msInterval);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedPulseSingleKey(KeyboardNames keyName, int startRedPercentage,
int startGreenPercentage, int startBluePercentage, int finishRedPercentage, int finishGreenPercentage,
int finishBluePercentage, int msDuration, bool isInfinite);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern bool LogiLedStopEffectsOnKey(KeyboardNames keyName);
[DllImport("LogitechLedEnginesWrapper ", CallingConvention = CallingConvention.Cdecl)]
public static extern void LogiLedShutdown();
}
}

View File

@ -1,230 +1,230 @@
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace Artemis.KeyboardProviders.Logitech.Utilities
{
public static class OrionUtilities
{
public static KeyMapping[] Keymappings =
{
// First row
new KeyMapping(0, 0),
new KeyMapping(1, 1),
new KeyMapping(2, 1),
new KeyMapping(3, 2),
new KeyMapping(4, 3),
new KeyMapping(5, 4),
new KeyMapping(6, 5),
new KeyMapping(7, 6),
new KeyMapping(8, 7),
new KeyMapping(9, 8),
new KeyMapping(10, 9),
new KeyMapping(11, 9),
new KeyMapping(12, 10),
new KeyMapping(13, 11),
new KeyMapping(13, 12),
new KeyMapping(14, 13),
new KeyMapping(15, 14),
new KeyMapping(16, 15),
new KeyMapping(17, 16),
new KeyMapping(18, 17),
new KeyMapping(19, 18),
// Second row
new KeyMapping(21, 21),
new KeyMapping(22, 22),
new KeyMapping(23, 23),
new KeyMapping(24, 24),
new KeyMapping(25, 25),
new KeyMapping(26, 26),
new KeyMapping(27, 27),
new KeyMapping(28, 28),
new KeyMapping(29, 29),
new KeyMapping(30, 30),
new KeyMapping(31, 31),
new KeyMapping(32, 32),
new KeyMapping(33, 33),
new KeyMapping(34, 34),
new KeyMapping(35, 35),
new KeyMapping(36, 36),
new KeyMapping(37, 37),
new KeyMapping(38, 38),
new KeyMapping(39, 39),
new KeyMapping(40, 40),
new KeyMapping(41, 41),
// Third row
new KeyMapping(42, 42),
new KeyMapping(43, 43),
new KeyMapping(44, 44),
new KeyMapping(45, 45),
new KeyMapping(46, 46),
new KeyMapping(47, 46),
new KeyMapping(48, 47),
new KeyMapping(49, 48),
new KeyMapping(50, 49),
new KeyMapping(51, 50),
new KeyMapping(52, 51),
new KeyMapping(53, 52),
new KeyMapping(54, 53),
new KeyMapping(54, 54),
new KeyMapping(55, 55),
new KeyMapping(56, 56),
new KeyMapping(57, 57),
new KeyMapping(58, 58),
new KeyMapping(59, 59),
new KeyMapping(60, 60),
new KeyMapping(61, 61),
new KeyMapping(62, 62),
// Fourth row
new KeyMapping(63, 63),
new KeyMapping(64, 64),
new KeyMapping(65, 65),
new KeyMapping(66, 65),
new KeyMapping(67, 66),
new KeyMapping(68, 67),
new KeyMapping(69, 68),
new KeyMapping(70, 69),
new KeyMapping(71, 70),
new KeyMapping(72, 71),
new KeyMapping(73, 72),
new KeyMapping(74, 73),
new KeyMapping(75, 74),
new KeyMapping(76, 75),
new KeyMapping(76, 76),
new KeyMapping(78, 77),
new KeyMapping(79, 78),
new KeyMapping(79, 79),
new KeyMapping(80, 80),
new KeyMapping(81, 81),
new KeyMapping(82, 82),
// Fifth row
new KeyMapping(84, 84),
new KeyMapping(85, 85),
new KeyMapping(86, 86),
new KeyMapping(87, 87),
new KeyMapping(88, 88),
new KeyMapping(89, 89),
new KeyMapping(90, 90),
new KeyMapping(91, 91),
new KeyMapping(92, 92),
new KeyMapping(93, 93),
new KeyMapping(94, 94),
new KeyMapping(95, 95),
new KeyMapping(96, 96),
new KeyMapping(97, 97),
new KeyMapping(98, 98),
new KeyMapping(99, 99),
new KeyMapping(100, 100),
new KeyMapping(101, 101),
new KeyMapping(102, 102),
new KeyMapping(103, 103),
new KeyMapping(104, 104),
// Sixth row
new KeyMapping(105, 105),
new KeyMapping(106, 106),
new KeyMapping(107, 107),
new KeyMapping(108, 107),
new KeyMapping(109, 109),
new KeyMapping(110, 110),
new KeyMapping(111, 110),
new KeyMapping(112, 111),
new KeyMapping(113, 112),
new KeyMapping(114, 113),
new KeyMapping(115, 114),
new KeyMapping(116, 115),
new KeyMapping(115, 116), // ALTGR
new KeyMapping(116, 117),
new KeyMapping(117, 118),
new KeyMapping(118, 119),
new KeyMapping(119, 120),
new KeyMapping(120, 121),
new KeyMapping(121, 122),
new KeyMapping(122, 123),
new KeyMapping(124, 124)
};
public static byte[] BitmapToByteArray(Bitmap b, bool remap = true)
{
if (b.Width > 21 || b.Height > 6)
b = ResizeImage(b, 21, 6);
var rect = new Rectangle(0, 0, b.Width, b.Height);
var bitmapData = b.LockBits(rect, ImageLockMode.ReadWrite, b.PixelFormat);
var depth = Image.GetPixelFormatSize(b.PixelFormat);
var step = depth/8;
var pixels = new byte[21*6*step];
var iptr = bitmapData.Scan0;
// Copy data from pointer to array
Marshal.Copy(iptr, pixels, 0, pixels.Length);
if (!remap)
return pixels;
var remapped = new byte[pixels.Length];
// Every key is 4 bytes
for (var i = 0; i <= pixels.Length/4; i++)
{
var firstSByte = Keymappings[i].Source*4;
var firstTByte = Keymappings[i].Target*4;
for (var j = 0; j < 4; j++)
remapped[firstTByte + j] = pixels[firstSByte + j];
}
return remapped;
}
/// <summary>
/// Resize the image to the specified width and height.
/// </summary>
/// <param name="image">The image to resize.</param>
/// <param name="width">The width to resize to.</param>
/// <param name="height">The height to resize to.</param>
/// <returns>The resized image.</returns>
public static Bitmap ResizeImage(Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
public struct KeyMapping
{
public KeyMapping(int source, int target)
{
Source = source;
Target = target;
}
public int Source { get; set; }
public int Target { get; set; }
}
}
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace Artemis.DeviceProviders.Logitech.Utilities
{
public static class OrionUtilities
{
public static KeyMapping[] Keymappings =
{
// First row
new KeyMapping(0, 0),
new KeyMapping(1, 1),
new KeyMapping(2, 1),
new KeyMapping(3, 2),
new KeyMapping(4, 3),
new KeyMapping(5, 4),
new KeyMapping(6, 5),
new KeyMapping(7, 6),
new KeyMapping(8, 7),
new KeyMapping(9, 8),
new KeyMapping(10, 9),
new KeyMapping(11, 9),
new KeyMapping(12, 10),
new KeyMapping(13, 11),
new KeyMapping(13, 12),
new KeyMapping(14, 13),
new KeyMapping(15, 14),
new KeyMapping(16, 15),
new KeyMapping(17, 16),
new KeyMapping(18, 17),
new KeyMapping(19, 18),
// Second row
new KeyMapping(21, 21),
new KeyMapping(22, 22),
new KeyMapping(23, 23),
new KeyMapping(24, 24),
new KeyMapping(25, 25),
new KeyMapping(26, 26),
new KeyMapping(27, 27),
new KeyMapping(28, 28),
new KeyMapping(29, 29),
new KeyMapping(30, 30),
new KeyMapping(31, 31),
new KeyMapping(32, 32),
new KeyMapping(33, 33),
new KeyMapping(34, 34),
new KeyMapping(35, 35),
new KeyMapping(36, 36),
new KeyMapping(37, 37),
new KeyMapping(38, 38),
new KeyMapping(39, 39),
new KeyMapping(40, 40),
new KeyMapping(41, 41),
// Third row
new KeyMapping(42, 42),
new KeyMapping(43, 43),
new KeyMapping(44, 44),
new KeyMapping(45, 45),
new KeyMapping(46, 46),
new KeyMapping(47, 46),
new KeyMapping(48, 47),
new KeyMapping(49, 48),
new KeyMapping(50, 49),
new KeyMapping(51, 50),
new KeyMapping(52, 51),
new KeyMapping(53, 52),
new KeyMapping(54, 53),
new KeyMapping(54, 54),
new KeyMapping(55, 55),
new KeyMapping(56, 56),
new KeyMapping(57, 57),
new KeyMapping(58, 58),
new KeyMapping(59, 59),
new KeyMapping(60, 60),
new KeyMapping(61, 61),
new KeyMapping(62, 62),
// Fourth row
new KeyMapping(63, 63),
new KeyMapping(64, 64),
new KeyMapping(65, 65),
new KeyMapping(66, 65),
new KeyMapping(67, 66),
new KeyMapping(68, 67),
new KeyMapping(69, 68),
new KeyMapping(70, 69),
new KeyMapping(71, 70),
new KeyMapping(72, 71),
new KeyMapping(73, 72),
new KeyMapping(74, 73),
new KeyMapping(75, 74),
new KeyMapping(76, 75),
new KeyMapping(76, 76),
new KeyMapping(78, 77),
new KeyMapping(79, 78),
new KeyMapping(79, 79),
new KeyMapping(80, 80),
new KeyMapping(81, 81),
new KeyMapping(82, 82),
// Fifth row
new KeyMapping(84, 84),
new KeyMapping(85, 85),
new KeyMapping(86, 86),
new KeyMapping(87, 87),
new KeyMapping(88, 88),
new KeyMapping(89, 89),
new KeyMapping(90, 90),
new KeyMapping(91, 91),
new KeyMapping(92, 92),
new KeyMapping(93, 93),
new KeyMapping(94, 94),
new KeyMapping(95, 95),
new KeyMapping(96, 96),
new KeyMapping(97, 97),
new KeyMapping(98, 98),
new KeyMapping(99, 99),
new KeyMapping(100, 100),
new KeyMapping(101, 101),
new KeyMapping(102, 102),
new KeyMapping(103, 103),
new KeyMapping(104, 104),
// Sixth row
new KeyMapping(105, 105),
new KeyMapping(106, 106),
new KeyMapping(107, 107),
new KeyMapping(108, 107),
new KeyMapping(109, 109),
new KeyMapping(110, 110),
new KeyMapping(111, 110),
new KeyMapping(112, 111),
new KeyMapping(113, 112),
new KeyMapping(114, 113),
new KeyMapping(115, 114),
new KeyMapping(116, 115),
new KeyMapping(115, 116), // ALTGR
new KeyMapping(116, 117),
new KeyMapping(117, 118),
new KeyMapping(118, 119),
new KeyMapping(119, 120),
new KeyMapping(120, 121),
new KeyMapping(121, 122),
new KeyMapping(122, 123),
new KeyMapping(124, 124)
};
public static byte[] BitmapToByteArray(Bitmap b, bool remap = true)
{
if (b.Width > 21 || b.Height > 6)
b = ResizeImage(b, 21, 6);
var rect = new Rectangle(0, 0, b.Width, b.Height);
var bitmapData = b.LockBits(rect, ImageLockMode.ReadWrite, b.PixelFormat);
var depth = Image.GetPixelFormatSize(b.PixelFormat);
var step = depth/8;
var pixels = new byte[21*6*step];
var iptr = bitmapData.Scan0;
// Copy data from pointer to array
Marshal.Copy(iptr, pixels, 0, pixels.Length);
if (!remap)
return pixels;
var remapped = new byte[pixels.Length];
// Every key is 4 bytes
for (var i = 0; i <= pixels.Length/4; i++)
{
var firstSByte = Keymappings[i].Source*4;
var firstTByte = Keymappings[i].Target*4;
for (var j = 0; j < 4; j++)
remapped[firstTByte + j] = pixels[firstSByte + j];
}
return remapped;
}
/// <summary>
/// Resize the image to the specified width and height.
/// </summary>
/// <param name="image">The image to resize.</param>
/// <param name="width">The width to resize to.</param>
/// <param name="height">The height to resize to.</param>
/// <returns>The resized image.</returns>
public static Bitmap ResizeImage(Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
public struct KeyMapping
{
public KeyMapping(int source, int target)
{
Source = source;
Target = target;
}
public int Source { get; set; }
public int Target { get; set; }
}
}
}

View File

@ -1,53 +1,53 @@
using System.Drawing;
using Artemis.KeyboardProviders.Razer.Utilities;
using Corale.Colore.Core;
using Corale.Colore.Razer;
using Constants = Corale.Colore.Razer.Keyboard.Constants;
namespace Artemis.KeyboardProviders.Razer
{
public class BlackWidow : KeyboardProvider
{
public BlackWidow()
{
Name = "Razer BlackWidow Chroma";
CantEnableText = "Couldn't connect to your Razer BlackWidow Chroma.\n" +
"Please check your cables and try updating Razer Synapse.\n\n" +
"If needed, you can select a different keyboard in Artemis under settings.";
}
public override bool CanEnable()
{
if (!Chroma.IsSdkAvailable())
return false;
// Some people have Synapse installed, but not a Chroma keyboard, deal with this
var blackWidowFound = Chroma.Instance.Query(Devices.Blackwidow).Connected;
var blackWidowTeFound = Chroma.Instance.Query(Devices.BlackwidowTe).Connected;
return blackWidowFound || blackWidowTeFound;
}
public override void Enable()
{
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()
{
Chroma.Instance.Uninitialize();
}
public override void DrawBitmap(Bitmap bitmap)
{
var razerArray = RazerUtilities.BitmapColorArray(bitmap, Height, Width);
Chroma.Instance.Keyboard.SetCustom(razerArray);
}
}
using System.Drawing;
using System.Windows;
using Artemis.DeviceProviders.Razer.Utilities;
using Artemis.Properties;
using Corale.Colore.Core;
using Corale.Colore.Razer;
using Constants = Corale.Colore.Razer.Keyboard.Constants;
namespace Artemis.DeviceProviders.Razer
{
public class BlackWidow : KeyboardProvider
{
public BlackWidow()
{
Name = "Razer BlackWidow Chroma";
Slug = "razer-blackwidow-chroma";
CantEnableText = "Couldn't connect to your Razer BlackWidow Chroma.\n" +
"Please check your cables and try updating Razer Synapse.\n\n" +
"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()
{
if (!Chroma.IsSdkAvailable())
return false;
// Some people have Synapse installed, but not a Chroma keyboard, deal with this
var blackWidowFound = Chroma.Instance.Query(Devices.Blackwidow).Connected;
var blackWidowTeFound = Chroma.Instance.Query(Devices.BlackwidowTe).Connected;
return blackWidowFound || blackWidowTeFound;
}
public override void Enable()
{
Chroma.Instance.Initialize();
}
public override void Disable()
{
Chroma.Instance.Uninitialize();
}
public override void DrawBitmap(Bitmap bitmap)
{
var razerArray = RazerUtilities.BitmapColorArray(bitmap, Height, Width);
Chroma.Instance.Keyboard.SetCustom(razerArray);
}
}
}

View File

@ -1,22 +1,22 @@
using System.Drawing;
using Artemis.Utilities;
using Corale.Colore.Razer.Keyboard.Effects;
namespace Artemis.KeyboardProviders.Razer.Utilities
{
public static class RazerUtilities
{
public static Custom BitmapColorArray(Bitmap b, int height, int width)
{
var keyboardGrid = Custom.Create();
if (b.Width > width || b.Height > height)
b = ImageUtilities.ResizeImage(b, width, height);
for (var y = 0; y < b.Height; y++)
for (var x = 0; x < b.Width; x++)
keyboardGrid[y, x] = b.GetPixel(x, y);
return keyboardGrid;
}
}
using System.Drawing;
using Artemis.Utilities;
using Corale.Colore.Razer.Keyboard.Effects;
namespace Artemis.DeviceProviders.Razer.Utilities
{
public static class RazerUtilities
{
public static Custom BitmapColorArray(Bitmap b, int height, int width)
{
var keyboardGrid = Custom.Create();
if (b.Width > width || b.Height > height)
b = ImageUtilities.ResizeImage(b, width, height);
for (var y = 0; y < b.Height; y++)
for (var x = 0; x < b.Width; x++)
keyboardGrid[y, x] = b.GetPixel(x, y);
return keyboardGrid;
}
}
}

View File

@ -1,12 +1,16 @@
namespace Artemis.Events
using Artemis.DeviceProviders;
namespace Artemis.Events
{
public class ActiveKeyboardChanged
{
public ActiveKeyboardChanged(string activeKeyboard)
public ActiveKeyboardChanged(KeyboardProvider oldKeyboard, KeyboardProvider newKeyboard)
{
ActiveKeyboard = activeKeyboard;
OldKeyboard = oldKeyboard;
NewKeyboard = newKeyboard;
}
public string ActiveKeyboard { get; set; }
public KeyboardProvider OldKeyboard { get; set; }
public KeyboardProvider NewKeyboard { get; set; }
}
}

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.Controls;
using System.Windows.Interactivity;
@ -6,21 +7,19 @@ using System.Windows.Interactivity;
namespace Artemis.ItemBehaviours
{
/// <summary>
/// Steve Greatrex - http://stackoverflow.com/a/5118406/5015269
/// Chaitanya Kadamati - http://stackoverflow.com/a/33233162/5015269
/// </summary>
public class BindableSelectedItemBehavior : Behavior<TreeView>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged;
}
protected override void OnDetaching()
{
base.OnDetaching();
if (AssociatedObject != null)
AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged;
}
@ -38,49 +37,59 @@ namespace Artemis.ItemBehaviours
set { SetValue(SelectedItemProperty, value); }
}
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem",
typeof (object), typeof (BindableSelectedItemBehavior), new UIPropertyMetadata(null, OnSelectedItemChanged));
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(object), typeof(BindableSelectedItemBehavior),
new UIPropertyMetadata(null, OnSelectedItemChanged));
private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var item = ((BindableSelectedItemBehavior) sender).AssociatedObject
.ItemContainerGenerator.ContainerFromItem(e.NewValue) as TreeViewItem;
if (item != 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))
var behavior = sender as BindableSelectedItemBehavior;
var tree = behavior?.AssociatedObject;
if (tree == null)
return;
for (var i = 0; i < ic.Count; i++)
if (e.NewValue == null)
{
var tvi = icg.ContainerFromIndex(i) as TreeViewItem;
if (tvi == null)
continue;
ClearTreeViewItemsControlSelection(tvi.Items, tvi.ItemContainerGenerator);
tvi.IsSelected = false;
foreach (var item in tree.Items.OfType<TreeViewItem>())
item.SetValue(TreeViewItem.IsSelectedProperty, 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

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.Collections.Generic;
using System.Linq;
using System.Threading;
using Artemis.Events;
using Artemis.Models;
using Artemis.Modules.Effects.ProfilePreview;
using Artemis.Settings;
using Caliburn.Micro;
using NLog;
using LogManager = NLog.LogManager;
using Ninject.Extensions.Logging;
namespace Artemis.Managers
{
/// <summary>
/// Manages the effects
/// </summary>
public class EffectManager
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly DeviceManager _deviceManager;
private readonly IEventAggregator _events;
private readonly MainManager _mainManager;
private readonly ILogger _logger;
private EffectModel _activeEffect;
private bool _clearing;
public EffectManager(MainManager mainManager, IEventAggregator events)
public EffectManager(ILogger logger, IEventAggregator events, DeviceManager deviceManager)
{
Logger.Info("Intializing EffectManager");
_mainManager = mainManager;
_logger = logger;
_logger.Info("Intializing EffectManager");
_events = events;
_deviceManager = deviceManager;
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; }
/// <summary>
@ -75,134 +72,101 @@ namespace Artemis.Managers
/// <returns>Whether enabling was successful or not.</returns>
public EffectModel GetLastEffect()
{
Logger.Debug("Getting last effect: {0}", General.Default.LastEffect);
if (General.Default.LastEffect == null)
return null;
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;
_logger.Debug("Getting last effect: {0}", General.Default.LastEffect);
return General.Default.LastEffect == null
? null
: EffectModels.FirstOrDefault(e => e.Name == General.Default.LastEffect);
}
/// <summary>
/// Disables the current effect and changes it to the provided effect.
/// </summary>
/// <param name="effectModel"></param>
/// <param name="force">Changes the effect, even if it's already running (effectively restarting it)</param>
public void ChangeEffect(EffectModel effectModel, bool force = false)
/// <param name="effectModel">The effect to activate</param>
/// <param name="loopManager">Optionally pass the LoopManager to automatically start it, if it's not running.</param>
public void ChangeEffect(EffectModel effectModel, LoopManager loopManager = null)
{
if (effectModel == null)
throw new ArgumentNullException(nameof(effectModel));
if (effectModel is OverlayModel)
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
var gameModel = effectModel as GameModel;
if (gameModel != null)
if (!gameModel.Enabled)
{
_logger.Debug("Cancelling effect change, provided game not enabled");
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;
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
_mainManager.Start(effectModel);
}
private void ChangeEffectWithPause(EffectModel effectModel)
{
var tryCount = 0;
while (PauseEffect != null)
if (loopManager != null && !loopManager.Running)
{
Thread.Sleep(500);
tryCount++;
if (tryCount > 20)
throw new Exception("Couldn't change effect before the time expired");
_logger.Debug("Starting LoopManager for effect change");
loopManager.Start();
}
// Don't interrupt an ongoing effect change
if (PauseEffect != null)
{
Logger.Debug("Change effect with pause cancelled");
return;
}
Logger.Debug("Changing effect with pause: {0}", effectModel?.Name);
_logger.Debug("Changed active effect to: {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)
return;
// Non-game effects are stored as the new LastEffect.
General.Default.LastEffect = ActiveEffect.Name;
General.Default.LastEffect = ActiveEffect?.Name;
General.Default.Save();
}
/// <summary>
/// Clears the current effect
/// </summary>
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)
return;
_clearing = true;
Logger.Debug("Clearing active effect");
_mainManager.Pause();
_mainManager.PauseCallback += ClearEffectPauseCallback;
}
private void ClearEffectPauseCallback()
{
_mainManager.PauseCallback -= ClearEffectPauseCallback;
if (PauseEffect != null)
lock (ActiveEffect)
{
Logger.Debug("Cancelling clearing effect");
return;
ActiveEffect.Dispose();
ActiveEffect = null;
General.Default.LastEffect = null;
General.Default.Save();
}
ActiveEffect.Dispose();
ActiveEffect = null;
General.Default.LastEffect = null;
General.Default.Save();
_clearing = false;
Logger.Debug("Finishing clearing active effect");
_mainManager.Unpause();
_logger.Debug("Cleared active effect");
}
/// <summary>
@ -211,7 +175,7 @@ namespace Artemis.Managers
/// <param name="activeEffect"></param>
public void DisableGame(EffectModel activeEffect)
{
Logger.Debug("Disabling game: {0}", activeEffect?.Name);
_logger.Debug("Disabling game: {0}", activeEffect?.Name);
if (GetLastEffect() == null)
ClearEffect();
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.Linq;
using System.Threading;
using System.Timers;
using Artemis.Events;
using Artemis.Models;
using Artemis.Services;
using Artemis.Modules.Effects.ProfilePreview;
using Artemis.Utilities.GameState;
using Artemis.Utilities.Keyboard;
using Artemis.Utilities.LogitechDll;
using Artemis.ViewModels;
using Caliburn.Micro;
using NLog;
using LogManager = NLog.LogManager;
using Ninject;
using Ninject.Extensions.Logging;
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();
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly IEventAggregator _events;
private readonly ILogger _logger;
private readonly Timer _processTimer;
private readonly int _fps;
private bool _paused;
private bool _restarting;
public MainManager(IEventAggregator events, MetroDialogService dialogService)
public MainManager(IEventAggregator events, ILogger logger, LoopManager loopManager,
DeviceManager deviceManager, EffectManager effectManager, ProfileManager profileManager)
{
Logger.Info("Intializing MainManager");
_logger = logger;
LoopManager = loopManager;
DeviceManager = deviceManager;
EffectManager = effectManager;
ProfileManager = profileManager;
Events = events;
DialogService = dialogService;
_logger.Info("Intializing MainManager");
KeyboardManager = new KeyboardManager(this, Events);
EffectManager = new EffectManager(this, Events);
KeyboardHook = new KeyboardHook();
_events = events;
_fps = 25;
UpdateWorker = new BackgroundWorker {WorkerSupportsCancellation = true};
ProcessWorker = new BackgroundWorker {WorkerSupportsCancellation = true};
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();
_processTimer = new Timer(1000);
_processTimer.Elapsed += ScanProcesses;
_processTimer.Start();
ProgramEnabled = false;
Running = false;
// TODO: Dependency inject utilities?
KeyboardHook = new KeyboardHook();
// Create and start the web server
GameStateWebServer = new GameStateWebServer();
GameStateWebServer.Start();
@ -59,141 +58,44 @@ namespace Artemis.Managers
PipeServer = new PipeServer();
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 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 GameStateWebServer GameStateWebServer { get; set; }
public IEventAggregator Events { get; set; }
public MetroDialogService DialogService { get; set; }
public bool ProgramEnabled { get; private set; }
public bool Suspended { get; set; }
public bool Running { get; private set; }
public event PauseCallbackHandler PauseCallback;
/// <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)
public void Dispose()
{
Logger.Debug("Starting MainManager");
// Can't take control when not enabled
if (!ProgramEnabled || UpdateWorker.CancellationPending || UpdateWorker.IsBusy || _paused)
return false;
_logger.Debug("Shutting down MainManager");
// Do nothing if already running
if (Running)
return true;
// 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();
_processTimer.Stop();
_processTimer.Dispose();
LoopManager.Stop();
EffectManager.ActiveEffect.Dispose();
GameStateWebServer.Stop();
PipeServer.Stop();
}
public void Restart()
{
if (_restarting)
return;
Logger.Debug("Restarting MainManager");
if (!Running)
{
Start();
return;
}
_restarting = true;
Stop();
}
/// <summary>
/// Loads the last active effect and starts the program
/// </summary>
public void EnableProgram()
{
Logger.Debug("Enabling program");
_logger.Debug("Enabling program");
ProgramEnabled = true;
Start(EffectManager.GetLastEffect());
Events.PublishOnUIThread(new ToggleEnabled(ProgramEnabled));
LoopManager.Start();
_events.PublishOnUIThread(new ToggleEnabled(ProgramEnabled));
}
/// <summary>
@ -201,129 +103,52 @@ namespace Artemis.Managers
/// </summary>
public void DisableProgram()
{
Logger.Debug("Disabling program");
Stop();
_logger.Debug("Disabling program");
LoopManager.Stop();
ProgramEnabled = false;
Events.PublishOnUIThread(new ToggleEnabled(ProgramEnabled));
_events.PublishOnUIThread(new ToggleEnabled(ProgramEnabled));
}
#region Workers
private void UpdateWorker_DoWork(object sender, DoWorkEventArgs e)
/// <summary>
/// Manages active games by keeping an eye on their processes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ScanProcesses(object sender, ElapsedEventArgs e)
{
var sw = new Stopwatch();
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)
if (!ProgramEnabled)
return;
Logger.Error(e.Error, "Exception in the BackgroundWorker");
throw e.Error;
}
var runningProcesses = Process.GetProcesses();
private void ProcessWorker_DoWork(object sender, DoWorkEventArgs e)
{
while (!ProcessWorker.CancellationPending)
// If the currently active effect is a disabled game, get rid of it.
if (EffectManager.ActiveEffect != null)
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);
continue;
_logger.Info("Disabling game: {0}", activeGame.Name);
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.Collections.Generic;
using System.Drawing;
using System.Linq;
using Artemis.Managers;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Models
{
@ -9,24 +14,50 @@ namespace Artemis.Models
public delegate void SettingsUpdateHandler(EffectSettings settings);
public bool Initialized;
public MainManager MainManager;
public string Name;
protected EffectModel(MainManager mainManager)
protected EffectModel(MainManager mainManager, IDataModel dataModel)
{
MainManager = mainManager;
DataModel = dataModel;
}
// Used by profile system
public IDataModel DataModel { get; set; }
public ProfileModel Profile { get; set; }
public abstract void Dispose();
// Called on creation
public abstract void Enable();
// Called every iteration
// Called every frame
public abstract void 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.Models.Interfaces;
using Artemis.Models.Profiles;
namespace Artemis.Models
{
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;
}
@ -14,7 +14,5 @@ namespace Artemis.Models
public GameSettings Settings { get; set; }
public bool Enabled { 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 bool Enabled { get; set; }
public string LastProfile { get; set; }
}
}

View File

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

View File

@ -1,5 +1,6 @@
using System.Drawing;
using Artemis.Managers;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Models
{
@ -8,7 +9,7 @@ namespace Artemis.Models
private bool _enabled;
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)
{
if (Enabled == enabled)
return;
if (enabled)
Enable();
else
Dispose();
Enabled = enabled;
}
public abstract Bitmap GenerateBitmap(Bitmap bitmap);
public abstract void RenderOverlay(ref Bitmap keyboard, ref Brush mouse, ref Brush headset, bool renderMice,
bool renderHeadsets);
}
}

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 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))
return false;
@ -23,9 +23,13 @@ namespace Artemis.Models.Profiles
// Put the subject in a list, allowing Dynamic Linq to be used.
var subjectList = new List<T> {(T) subject};
var res = Type == "String"
? subjectList.Where($"{Field}.ToLower() {Operator} @0", Value.ToLower()).Any()
: subjectList.Where($"{Field} {Operator} {Value}").Any();
bool res;
if (Type == "String")
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;
}
}

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.Xml.Serialization;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles.Properties;
using Artemis.Utilities;
using Artemis.Utilities.Layers;
using Artemis.Utilities.ParentChild;
namespace Artemis.Models.Profiles
{
public class LayerModel : IChildItem<LayerModel>, IChildItem<ProfileModel>
{
[XmlIgnore] private readonly LayerDrawer _drawer;
[XmlIgnore] private bool _mustDraw;
public LayerModel()
{
UserProps = new LayerPropertiesModel();
CalcProps = new LayerPropertiesModel();
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 int Order { get; set; }
public LayerType LayerType { get; set; }
public bool Enabled { get; set; }
public int Order { get; set; }
public LayerPropertiesModel UserProps { get; set; }
public bool Expanded { get; set; }
public LayerPropertiesModel Properties { get; set; }
public ChildItemCollection<LayerModel, LayerModel> Children { get; }
public List<LayerConditionModel> LayerConditions { get; set; }
public List<LayerDynamicPropertiesModel> LayerProperties { get; set; }
[XmlIgnore]
public LayerPropertiesModel CalcProps { get; set; }
public ImageSource LayerImage => Drawer.DrawThumbnail(this);
[XmlIgnore]
public ImageSource LayerImage => _drawer.GetThumbnail();
public LayerModel Parent { get; internal set; }
[XmlIgnore]
public LayerModel ParentLayer { get; internal set; }
public ProfileModel Profile { get; internal set; }
[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.Keyboard)
_drawer.Draw(c, _mustDraw);
if (LayerType != LayerType.Keyboard && LayerType != LayerType.KeyboardGif)
return;
// 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)
_drawer.DrawGif(c);
_mustDraw = false;
GifImage = Drawer.DrawGif(c, (KeyboardPropertiesModel) Properties, appliedProperties, GifImage);
}
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 (!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)
layerModel.Update<T>(dataModel);
return;
if (!ConditionsMet<T>(dataModel))
return null; // Return null when not previewing and the conditions arent met
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
newOrder = selectedLayer.Order + 1;
appliedProperties = Properties.GetAppliedProperties(dataModel, true);
var target = Children.FirstOrDefault(l => l.Order == newOrder);
if (target == null)
return;
// TODO: Mouse/headset animations
target.Order = selectedLayer.Order;
selectedLayer.Order = newOrder;
if (LayerType != LayerType.Folder)
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);
for (var i = 0; i < Children.Count; 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
LayerModel IChildItem<LayerModel>.Parent
{
get { return ParentLayer; }
set { ParentLayer = value; }
get { return Parent; }
set { Parent = value; }
}
ProfileModel IChildItem<ProfileModel>.Parent
{
get { return ParentProfile; }
set { ParentProfile = value; }
get { return Profile; }
set { Profile = value; }
}
#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.Windows;
using System.Windows.Media;
using System.Xml.Serialization;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles.Properties;
using Artemis.Utilities;
using Artemis.Utilities.ParentChild;
using Brush = System.Windows.Media.Brush;
using Color = System.Windows.Media.Color;
using Point = System.Windows.Point;
using Size = System.Windows.Size;
namespace Artemis.Models.Profiles
{
@ -20,14 +26,17 @@ namespace Artemis.Models.Profiles
public ChildItemCollection<ProfileModel, LayerModel> Layers { get; }
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 DrawingVisual DrawingVisual { get; set; }
[XmlIgnore]
public DrawingVisual DrawingVisual { get; set; }
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);
}
@ -44,61 +53,12 @@ namespace Artemis.Models.Profiles
unchecked
{
var hashCode = Name?.GetHashCode() ?? 0;
hashCode = (hashCode*397) ^ (KeyboardName?.GetHashCode() ?? 0);
hashCode = (hashCode*397) ^ (KeyboardSlug?.GetHashCode() ?? 0);
hashCode = (hashCode*397) ^ (GameName?.GetHashCode() ?? 0);
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()
{
Layers.Sort(l => l.Order);
@ -106,29 +66,156 @@ namespace Artemis.Models.Profiles
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;
DrawingVisual.Dispatcher.Invoke(delegate
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
{
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 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
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<T>(gameDataModel, c, preview);
// Remove the clip
c.Pop();
if (!layerModel.ConditionsMet<T>(dataModel))
continue;
}
bitmap = ImageUtilities.DrawinVisualToBitmap(visual, keyboardRect);
});
return bitmap;
layers.Add(layerModel);
layers.AddRange(layerModel.GetRenderLayers<T>(dataModel, includeMice, includeHeadsets, ignoreConditions));
}
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.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Utilities.Keyboard;
using Kaliko.ImageLibrary;
using Kaliko.ImageLibrary.Filters;
namespace Artemis.Modules.Effects.AmbientLightning
{
@ -21,7 +19,7 @@ namespace Artemis.Modules.Effects.AmbientLightning
private KeyboardRectangle _topRect;
public AmbientLightningEffectModel(MainManager mainManager, AmbientLightningEffectSettings settings)
: base(mainManager)
: base(mainManager, null)
{
Name = "Ambient Lightning";
Settings = settings;
@ -49,9 +47,9 @@ namespace Artemis.Modules.Effects.AmbientLightning
_colors = new List<Color>();
_screenCapturer = new ScreenCapture();
_topRect = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0, 0, new List<Color>(),
LinearGradientMode.Horizontal) {Height = MainManager.KeyboardManager.ActiveKeyboard.Height*Scale/2};
_botRect = 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.DeviceManager.ActiveKeyboard.Height*Scale/2};
_botRect = new KeyboardRectangle(MainManager.DeviceManager.ActiveKeyboard, 0, 0, new List<Color>(),
LinearGradientMode.Horizontal);
Initialized = true;
@ -102,8 +100,8 @@ namespace Artemis.Modules.Effects.AmbientLightning
}
// Put the resulting colors in 6 rectangles, their size differs per keyboard
var rectWidth = MainManager.KeyboardManager.ActiveKeyboard.Width/3*Scale;
var rectHeight = MainManager.KeyboardManager.ActiveKeyboard.Height/2*Scale;
var rectWidth = MainManager.DeviceManager.ActiveKeyboard.Width/3*Scale;
var rectHeight = MainManager.DeviceManager.ActiveKeyboard.Height/2*Scale;
for (var row = 0; row < 2; row++)
{
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);
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);
return null;
}
}
}

View File

@ -5,25 +5,17 @@ using Caliburn.Micro;
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
MainManager = mainManager;
MainManager.Events.Subscribe(this);
DisplayName = "Ambient Lightning";
// Settings are loaded from file by class
EffectSettings = new AmbientLightningEffectSettings();
// Create effect model and add it to MainManager
EffectModel = new AmbientLightningEffectModel(mainManager, (AmbientLightningEffectSettings) EffectSettings);
events.Subscribe(this);
MainManager.EffectManager.EffectModels.Add(EffectModel);
}
public static string Name => "Ambient Lightning";
public void Handle(ActiveEffectChanged message)
{
NotifyOfPropertyChange(() => EffectEnabled);

View File

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

View File

@ -5,11 +5,13 @@ using System.Drawing.Drawing2D;
using System.Linq;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Modules.Effects.AudioVisualizer.Utilities;
using Artemis.Utilities;
using Artemis.Utilities.Keyboard;
using NAudio.CoreAudioApi;
using NAudio.Wave;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Modules.Effects.AudioVisualizer
{
@ -22,7 +24,7 @@ namespace Artemis.Modules.Effects.AudioVisualizer
private int _sensitivity;
private IWaveIn _waveIn;
public AudioVisualizerModel(MainManager mainManager, AudioVisualizerSettings settings) : base(mainManager)
public AudioVisualizerModel(MainManager mainManager, AudioVisualizerSettings settings) : base(mainManager, null)
{
Settings = settings;
Name = "Audiovisualizer";
@ -49,6 +51,8 @@ namespace Artemis.Modules.Effects.AudioVisualizer
_sampleAggregator.PerformFFT = false;
_sampleAggregator.FftCalculated -= FftCalculated;
if (_waveIn == null)
return;
_waveIn.StopRecording();
_waveIn.DataAvailable -= OnDataAvailable;
_waveIn = null;
@ -57,7 +61,7 @@ namespace Artemis.Modules.Effects.AudioVisualizer
public override void Enable()
{
Initialized = false;
Lines = MainManager.KeyboardManager.ActiveKeyboard.Width;
Lines = MainManager.DeviceManager.ActiveKeyboard.Width;
// TODO: Device selection
SelectedDeviceId = new MMDeviceEnumerator()
@ -69,7 +73,7 @@ namespace Artemis.Modules.Effects.AudioVisualizer
for (var i = 0; i < Lines; i++)
{
SoundRectangles.Add(new KeyboardRectangle(
MainManager.KeyboardManager.ActiveKeyboard,
MainManager.DeviceManager.ActiveKeyboard,
0, 0, new List<Color>
{
ColorHelpers.ToDrawingColor(Settings.TopColor),
@ -121,7 +125,7 @@ namespace Artemis.Modules.Effects.AudioVisualizer
// Apply Sensitivity setting
height = height*_sensitivity;
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)
SoundRectangles[i].Height = keyboardHeight;
else
@ -131,31 +135,12 @@ namespace Artemis.Modules.Effects.AudioVisualizer
SoundRectangles[i].Width = Scale;
if (_fromBottom)
SoundRectangles[i].Y = MainManager.KeyboardManager.ActiveKeyboard.Height*Scale -
SoundRectangles[i].Y = MainManager.DeviceManager.ActiveKeyboard.Height*Scale -
SoundRectangles[i].Height;
}
_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)
{
var buffer = e.Buffer;
@ -199,5 +184,33 @@ namespace Artemis.Modules.Effects.AudioVisualizer
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="*" />
</Grid.RowDefinitions>
@ -80,38 +79,28 @@
Grid.Row="4" Grid.Column="1" HorizontalAlignment="Right" OnLabel="Yes"
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 -->
<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">
Volume sensitivity multiplier
</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"
Value="{Binding Path=EffectSettings.Sensitivity, Mode=TwoWay}" Minimum="1" Maximum="10"
SmallChange="1" IsSnapToTickEnabled="True" />
<!-- 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">
Bar fade-out speed
</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"
Value="{Binding Path=EffectSettings.FadeSpeed, Mode=TwoWay}" Minimum="1" Maximum="3"
SmallChange="1" IsSnapToTickEnabled="True" />
<!-- 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"
Style="{DynamicResource SquareButtonStyle}" />
<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
{
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
MainManager = mainManager;
MainManager.Events.Subscribe(this);
DisplayName = "Audio Visualization";
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);
EffectSettings = ((AudioVisualizerModel) EffectModel).Settings;
}
public static string Name => "Audio Visualizer";
public void Handle(ActiveEffectChanged message)
{
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.Models;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Modules.Effects.ProfilePreview
{
public class ProfilePreviewModel : EffectModel
{
private readonly ProfilePreviewDataModel _previewDataModel;
public ProfilePreviewModel(MainManager mainManager) : base(mainManager)
public ProfilePreviewModel(MainManager mainManager) : base(mainManager, new ProfilePreviewDataModel())
{
Name = "Profile Preview";
_previewDataModel = new ProfilePreviewDataModel();
}
public ProfileModel SelectedProfile { get; set; }
public override void Dispose()
{
Initialized = false;
SelectedProfile = null;
}
public override void Enable()
@ -31,32 +28,38 @@ namespace Artemis.Modules.Effects.ProfilePreview
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)
return bitmap;
public override void Render(out Bitmap keyboard, out Brush mouse, out Brush headset, bool renderMice,
bool renderHeadsets)
{
keyboard = null;
mouse = null;
headset = null;
var keyboardRect = MainManager.KeyboardManager.ActiveKeyboard.KeyboardRectangle(4);
var image = SelectedProfile.GenerateBitmap<ProfilePreviewDataModel>(keyboardRect, _previewDataModel, true);
if (Profile == null || DataModel == null)
return;
// Draw on top of everything else
using (var g = Graphics.FromImage(bitmap))
g.DrawImage(image, 0, 0);
// Get all enabled layers who's conditions are met
var renderLayers = GetRenderLayers(renderMice, renderHeadsets);
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.Linq;
using System.Windows.Forms;
using Artemis.KeyboardProviders.Corsair;
using Artemis.KeyboardProviders.Logitech.Utilities;
using Artemis.DeviceProviders.Corsair;
using Artemis.DeviceProviders.Logitech.Utilities;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Utilities;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Modules.Effects.TypeWave
{
@ -16,7 +18,7 @@ namespace Artemis.Modules.Effects.TypeWave
private readonly List<Wave> _waves;
private Color _randomColor;
public TypeWaveModel(MainManager mainManager, TypeWaveSettings settings) : base(mainManager)
public TypeWaveModel(MainManager mainManager, TypeWaveSettings settings) : base(mainManager, null)
{
Name = "TypeWave";
_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);
using (var g = Graphics.FromImage(bitmap))
public override void Render(out Bitmap keyboard, out Brush mouse, out Brush headset, bool renderMice,
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.SmoothingMode = SmoothingMode.HighQuality;
@ -113,7 +125,7 @@ namespace Artemis.Modules.Effects.TypeWave
_waves[i].Size, _waves[i].Size);
Color fillColor;
if (MainManager.KeyboardManager.ActiveKeyboard is CorsairRGB)
if (MainManager.DeviceManager.ActiveKeyboard is CorsairRGB)
fillColor = Color.Black;
else
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);
}
}
return bitmap;
}
}

View File

@ -5,24 +5,18 @@ using Caliburn.Micro;
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
MainManager = mainManager;
MainManager.Events.Subscribe(this);
DisplayName = "Type Waves";
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);
EffectSettings = ((TypeWaveModel) EffectModel).Settings;
}
public static string Name => "Type Waves";
public void Handle(ActiveEffectChanged message)
{
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: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:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:cal="http://www.caliburnproject.org"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
mc:Ignorable="d"
d:DesignHeight="407.812" d:DesignWidth="671.484"
cal:Bind.AtDesignTime="True">
d:DesignHeight="476.986" d:DesignWidth="538.772">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid Margin="15, 5, 15, 5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="320" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<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">
<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="Creates holes in the keyboard's lightning as you press keys." />
Text="Allows you to create layers shown while not gaming" />
</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]" />
<Popup PlacementTarget="{Binding ElementName=EffectEnabled}"
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>
cal:Message.Attach="[Event Click] = [Action ToggleEffect]"
ToolTip="Note: You can't enable an effect when Artemis is disabled" />
</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>
</ScrollViewer>
</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;
}
}
[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">
<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>

View File

@ -2,7 +2,7 @@
namespace Artemis.Modules.Games.CounterStrike
{
public class CounterStrikeDataModel : IGameDataModel
public class CounterStrikeDataModel : IDataModel
{
public Provider provider { 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.Models;
using Artemis.Models.Profiles;
using Artemis.Utilities.GameState;
using Newtonsoft.Json;
using Ninject.Extensions.Logging;
namespace Artemis.Modules.Games.CounterStrike
{
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";
ProcessName = "csgo";
@ -17,6 +21,7 @@ namespace Artemis.Modules.Games.CounterStrike
Initialized = false;
}
public ILogger Logger { get; set; }
public int Scale { get; set; }
public override void Dispose()
@ -29,7 +34,6 @@ namespace Artemis.Modules.Games.CounterStrike
{
Initialized = false;
GameDataModel = new CounterStrikeDataModel();
MainManager.GameStateWebServer.GameDataReceived += HandleGameData;
Initialized = true;
@ -37,20 +41,7 @@ namespace Artemis.Modules.Games.CounterStrike
public override void Update()
{
if (Profile == null || GameDataModel == null)
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);
// TODO: Set up active weapon in the datamodel
}
public void HandleGameData(object sender, GameDataReceivedEventArgs e)
@ -62,7 +53,20 @@ namespace Artemis.Modules.Games.CounterStrike
return;
// 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()
{
Enabled = CounterStrike.Default.Enabled;
LastProfile = CounterStrike.Default.LastProfile;
GameDirectory = CounterStrike.Default.GameDirectory;
AmmoEnabled = CounterStrike.Default.AmmoEnabled;

View File

@ -3,25 +3,23 @@
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:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:cal="http://www.caliburnproject.org"
mc:Ignorable="d"
d:DesignHeight="476.986" d:DesignWidth="538.772">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid Margin="15, 5, 15, 5">
<Grid Margin="15,5,5,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="80" />
<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" HorizontalAlignment="Left">
<Label.Content>
@ -41,20 +39,20 @@
<StackPanel Grid.Row="1"
Grid.Column="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>
<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 PlaceConfigFile]" />
<Button x:Name="BrowseDirectory" Content="..." RenderTransformOrigin="-0.039,-0.944"
HorizontalAlignment="Right" Width="25"
Style="{DynamicResource SquareButtonStyle}" Height="25" />
Style="{DynamicResource SquareButtonStyle}" Height="26" Margin="0,-2,0,0" />
</Grid>
</StackPanel>
<!-- 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 -->
<StackPanel Grid.Column="0" Grid.Row="4" Orientation="Horizontal" VerticalAlignment="Bottom">

View File

@ -1,23 +1,38 @@
using System.IO;
using System.Windows.Forms;
using Artemis.InjectionFactories;
using Artemis.Managers;
using Artemis.Properties;
using Artemis.Utilities;
using Artemis.ViewModels.Abstract;
using Caliburn.Micro;
namespace Artemis.Modules.Games.CounterStrike
{
public class CounterStrikeViewModel : GameViewModel<CounterStrikeDataModel>
public sealed class CounterStrikeViewModel : GameViewModel
{
public CounterStrikeViewModel(MainManager mainManager)
: base(mainManager, new CounterStrikeModel(mainManager, new CounterStrikeSettings()))
public CounterStrikeViewModel(MainManager main, IEventAggregator events, IProfileEditorVmFactory pFactory)
: 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);
FindGameDir();
PlaceConfigFile();
}
public static string Name => "CS:GO";
public string Content => "Counter-Strike: GO Content";
public void FindGameDir()
{
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()
{
@ -26,7 +41,7 @@ namespace Artemis.Modules.Games.CounterStrike
if (result != DialogResult.OK)
return;
((CounterStrikeSettings) GameSettings).GameDirectory = dialog.SelectedPath;
((CounterStrikeSettings) GameSettings).GameDirectory = Path.GetDirectoryName(dialog.SelectedPath);
NotifyOfPropertyChange(() => GameSettings);
GameSettings.Save();
@ -37,22 +52,22 @@ namespace Artemis.Modules.Games.CounterStrike
{
if (((CounterStrikeSettings) GameSettings).GameDirectory == string.Empty)
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}}",
MainManager.GameStateWebServer.Port.ToString());
File.WriteAllText(
((CounterStrikeSettings) GameSettings).GameDirectory + "/csgo/cfg/gamestate_integration_artemis.cfg",
cfgFile);
File.WriteAllText(path + "/csgo/cfg/gamestate_integration_artemis.cfg", cfgFile);
return;
}
MainManager.DialogService.ShowErrorMessageBox("Please select a valid CS:GO directory\n\n" +
@"By default CS:GO is in \SteamApps\common\Counter-Strike Global Offensive");
DialogService.ShowErrorMessageBox("Please select a valid CS:GO directory\n\n" +
@"By default CS:GO is in \SteamApps\common\Counter-Strike Global Offensive");
((CounterStrikeSettings) GameSettings).GameDirectory = string.Empty;
NotifyOfPropertyChange(() => GameSettings);
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.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]

View File

@ -7,6 +7,9 @@
<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>

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

View File

@ -1,25 +1,16 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using Artemis.KeyboardProviders;
using System.Collections.Generic;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Utilities;
using Artemis.Models.Profiles;
using Artemis.Utilities.GameState;
using Artemis.Utilities.Keyboard;
using Newtonsoft.Json;
namespace Artemis.Modules.Games.Dota2
{
internal class Dota2Model : GameModel
{
private KeyboardRegion _abilityKeys;
private KeyboardRegion _keyPad;
private KeyboardRegion _topRow;
public Dota2Model(MainManager mainManager, Dota2Settings settings) : base(mainManager, settings)
public Dota2Model(MainManager mainManager, Dota2Settings settings)
: base(mainManager, settings, new Dota2DataModel())
{
Name = "Dota2";
ProcessName = "dota2";
@ -29,6 +20,7 @@ namespace Artemis.Modules.Games.Dota2
Scale = 4;
}
public int Scale { get; set; }
public new Dota2Settings Settings { get; set; }
public override void Dispose()
@ -40,278 +32,26 @@ namespace Artemis.Modules.Games.Dota2
public override void Enable()
{
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;
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()
{
if (D2Json?.map == null)
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;
UpdateDay();
}
private void UpdateDay()
{
if (D2Json?.map?.daytime == null)
var dataModel = DataModel as Dota2DataModel;
if (dataModel?.map?.daytime == null)
return;
if (D2Json.map.nightstalker_night)
{
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};
var timeLeft = 240 - dataModel.map.clock_time%240;
dataModel.map.dayCyclePercentage = (int) (100.00/240*timeLeft);
}
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)
{
var jsonString = e.Json.ToString();
@ -321,19 +61,12 @@ namespace Artemis.Modules.Games.Dota2
return;
// Parse the JSON
D2Json = JsonConvert.DeserializeObject<Dota2DataModel.Rootobject>(jsonString);
DataModel = JsonConvert.DeserializeObject<Dota2DataModel>(jsonString);
}
#region Variables
public Dota2DataModel.Rootobject D2Json { get; set; }
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
public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{
return Profile.GetRenderLayers<Dota2DataModel>(DataModel, renderMice, renderHeadsets);
}
}
}

View File

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

View File

@ -4,36 +4,27 @@
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"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
mc:Ignorable="d" d:DesignWidth="635" Height="515.691">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Margin="0,0,0,-19">
<Grid Margin="15, 5, 15, 5">
mc:Ignorable="d"
d:DesignHeight="476.986" d:DesignWidth="538.772">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Grid Margin="15,5,5,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<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="*" />
</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="Shows game states and events from Dota 2." />
Text="Shows verious game states and events on the keyboard." />
</Label.Content>
</Label>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
@ -45,130 +36,31 @@
</StackPanel>
</StackPanel>
<StackPanel Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2" Margin="0,0,1,0">
<Label FontSize="16" Content="Dota 2 Directory" FontFamily="Segoe UI Semibold" Foreground="#535353"
Width="130" HorizontalAlignment="Left" />
<Label FontSize="20" HorizontalAlignment="Left" Content="Dota 2 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 PlaceConfigFile]" />
<Button x:Name="BrowseDirectory" Content="..." RenderTransformOrigin="-0.039,-0.944"
HorizontalAlignment="Right" Width="25"
Style="{DynamicResource SquareButtonStyle}" Height="25" />
Style="{DynamicResource SquareButtonStyle}" Height="26" Margin="0,-2,0,0" />
</Grid>
</StackPanel>
<!-- Main Color -->
<TextBlock Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left" Width="114" VerticalAlignment="Center"
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" />
<!-- Profile editor -->
<ContentControl Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" x:Name="ProfileEditor" Margin="0,0,-20,0" />
<!-- Ability Ready Color -->
<TextBlock Grid.Row="3" Grid.Column="0" HorizontalAlignment="Left" Width="114" VerticalAlignment="Center"
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">
<!-- Buttons -->
<StackPanel Grid.Column="0" Grid.Row="4" 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,33 +1,41 @@
using System.IO;
using System.Windows.Forms;
using Artemis.InjectionFactories;
using Artemis.Managers;
using Artemis.Properties;
using Artemis.Utilities;
using Artemis.ViewModels.Abstract;
using Caliburn.Micro;
namespace Artemis.Modules.Games.Dota2
{
public class Dota2ViewModel : GameViewModel<Dota2DataModel>
public sealed class Dota2ViewModel : GameViewModel
{
public Dota2ViewModel(MainManager mainManager)
: base(mainManager, new Dota2Model(mainManager, new Dota2Settings()))
public Dota2ViewModel(MainManager main, IEventAggregator events, IProfileEditorVmFactory pFactory)
: base(main, new Dota2Model(main, new Dota2Settings()), events, pFactory)
{
DisplayName = "Dota 2";
MainManager.EffectManager.EffectModels.Add(GameModel);
FindGameDir();
PlaceConfigFile();
}
public BindableCollection<string> KeyboardLayouts => new BindableCollection<string>(new[]
public void FindGameDir()
{
"Default",
"MMO",
"WASD",
"League of Legends",
"Heros of Newearth",
"Smite"
});
var gameSettings = (Dota2Settings) 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;
public static string Name => "Dota 2";
public string Content => "Dota 2 Content";
var dir = GeneralHelpers.FindSteamGame(@"\dota 2 beta\game\bin\win32\dota2.exe");
// Remove subdirectories where they stuck the executable
dir = dir?.Substring(0, dir.Length - 15);
gameSettings.GameDirectory = dir ?? string.Empty;
gameSettings.Save();
}
public void BrowseDirectory()
{
@ -68,12 +76,11 @@ namespace Artemis.Modules.Games.Dota2
cfgFile);
}
return;
}
MainManager.DialogService.ShowErrorMessageBox("Please select a valid Dota 2 directory\n\n" +
@"By default Dota 2 is in \SteamApps\common\dota 2 beta");
DialogService.ShowErrorMessageBox("Please select a valid Dota 2 directory\n\n" +
@"By default Dota 2 is in \SteamApps\common\dota 2 beta");
((Dota2Settings) GameSettings).GameDirectory = string.Empty;
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