diff --git a/.gitignore b/.gitignore index 5115c12d8..0922ac1a4 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,7 @@ ipch/ *.opensdf *.sdf *.cachefile +*.VC.db # Visual Studio profiler *.psess @@ -189,3 +190,4 @@ FakesAssemblies/ # Visual Studio 6 workspace options file *.opt +*.opendb diff --git a/Artemis/Artemis.VC.db b/Artemis/Artemis.VC.db new file mode 100644 index 000000000..51c7aaef8 Binary files /dev/null and b/Artemis/Artemis.VC.db differ diff --git a/Artemis/Artemis.sln b/Artemis/Artemis.sln index cf6e97100..201149a73 100644 --- a/Artemis/Artemis.sln +++ b/Artemis/Artemis.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 14.0.24720.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}") = "LogiLed2Artemis", "LogiLed2Artemis\LogiLed2Artemis.vcxproj", "{D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}" +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 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.CD_ROM|Any CPU.ActiveCfg = Release|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.CD_ROM|Any CPU.Build.0 = Release|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.CD_ROM|x64.ActiveCfg = Release|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.CD_ROM|x64.Build.0 = Release|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.CD_ROM|x86.ActiveCfg = Release|Win32 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.CD_ROM|x86.Build.0 = Release|Win32 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.Debug|x64.ActiveCfg = Debug|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.Debug|x64.Build.0 = Debug|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.Debug|x86.ActiveCfg = Debug|Win32 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.Debug|x86.Build.0 = Debug|Win32 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.DVD-5|Any CPU.ActiveCfg = Release|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.DVD-5|Any CPU.Build.0 = Release|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.DVD-5|x64.ActiveCfg = Debug|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.DVD-5|x64.Build.0 = Debug|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.DVD-5|x86.ActiveCfg = Debug|Win32 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.DVD-5|x86.Build.0 = Debug|Win32 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.Release|Any CPU.ActiveCfg = Release|Win32 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.Release|x64.ActiveCfg = Release|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.Release|x64.Build.0 = Release|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.Release|x86.ActiveCfg = Release|Win32 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.Release|x86.Build.0 = Release|Win32 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.SingleImage|Any CPU.ActiveCfg = Release|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.SingleImage|Any CPU.Build.0 = Release|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.SingleImage|x64.ActiveCfg = Release|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.SingleImage|x64.Build.0 = Release|x64 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.SingleImage|x86.ActiveCfg = Release|Win32 + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C}.SingleImage|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Artemis/Artemis/App.xaml b/Artemis/Artemis/App.xaml index bae7d6958..7acc3be4c 100644 --- a/Artemis/Artemis/App.xaml +++ b/Artemis/Artemis/App.xaml @@ -17,8 +17,9 @@ + Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" /> + diff --git a/Artemis/Artemis/App.xaml.cs b/Artemis/Artemis/App.xaml.cs index 04e288836..f68067c70 100644 --- a/Artemis/Artemis/App.xaml.cs +++ b/Artemis/Artemis/App.xaml.cs @@ -1,60 +1,60 @@ -using System; -using System.Windows; -using System.Windows.Threading; -using Artemis.Utilities; -using WpfExceptionViewer; - -namespace Artemis -{ - /// - /// Interaction logic for App.xaml - /// - public partial class App : Application - { - public App() - { - if (!GeneralHelpers.IsRunAsAdministrator()) - GeneralHelpers.RunAsAdministrator(); - - InitializeComponent(); - } - - public bool DoHandle { get; set; } - - private void Application_Startup(object sender, StartupEventArgs e) - { - AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; - } - - private void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) - { - if (DoHandle) - { - GetArtemisExceptionViewer(e.Exception).ShowDialog(); - e.Handled = true; - } - else - { - GetArtemisExceptionViewer(e.Exception).ShowDialog(); - e.Handled = false; - } - } - - - private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) - { - var ex = e.ExceptionObject as Exception; - GetArtemisExceptionViewer(ex).ShowDialog(); - } - - private static ExceptionViewer GetArtemisExceptionViewer(Exception e) - { - return new ExceptionViewer("An unexpected error occurred in Artemis.", e) - { - Title = "Artemis - Exception :c", - Height = 400, - Width = 800 - }; - } - } +using System; +using System.Windows; +using System.Windows.Threading; +using Artemis.Utilities; +using WpfExceptionViewer; + +namespace Artemis +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + public App() + { + if (!GeneralHelpers.IsRunAsAdministrator()) + GeneralHelpers.RunAsAdministrator(); + + InitializeComponent(); + } + + public bool DoHandle { get; set; } + + private void Application_Startup(object sender, StartupEventArgs e) + { + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + } + + private void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) + { + if (DoHandle) + { + GetArtemisExceptionViewer(e.Exception).ShowDialog(); + e.Handled = true; + } + else + { + GetArtemisExceptionViewer(e.Exception).ShowDialog(); + e.Handled = false; + } + } + + + private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + var ex = e.ExceptionObject as Exception; + GetArtemisExceptionViewer(ex).ShowDialog(); + } + + private static ExceptionViewer GetArtemisExceptionViewer(Exception e) + { + return new ExceptionViewer("An unexpected error occurred in Artemis.", e) + { + Title = "Artemis - Exception :c", + Height = 400, + Width = 800 + }; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index 1ea60910f..a0da17063 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -136,6 +136,10 @@ ..\packages\Caliburn.Micro.2.0.2\lib\net45\Caliburn.Micro.Platform.dll True + + False + lib\ColorBox.dll + ..\packages\Colore.4.0.0\lib\net35\Corale.Colore.dll True @@ -145,7 +149,7 @@ True - ..\packages\Hardcodet.NotifyIcon.Wpf.1.0.5\lib\net451\Hardcodet.Wpf.TaskbarNotification.dll + ..\packages\Hardcodet.NotifyIcon.Wpf.1.0.8\lib\net451\Hardcodet.Wpf.TaskbarNotification.dll True @@ -168,11 +172,7 @@ True - ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll - True - - - ..\packages\Screna.0.1.3\lib\Screna.dll + ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll True @@ -188,8 +188,13 @@ True + + + ..\packages\System.Linq.Dynamic.1.0.6\lib\net40\System.Linq.Dynamic.dll + True + @@ -214,28 +219,28 @@ - - ..\packages\Extended.Wpf.Toolkit.2.6\lib\net40\Xceed.Wpf.AvalonDock.dll + + ..\packages\Extended.Wpf.Toolkit.2.7\lib\net40\Xceed.Wpf.AvalonDock.dll True - - ..\packages\Extended.Wpf.Toolkit.2.6\lib\net40\Xceed.Wpf.AvalonDock.Themes.Aero.dll + + ..\packages\Extended.Wpf.Toolkit.2.7\lib\net40\Xceed.Wpf.AvalonDock.Themes.Aero.dll True - - ..\packages\Extended.Wpf.Toolkit.2.6\lib\net40\Xceed.Wpf.AvalonDock.Themes.Metro.dll + + ..\packages\Extended.Wpf.Toolkit.2.7\lib\net40\Xceed.Wpf.AvalonDock.Themes.Metro.dll True - - ..\packages\Extended.Wpf.Toolkit.2.6\lib\net40\Xceed.Wpf.AvalonDock.Themes.VS2010.dll + + ..\packages\Extended.Wpf.Toolkit.2.7\lib\net40\Xceed.Wpf.AvalonDock.Themes.VS2010.dll True - - ..\packages\Extended.Wpf.Toolkit.2.6\lib\net40\Xceed.Wpf.DataGrid.dll + + ..\packages\Extended.Wpf.Toolkit.2.7\lib\net40\Xceed.Wpf.DataGrid.dll True - - ..\packages\Extended.Wpf.Toolkit.2.6\lib\net40\Xceed.Wpf.Toolkit.dll + + ..\packages\Extended.Wpf.Toolkit.2.7\lib\net40\Xceed.Wpf.Toolkit.dll True @@ -249,9 +254,12 @@ Code + + + @@ -269,6 +277,12 @@ + + + + + + @@ -298,6 +312,7 @@ True True + @@ -313,6 +328,7 @@ True True + True @@ -366,11 +382,13 @@ Offsets.settings + + @@ -380,9 +398,12 @@ + + + @@ -397,8 +418,12 @@ + + + + @@ -435,12 +460,24 @@ Witcher3View.xaml + + LayerConditionView.xaml + + + LayerDynamicPropertiesView.xaml + + + LayerEditorView.xaml + OverlaysView.xaml VolumeDisplayView.xaml + + ProfileEditorView.xaml + ShellView.xaml @@ -457,8 +494,8 @@ ResXFileCodeGenerator - Resources.Designer.cs Designer + Resources.Designer.cs SettingsSingleFileGenerator @@ -495,18 +532,24 @@ - - PreserveNewest + + + + + + + + + - SettingsSingleFileGenerator Offsets.Designer.cs @@ -532,6 +575,14 @@ MSBuild:Compile Designer + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -576,6 +627,18 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + MSBuild:Compile + Designer + Designer MSBuild:Compile @@ -584,6 +647,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/Artemis/Artemis/ArtemisBootstrapper.cs b/Artemis/Artemis/ArtemisBootstrapper.cs index f3892e34f..d9d09728f 100644 --- a/Artemis/Artemis/ArtemisBootstrapper.cs +++ b/Artemis/Artemis/ArtemisBootstrapper.cs @@ -1,50 +1,92 @@ -using System.Diagnostics; -using System.Linq; -using System.Reflection; -using System.Windows; -using System.Windows.Forms; -using Artemis.ViewModels; -using Autofac; -using Caliburn.Micro; -using Caliburn.Micro.Autofac; -using Application = System.Windows.Application; -using MessageBox = System.Windows.Forms.MessageBox; - -namespace Artemis -{ - public class ArtemisBootstrapper : AutofacBootstrapper - { - public ArtemisBootstrapper() - { - CheckDuplicateInstances(); - - Initialize(); - } - - protected override void ConfigureContainer(ContainerBuilder builder) - { - base.ConfigureContainer(builder); - - // create a window manager instance to be used by everyone asking for one (including Caliburn.Micro) - builder.RegisterInstance(new WindowManager()); - builder.RegisterType(); - builder.RegisterType(); - } - - protected override void OnStartup(object sender, StartupEventArgs e) - { - DisplayRootViewFor(); - } - - private void CheckDuplicateInstances() - { - if (Process.GetProcesses().Count(p => p.ProcessName.Contains(Assembly.GetExecutingAssembly() - .FullName.Split(',')[0]) && !p.Modules[0].FileName.Contains("vshost")) < 2) - return; - - MessageBox.Show("An instance of Artemis is already running (check your system tray).", - "Artemis (╯°□°)╯︵ ┻━┻", MessageBoxButtons.OK, MessageBoxIcon.Warning); - Application.Current.Shutdown(); - } - } +using System.Diagnostics; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Forms; +using Artemis.ViewModels; +using Autofac; +using Caliburn.Micro; +using Caliburn.Micro.Autofac; +using Application = System.Windows.Application; +using MessageBox = System.Windows.Forms.MessageBox; + +namespace Artemis +{ + public class ArtemisBootstrapper : AutofacBootstrapper + { + public ArtemisBootstrapper() + { + CheckDuplicateInstances(); + + Initialize(); + + MessageBinder.SpecialValues.Add("$scaledmousex", (ctx) => + { + var img = ctx.Source as Image; + var input = ctx.Source as IInputElement; + var e = ctx.EventArgs as System.Windows.Input.MouseEventArgs; + + // If there is an image control, get the scaled position + if (img != null && e != null) + { + Point position = e.GetPosition(img); + return (int)(img.Source.Width * (position.X / img.ActualWidth)); + } + + // If there is another type of of IInputControl get the non-scaled position - or do some processing to get a scaled position, whatever needs to happen + if (e != null && input != null) + return e.GetPosition(input).X; + + // Return 0 if no processing could be done + return 0; + }); + MessageBinder.SpecialValues.Add("$scaledmousey", (ctx) => + { + var img = ctx.Source as Image; + var input = ctx.Source as IInputElement; + var e = ctx.EventArgs as System.Windows.Input.MouseEventArgs; + + // If there is an image control, get the scaled position + if (img != null && e != null) + { + Point position = e.GetPosition(img); + return (int)(img.Source.Width * (position.Y / img.ActualWidth)); + } + + // If there is another type of of IInputControl get the non-scaled position - or do some processing to get a scaled position, whatever needs to happen + if (e != null && input != null) + return e.GetPosition(input).Y; + + // Return 0 if no processing could be done + return 0; + }); + } + + protected override void ConfigureContainer(ContainerBuilder builder) + { + base.ConfigureContainer(builder); + + // create a window manager instance to be used by everyone asking for one (including Caliburn.Micro) + builder.RegisterInstance(new WindowManager()); + builder.RegisterType(); + builder.RegisterType(); + } + + protected override void OnStartup(object sender, StartupEventArgs e) + { + DisplayRootViewFor(); + } + + private void CheckDuplicateInstances() + { + var processes = Process.GetProcesses(); + if (processes.Count(p => p.ProcessName == "Artemis") < 2) + return; + + MessageBox.Show("An instance of Artemis is already running (check your system tray).", + "Artemis (╯°□°)╯︵ ┻━┻", MessageBoxButtons.OK, MessageBoxIcon.Warning); + Application.Current.Shutdown(); + } + + } } \ No newline at end of file diff --git a/Artemis/Artemis/DAL/ProfileProvider.cs b/Artemis/Artemis/DAL/ProfileProvider.cs new file mode 100644 index 000000000..0324a344a --- /dev/null +++ b/Artemis/Artemis/DAL/ProfileProvider.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Xml.Serialization; +using Artemis.Models; +using Artemis.Models.Profiles; + +namespace Artemis.DAL +{ + public static class ProfileProvider + { + private static readonly string ProfileFolder = + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\profiles"; + + /// + /// Get all profiles + /// + /// All profiles + public static List GetAll() + { + return ReadProfiles(); + } + + /// + /// Get all profiles matching the provided game + /// + /// The game to match + /// All profiles matching the provided game + public static List GetAll(GameModel game) + { + return GetAll().Where(g => g.GameName.Equals(game.Name)).ToList(); + } + + /// + /// Adds or update the given profile. + /// Updates occur when a profile with the same name and game exist. + /// + /// The profile to add or update + 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"); + + var path = ProfileFolder + $@"\{prof.KeyboardName}\{prof.GameName}"; + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + + var serializer = new XmlSerializer(typeof (ProfileModel)); + using (var file = new StreamWriter(path + $@"\{prof.Name}.xml")) + { + serializer.Serialize(file, prof); + } + } + + private static List ReadProfiles() + { + CheckProfiles(); + var profiles = new List(); + + // 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)); + foreach (var path in profilePaths) + { + using (var file = new StreamReader(path)) + { + var prof = (ProfileModel) deserializer.Deserialize(file); + if (prof.GameName?.Length > 1 && prof.KeyboardName?.Length > 1 && prof.Name?.Length > 1) + profiles.Add(prof); + } + } + + return profiles; + } + + private static void CheckProfiles() + { + // Create the directory structure + if (Directory.Exists(ProfileFolder)) + return; + + Directory.CreateDirectory(ProfileFolder); + Debug.WriteLine("Place presets"); + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Events/ActiveEffectChanged.cs b/Artemis/Artemis/Events/ActiveEffectChanged.cs index a7a90c3e4..fc35c1723 100644 --- a/Artemis/Artemis/Events/ActiveEffectChanged.cs +++ b/Artemis/Artemis/Events/ActiveEffectChanged.cs @@ -1,12 +1,12 @@ -namespace Artemis.Events -{ - public class ActiveEffectChanged - { - public ActiveEffectChanged(string activeEffect) - { - ActiveEffect = activeEffect; - } - - public string ActiveEffect { get; set; } - } +namespace Artemis.Events +{ + public class ActiveEffectChanged + { + public ActiveEffectChanged(string activeEffect) + { + ActiveEffect = activeEffect; + } + + public string ActiveEffect { get; set; } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Events/ActiveKeyboardChanged.cs b/Artemis/Artemis/Events/ActiveKeyboardChanged.cs new file mode 100644 index 000000000..fb123dd86 --- /dev/null +++ b/Artemis/Artemis/Events/ActiveKeyboardChanged.cs @@ -0,0 +1,12 @@ +namespace Artemis.Events +{ + public class ActiveKeyboardChanged + { + public ActiveKeyboardChanged(string activeKeyboard) + { + ActiveKeyboard = activeKeyboard; + } + + public string ActiveKeyboard { get; set; } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Events/ChangeBitmap.cs b/Artemis/Artemis/Events/ChangeBitmap.cs index cdae57658..4f72e82b8 100644 --- a/Artemis/Artemis/Events/ChangeBitmap.cs +++ b/Artemis/Artemis/Events/ChangeBitmap.cs @@ -1,19 +1,19 @@ -using System.Drawing; - -namespace Artemis.Events -{ - public class ChangeBitmap - { - public ChangeBitmap(Bitmap bitmap) - { - Bitmap = bitmap; - } - - public Bitmap Bitmap { get; private set; } - - public void ChangeTextMessage(Bitmap bitmap) - { - Bitmap = bitmap; - } - } +using System.Drawing; + +namespace Artemis.Events +{ + public class ChangeBitmap + { + public ChangeBitmap(Bitmap bitmap) + { + Bitmap = bitmap; + } + + public Bitmap Bitmap { get; private set; } + + public void ChangeTextMessage(Bitmap bitmap) + { + Bitmap = bitmap; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Events/ToggleEnabled.cs b/Artemis/Artemis/Events/ToggleEnabled.cs index 00112d7f3..8f30aa40e 100644 --- a/Artemis/Artemis/Events/ToggleEnabled.cs +++ b/Artemis/Artemis/Events/ToggleEnabled.cs @@ -1,12 +1,12 @@ -namespace Artemis.Events -{ - public class ToggleEnabled - { - public ToggleEnabled(bool enabled) - { - Enabled = enabled; - } - - public bool Enabled { get; set; } - } +namespace Artemis.Events +{ + public class ToggleEnabled + { + public ToggleEnabled(bool enabled) + { + Enabled = enabled; + } + + public bool Enabled { get; set; } + } } \ No newline at end of file diff --git a/Artemis/Artemis/ItemBehaviours/BindableSelectedItemBehavior.cs b/Artemis/Artemis/ItemBehaviours/BindableSelectedItemBehavior.cs new file mode 100644 index 000000000..ffb3687ad --- /dev/null +++ b/Artemis/Artemis/ItemBehaviours/BindableSelectedItemBehavior.cs @@ -0,0 +1,88 @@ +using System.Collections; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Interactivity; + +namespace Artemis.ItemBehaviours +{ + /// + /// Steve Greatrex - http://stackoverflow.com/a/5118406/5015269 + /// + public class BindableSelectedItemBehavior : Behavior + { + protected override void OnAttached() + { + base.OnAttached(); + + AssociatedObject.SelectedItemChanged += OnTreeViewSelectedItemChanged; + } + + protected override void OnDetaching() + { + base.OnDetaching(); + + if (AssociatedObject != null) + AssociatedObject.SelectedItemChanged -= OnTreeViewSelectedItemChanged; + } + + private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e) + { + SelectedItem = e.NewValue; + } + + #region SelectedItem Property + + public object SelectedItem + { + get { return GetValue(SelectedItemProperty); } + set { SetValue(SelectedItemProperty, value); } + } + + 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); + } + + /// + /// Clears a TreeView's selected item recursively + /// Tom Wright - http://stackoverflow.com/a/1406116/5015269 + /// + /// + public static void ClearTreeViewSelection(TreeView tv) + { + if (tv != null) + ClearTreeViewItemsControlSelection(tv.Items, tv.ItemContainerGenerator); + } + + /// + /// Clears a TreeView's selected item recursively + /// Tom Wright - http://stackoverflow.com/a/1406116/5015269 + /// + /// + /// + private static void ClearTreeViewItemsControlSelection(ICollection ic, ItemContainerGenerator icg) + { + if ((ic == null) || (icg == null)) + return; + + for (var i = 0; i < ic.Count; i++) + { + var tvi = icg.ContainerFromIndex(i) as TreeViewItem; + if (tvi == null) + continue; + ClearTreeViewItemsControlSelection(tvi.Items, tvi.ItemContainerGenerator); + tvi.IsSelected = false; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/Corsair/CorsairRGB.cs b/Artemis/Artemis/KeyboardProviders/Corsair/CorsairRGB.cs index f064dc811..2802ebf11 100644 --- a/Artemis/Artemis/KeyboardProviders/Corsair/CorsairRGB.cs +++ b/Artemis/Artemis/KeyboardProviders/Corsair/CorsairRGB.cs @@ -1,20 +1,22 @@ 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.Headset; using CUE.NET.Devices.Keyboard; -using CUE.NET.Devices.Mouse; 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"; @@ -74,6 +76,7 @@ namespace Artemis.KeyboardProviders.Corsair 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))); @@ -81,6 +84,7 @@ namespace Artemis.KeyboardProviders.Corsair 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))); @@ -88,16 +92,18 @@ namespace Artemis.KeyboardProviders.Corsair 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))); - Width = 22; break; } } @@ -106,7 +112,7 @@ namespace Artemis.KeyboardProviders.Corsair { CueSDK.Reinitialize(); } - + /// /// Properly resizes any size bitmap to the keyboard by creating a rectangle whose size is dependent on the bitmap /// size. @@ -118,7 +124,7 @@ namespace Artemis.KeyboardProviders.Corsair using (var g = Graphics.FromImage(fixedBmp)) { g.Clear(Color.Black); - g.DrawImage(bitmap, 0,0); + g.DrawImage(bitmap, 0, 0); } var fixedImage = ImageUtilities.ResizeImage(fixedBmp, Width, Height); @@ -131,4 +137,4 @@ namespace Artemis.KeyboardProviders.Corsair _keyboard.Update(); } } -} +} \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/KeyboardProvider.cs b/Artemis/Artemis/KeyboardProviders/KeyboardProvider.cs index b2ed485ea..746163184 100644 --- a/Artemis/Artemis/KeyboardProviders/KeyboardProvider.cs +++ b/Artemis/Artemis/KeyboardProviders/KeyboardProvider.cs @@ -1,32 +1,54 @@ -using System.Collections.Generic; -using System.Drawing; - -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 KeyboardRegions { get; set; } - - public abstract bool CanEnable(); - public abstract void Enable(); - public abstract void Disable(); - public abstract void DrawBitmap(Bitmap bitmap); - - /// - /// Returns a bitmap matching the keyboard's dimensions - /// - /// - public Bitmap KeyboardBitmap() => new Bitmap(Width, Height); - - /// - /// Returns a bitmap matching the keyboard's dimensions using the provided scale - /// - /// - public Bitmap KeyboardBitmap(int scale) => new Bitmap(Width*scale, Height*scale); - } +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 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); + + /// + /// Returns a bitmap matching the keyboard's dimensions + /// + /// + public Bitmap KeyboardBitmap() => new Bitmap(Width, Height); + + /// + /// Returns a bitmap matching the keyboard's dimensions using the provided scale + /// + /// + public Bitmap KeyboardBitmap(int scale) => new Bitmap(Width*scale, Height*scale); + + public Rect KeyboardRectangle(int scale) => new Rect(new Size(Width*scale, Height*scale)); + } + + public 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; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/KeyboardRegion.cs b/Artemis/Artemis/KeyboardProviders/KeyboardRegion.cs index d4f3ed015..59f4565e6 100644 --- a/Artemis/Artemis/KeyboardProviders/KeyboardRegion.cs +++ b/Artemis/Artemis/KeyboardProviders/KeyboardRegion.cs @@ -1,20 +1,20 @@ -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); - } +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); + } } \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/Logitech/Orion.cs b/Artemis/Artemis/KeyboardProviders/Logitech/Orion.cs index b4fb74df9..2c5c356db 100644 --- a/Artemis/Artemis/KeyboardProviders/Logitech/Orion.cs +++ b/Artemis/Artemis/KeyboardProviders/Logitech/Orion.cs @@ -3,6 +3,7 @@ using System.Drawing; using System.Threading; using System.Windows; using Artemis.KeyboardProviders.Logitech.Utilities; +using Artemis.Properties; using Artemis.Utilities; using Artemis.Utilities.LogitechDll; using Point = System.Drawing.Point; @@ -16,10 +17,11 @@ namespace Artemis.KeyboardProviders.Logitech 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" + + "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 { new KeyboardRegion("TopRow", new Point(0, 0), new Point(18, 0)), @@ -40,6 +42,12 @@ namespace Artemis.KeyboardProviders.Logitech // 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; } diff --git a/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/KeyMap.cs b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/KeyMap.cs index 6c341892f..d3d6f687a 100644 --- a/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/KeyMap.cs +++ b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/KeyMap.cs @@ -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 - { - // 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 UsEnglishOrionKeys { get; set; } - } +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 + { + // 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 UsEnglishOrionKeys { get; set; } + } } \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/KeyboardNames.cs b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/KeyboardNames.cs index 32da4051d..e2efcd880 100644 --- a/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/KeyboardNames.cs +++ b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/KeyboardNames.cs @@ -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.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 + } } \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/LogitechGSDK.cs b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/LogitechGSDK.cs index b3e1bd9ed..f41748402 100644 --- a/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/LogitechGSDK.cs +++ b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/LogitechGSDK.cs @@ -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.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(); + } } \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/OrionUtilities.cs b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/OrionUtilities.cs index a9a1911d8..98f38c569 100644 --- a/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/OrionUtilities.cs +++ b/Artemis/Artemis/KeyboardProviders/Logitech/Utilities/OrionUtilities.cs @@ -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), +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(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; - } - - /// - /// Resize the image to the specified width and height. - /// - /// The image to resize. - /// The width to resize to. - /// The height to resize to. - /// The resized image. - 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; } - } - } + 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; + } + + /// + /// Resize the image to the specified width and height. + /// + /// The image to resize. + /// The width to resize to. + /// The height to resize to. + /// The resized image. + 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; } + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/ProviderHelper.cs b/Artemis/Artemis/KeyboardProviders/ProviderHelper.cs index 8e03f5aba..a28ef0f8b 100644 --- a/Artemis/Artemis/KeyboardProviders/ProviderHelper.cs +++ b/Artemis/Artemis/KeyboardProviders/ProviderHelper.cs @@ -1,20 +1,20 @@ -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 GetKeyboardProviders() - { - return new List - { - new CorsairRGB(), - new Orion(), - new BlackWidow() - }; - } - } +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 GetKeyboardProviders() + { + return new List + { + new CorsairRGB(), + new Orion(), + new BlackWidow() + }; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/Razer/BlackWidow.cs b/Artemis/Artemis/KeyboardProviders/Razer/BlackWidow.cs index fb9881738..908f83fdb 100644 --- a/Artemis/Artemis/KeyboardProviders/Razer/BlackWidow.cs +++ b/Artemis/Artemis/KeyboardProviders/Razer/BlackWidow.cs @@ -1,55 +1,53 @@ -using System; -using System.Drawing; -using Artemis.KeyboardProviders.Razer.Utilities; -using Corale.Colore.Core; -using Corale.Colore.Razer.Keyboard; -using ColoreColor = Corale.Colore.Core.Color; -using KeyboardCustom = Corale.Colore.Razer.Keyboard.Effects.Custom; - -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(Corale.Colore.Razer.Devices.Blackwidow).Connected; - var blackWidowTeFound = Chroma.Instance.Query(Corale.Colore.Razer.Devices.BlackwidowTe).Connected; - return (blackWidowFound || blackWidowTeFound); - } - - public override void Enable() - { - Chroma.Instance.Initialize(); - Height = Constants.MaxRows; - Width = Constants.MaxColumns; +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); - } - } + 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); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/KeyboardProviders/Razer/Utilities/RazerUtilities.cs b/Artemis/Artemis/KeyboardProviders/Razer/Utilities/RazerUtilities.cs index 07c7a17d7..fcb8cf5c0 100644 --- a/Artemis/Artemis/KeyboardProviders/Razer/Utilities/RazerUtilities.cs +++ b/Artemis/Artemis/KeyboardProviders/Razer/Utilities/RazerUtilities.cs @@ -1,24 +1,24 @@ -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -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 System.Drawing.Drawing2D; +using System.Drawing.Imaging; +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; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Managers/EffectManager.cs b/Artemis/Artemis/Managers/EffectManager.cs index 5ae38a048..f7b639406 100644 --- a/Artemis/Artemis/Managers/EffectManager.cs +++ b/Artemis/Artemis/Managers/EffectManager.cs @@ -14,6 +14,7 @@ namespace Artemis.Managers private readonly MainManager _mainManager; private bool _clearing; private EffectModel _pauseEffect; + private EffectModel _activeEffect; public EffectManager(MainManager mainManager, IEventAggregator events) { @@ -24,7 +25,16 @@ namespace Artemis.Managers } public List EffectModels { get; set; } - public EffectModel ActiveEffect { get; private set; } + + public EffectModel ActiveEffect + { + get { return _activeEffect; } + private set + { + _activeEffect = value; + _events.PublishOnUIThread(new ActiveEffectChanged(value?.Name)); + } + } public IEnumerable EnabledOverlays { @@ -101,7 +111,7 @@ namespace Artemis.Managers ActiveEffect.Enable(); // Let the ViewModels know - _events.PublishOnUIThread(new ActiveEffectChanged(ActiveEffect.Name)); + //_events.PublishOnUIThread(new ActiveEffectChanged(ActiveEffect.Name)); _mainManager.Unpause(); _pauseEffect = null; @@ -143,7 +153,7 @@ namespace Artemis.Managers General.Default.LastEffect = null; General.Default.Save(); - _events.PublishOnUIThread(new ActiveEffectChanged("")); + //_events.PublishOnUIThread(new ActiveEffectChanged("")); _clearing = false; _mainManager.Unpause(); diff --git a/Artemis/Artemis/Managers/KeyboardManager.cs b/Artemis/Artemis/Managers/KeyboardManager.cs index f6e7c9d1f..cc0463332 100644 --- a/Artemis/Artemis/Managers/KeyboardManager.cs +++ b/Artemis/Artemis/Managers/KeyboardManager.cs @@ -1,23 +1,37 @@ using System.Collections.Generic; using System.Linq; -using System.Windows.Forms; +using Artemis.Events; using Artemis.KeyboardProviders; using Artemis.Settings; +using Caliburn.Micro; namespace Artemis.Managers { public class KeyboardManager { + private readonly IEventAggregator _events; private readonly MainManager _mainManager; + private KeyboardProvider _activeKeyboard; - public KeyboardManager(MainManager mainManager) + public KeyboardManager(MainManager mainManager, IEventAggregator events) { _mainManager = mainManager; + _events = events; KeyboardProviders = ProviderHelper.GetKeyboardProviders(); } public List KeyboardProviders { get; set; } - public KeyboardProvider ActiveKeyboard { get; set; } + + public KeyboardProvider ActiveKeyboard + { + get { return _activeKeyboard; } + set + { + _activeKeyboard = value; + // Let the ViewModels know + _events.PublishOnUIThread(new ActiveKeyboardChanged(value?.Name)); + } + } /// /// Enables the last keyboard according to the settings file diff --git a/Artemis/Artemis/Managers/MainManager.cs b/Artemis/Artemis/Managers/MainManager.cs index f4f6a4859..381795d2e 100644 --- a/Artemis/Artemis/Managers/MainManager.cs +++ b/Artemis/Artemis/Managers/MainManager.cs @@ -2,7 +2,6 @@ using System.Diagnostics; using System.Linq; using System.Threading; -using System.Windows.Forms; using Artemis.Events; using Artemis.Models; using Artemis.Services; @@ -26,7 +25,7 @@ namespace Artemis.Managers Events = events; DialogService = dialogService; - KeyboardManager = new KeyboardManager(this); + KeyboardManager = new KeyboardManager(this, Events); EffectManager = new EffectManager(this, Events); KeyboardHook = new KeyboardHook(); @@ -51,8 +50,8 @@ namespace Artemis.Managers GameStateWebServer.Start(); // Start the named pipe - //PipeServer = new PipeServer(); - //PipeServer.Start("artemis"); + PipeServer = new PipeServer(); + PipeServer.Start("artemis"); } public PipeServer PipeServer { get; set; } diff --git a/Artemis/Artemis/Models/EffectSettings.cs b/Artemis/Artemis/Models/EffectSettings.cs index 5595ed92e..98996df54 100644 --- a/Artemis/Artemis/Models/EffectSettings.cs +++ b/Artemis/Artemis/Models/EffectSettings.cs @@ -1,20 +1,20 @@ -namespace Artemis.Models -{ - public abstract class EffectSettings - { - /// - /// Loads the settings from the settings file - /// - public abstract void Load(); - - /// - /// Saves the settings to the settings file - /// - public abstract void Save(); - - /// - /// Returns the settings to their default value - /// - public abstract void ToDefault(); - } +namespace Artemis.Models +{ + public abstract class EffectSettings + { + /// + /// Loads the settings from the settings file + /// + public abstract void Load(); + + /// + /// Saves the settings to the settings file + /// + public abstract void Save(); + + /// + /// Returns the settings to their default value + /// + public abstract void ToDefault(); + } } \ No newline at end of file diff --git a/Artemis/Artemis/Models/GameModel.cs b/Artemis/Artemis/Models/GameModel.cs index 585304267..8500747fc 100644 --- a/Artemis/Artemis/Models/GameModel.cs +++ b/Artemis/Artemis/Models/GameModel.cs @@ -1,14 +1,18 @@ -using Artemis.Managers; - -namespace Artemis.Models -{ - public abstract class GameModel : EffectModel - { - public bool Enabled; - public string ProcessName; - - protected GameModel(MainManager mainManager) : base(mainManager) - { - } - } +using Artemis.Managers; +using Artemis.Models.Interfaces; +using Artemis.Models.Profiles; + +namespace Artemis.Models +{ + public abstract class GameModel : EffectModel + { + public bool Enabled { get; set; } + public string ProcessName { get; set; } + public IGameDataModel GameDataModel { get; set; } + public ProfileModel Profile { get; set; } + + protected GameModel(MainManager mainManager) : base(mainManager) + { + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Models/Interfaces/GameDataModel.cs b/Artemis/Artemis/Models/Interfaces/GameDataModel.cs new file mode 100644 index 000000000..3dd99c183 --- /dev/null +++ b/Artemis/Artemis/Models/Interfaces/GameDataModel.cs @@ -0,0 +1,6 @@ +namespace Artemis.Models.Interfaces +{ + public interface IGameDataModel + { + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Models/OverlayModel.cs b/Artemis/Artemis/Models/OverlayModel.cs index 21d2ddd2f..1020acb1c 100644 --- a/Artemis/Artemis/Models/OverlayModel.cs +++ b/Artemis/Artemis/Models/OverlayModel.cs @@ -1,46 +1,46 @@ -using System.Drawing; -using Artemis.Managers; - -namespace Artemis.Models -{ - public abstract class OverlayModel : EffectModel - { - private bool _enabled; - public string ProcessName; - - protected OverlayModel(MainManager mainManager) : base(mainManager) - { - } - - public bool Enabled - { - get { return _enabled; } - set - { - if (_enabled == value) - return; - - if (value) - Enable(); - else - Dispose(); - _enabled = value; - } - } - - public void SetEnabled(bool enabled) - { - if (Enabled == enabled) - return; - - if (enabled) - Enable(); - else - Dispose(); - - Enabled = enabled; - } - - public abstract Bitmap GenerateBitmap(Bitmap bitmap); - } +using System.Drawing; +using Artemis.Managers; + +namespace Artemis.Models +{ + public abstract class OverlayModel : EffectModel + { + private bool _enabled; + public string ProcessName; + + protected OverlayModel(MainManager mainManager) : base(mainManager) + { + } + + public bool Enabled + { + get { return _enabled; } + set + { + if (_enabled == value) + return; + + if (value) + Enable(); + else + Dispose(); + _enabled = value; + } + } + + public void SetEnabled(bool enabled) + { + if (Enabled == enabled) + return; + + if (enabled) + Enable(); + else + Dispose(); + + Enabled = enabled; + } + + public abstract Bitmap GenerateBitmap(Bitmap bitmap); + } } \ No newline at end of file diff --git a/Artemis/Artemis/Models/Profiles/LayerConditionModel.cs b/Artemis/Artemis/Models/Profiles/LayerConditionModel.cs new file mode 100644 index 000000000..35ed776cc --- /dev/null +++ b/Artemis/Artemis/Models/Profiles/LayerConditionModel.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Linq.Dynamic; +using Artemis.Models.Interfaces; +using Artemis.Utilities; + +namespace Artemis.Models.Profiles +{ + public class LayerConditionModel + { + public string Field { get; set; } + public string Value { get; set; } + public string Operator { get; set; } + public string Type { get; set; } + + public bool ConditionMet(IGameDataModel subject) + { + if (string.IsNullOrEmpty(Field) || string.IsNullOrEmpty(Value) || string.IsNullOrEmpty(Type)) + return false; + + var inspect = GeneralHelpers.GetPropertyValue(subject, Field); + if (inspect == null) + return false; + + // Put the subject in a list, allowing Dynamic Linq to be used. + var subjectList = new List {(T) subject}; + var res = Type == "String" + ? subjectList.Where($"{Field}.ToLower() {Operator} @0", Value.ToLower()).Any() + : subjectList.Where($"{Field} {Operator} {Value}").Any(); + return res; + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Models/Profiles/LayerDynamicPropertiesModel.cs b/Artemis/Artemis/Models/Profiles/LayerDynamicPropertiesModel.cs new file mode 100644 index 000000000..43af20b1e --- /dev/null +++ b/Artemis/Artemis/Models/Profiles/LayerDynamicPropertiesModel.cs @@ -0,0 +1,67 @@ +using System.ComponentModel; +using Artemis.Models.Interfaces; +using Artemis.Utilities; +using static System.Decimal; + +namespace Artemis.Models.Profiles +{ + public class LayerDynamicPropertiesModel + { + /// + /// Property this dynamic property applies on + /// + public string LayerProperty { get; set; } + + /// + /// Property to base the percentage upon + /// + public string GameProperty { get; set; } + + /// + /// Percentage source, the number that defines 100% + /// + public string PercentageSource { get; set; } + + /// + /// Type of property + /// + public LayerPropertyType LayerPropertyType { get; set; } + + internal void ApplyProperty(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(GameProperty); + if (layerProp == null || userProp == null) + return; + + var percentage = ToDouble(gameProperty) / percentageSource; + layerProp.SetValue(props, (int) (percentage*(int) userProp.GetValue(userProps, null))); + } + + private void ApplyProp(LayerPropertiesModel props, LayerPropertiesModel userProps, IGameDataModel data) + { + var value = data.GetPropValue(PercentageSource); + Apply(props, userProps, data, value); + } + } + + public enum LayerPropertyType + { + [Description("None")] None, + [Description("% of")] PercentageOf, + [Description("% of property")] PercentageOfProperty + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Models/Profiles/LayerModel.cs b/Artemis/Artemis/Models/Profiles/LayerModel.cs new file mode 100644 index 000000000..23dc597b9 --- /dev/null +++ b/Artemis/Artemis/Models/Profiles/LayerModel.cs @@ -0,0 +1,150 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Windows.Media; +using System.Xml.Serialization; +using Artemis.Models.Interfaces; +using Artemis.Utilities; +using Artemis.Utilities.ParentChild; + +namespace Artemis.Models.Profiles +{ + public class LayerModel : IChildItem, IChildItem + { + [XmlIgnore] private readonly LayerDrawer _drawer; + [XmlIgnore] private bool _mustDraw; + + public LayerModel() + { + UserProps = new LayerPropertiesModel(); + CalcProps = new LayerPropertiesModel(); + + Children = new ChildItemCollection(this); + LayerConditions = new List(); + LayerProperties = new List(); + + _mustDraw = true; + _drawer = new LayerDrawer(this, 4); + } + + public string Name { get; set; } + public LayerType LayerType { get; set; } + public bool Enabled { get; set; } + public int Order { get; set; } + public LayerPropertiesModel UserProps { get; set; } + + public ChildItemCollection Children { get; } + public List LayerConditions { get; set; } + public List LayerProperties { get; set; } + + [XmlIgnore] + public LayerPropertiesModel CalcProps { get; set; } + + [XmlIgnore] + public ImageSource LayerImage => _drawer.GetThumbnail(); + + [XmlIgnore] + public LayerModel ParentLayer { get; internal set; } + + [XmlIgnore] + public ProfileModel ParentProfile { get; internal set; } + + public bool ConditionsMet(IGameDataModel dataModel) + { + return Enabled && LayerConditions.All(cm => cm.ConditionMet(dataModel)); + } + + public void DrawPreview(DrawingContext c) + { + GeneralHelpers.CopyProperties(CalcProps, UserProps); + if (LayerType == LayerType.Keyboard || LayerType == LayerType.Keyboard) + _drawer.Draw(c, _mustDraw); + else if (LayerType == LayerType.KeyboardGif) + _drawer.DrawGif(c); + _mustDraw = false; + } + + public void Draw(IGameDataModel dataModel, DrawingContext c) + { + if (!ConditionsMet(dataModel)) + return; + + if (LayerType == LayerType.Folder) + foreach (var layerModel in Children.OrderByDescending(l => l.Order)) + layerModel.Draw(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(IGameDataModel dataModel) + { + if (LayerType == LayerType.Folder) + { + foreach (var layerModel in Children) + layerModel.Update(dataModel); + return; + } + + GeneralHelpers.CopyProperties(CalcProps, UserProps); + foreach (var dynamicProperty in LayerProperties) + dynamicProperty.ApplyProperty(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; + + var target = Children.FirstOrDefault(l => l.Order == newOrder); + if (target == null) + return; + + target.Order = selectedLayer.Order; + selectedLayer.Order = newOrder; + } + + private void FixOrder() + { + Children.Sort(l => l.Order); + for (var i = 0; i < Children.Count; i++) + Children[i].Order = i; + } + + #region IChildItem Members + + LayerModel IChildItem.Parent + { + get { return ParentLayer; } + set { ParentLayer = value; } + } + + ProfileModel IChildItem.Parent + { + get { return ParentProfile; } + set { ParentProfile = value; } + } + + #endregion + } + + public enum LayerType + { + [Description("Folder")] Folder, + [Description("Keyboard")] Keyboard, + [Description("Keyboard - GIF")] KeyboardGif, + [Description("Mouse")] Mouse, + [Description("Headset")] Headset + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Models/Profiles/LayerPropertiesModel.cs b/Artemis/Artemis/Models/Profiles/LayerPropertiesModel.cs new file mode 100644 index 000000000..0e0f40065 --- /dev/null +++ b/Artemis/Artemis/Models/Profiles/LayerPropertiesModel.cs @@ -0,0 +1,41 @@ +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 + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Models/Profiles/ProfileModel.cs b/Artemis/Artemis/Models/Profiles/ProfileModel.cs new file mode 100644 index 000000000..546dd1c37 --- /dev/null +++ b/Artemis/Artemis/Models/Profiles/ProfileModel.cs @@ -0,0 +1,134 @@ +using System.Drawing; +using System.Linq; +using System.Windows; +using System.Windows.Media; +using Artemis.Models.Interfaces; +using Artemis.Utilities; +using Artemis.Utilities.ParentChild; +using Color = System.Windows.Media.Color; + +namespace Artemis.Models.Profiles +{ + public class ProfileModel + { + public ProfileModel() + { + Layers = new ChildItemCollection(this); + DrawingVisual = new DrawingVisual(); + } + + public ChildItemCollection Layers { get; } + + public string Name { get; set; } + public string KeyboardName { get; set; } + public string GameName { get; set; } + public DrawingVisual DrawingVisual { get; set; } + + + protected bool Equals(ProfileModel other) + { + return string.Equals(Name, other.Name) && string.Equals(KeyboardName, other.KeyboardName) && + string.Equals(GameName, other.GameName); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((ProfileModel) obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = Name?.GetHashCode() ?? 0; + hashCode = (hashCode*397) ^ (KeyboardName?.GetHashCode() ?? 0); + hashCode = (hashCode*397) ^ (GameName?.GetHashCode() ?? 0); + return hashCode; + } + } + + /// + /// Adds a new layer with default settings to the profile + /// + /// The newly added layer + 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); + for (var i = 0; i < Layers.Count; i++) + Layers[i].Order = i; + } + + public Bitmap GenerateBitmap(Rect keyboardRect, IGameDataModel gameDataModel) + { + Bitmap bitmap = null; + DrawingVisual.Dispatcher.Invoke(delegate + { + 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(gameDataModel, c); + + // Remove the clip + c.Pop(); + } + + bitmap = ImageUtilities.DrawinVisualToBitmap(visual, keyboardRect); + }); + return bitmap; + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/AmbientLightning/AmbientLightningEffectSettings.cs b/Artemis/Artemis/Modules/Effects/AmbientLightning/AmbientLightningEffectSettings.cs index 70c673008..28685ccf1 100644 --- a/Artemis/Artemis/Modules/Effects/AmbientLightning/AmbientLightningEffectSettings.cs +++ b/Artemis/Artemis/Modules/Effects/AmbientLightning/AmbientLightningEffectSettings.cs @@ -1,37 +1,37 @@ -using System.Drawing.Drawing2D; -using Artemis.Models; - -namespace Artemis.Modules.Effects.AmbientLightning -{ - internal class AmbientLightningEffectSettings : EffectSettings - { - public AmbientLightningEffectSettings() - { - 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; - } - } +using System.Drawing.Drawing2D; +using Artemis.Models; + +namespace Artemis.Modules.Effects.AmbientLightning +{ + internal class AmbientLightningEffectSettings : EffectSettings + { + public AmbientLightningEffectSettings() + { + 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; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/AmbientLightning/AmbientLightningEffectViewModel.cs b/Artemis/Artemis/Modules/Effects/AmbientLightning/AmbientLightningEffectViewModel.cs index eb65e08ee..484318838 100644 --- a/Artemis/Artemis/Modules/Effects/AmbientLightning/AmbientLightningEffectViewModel.cs +++ b/Artemis/Artemis/Modules/Effects/AmbientLightning/AmbientLightningEffectViewModel.cs @@ -1,32 +1,32 @@ -using Artemis.Events; -using Artemis.Managers; -using Artemis.ViewModels.Abstract; -using Caliburn.Micro; - -namespace Artemis.Modules.Effects.AmbientLightning -{ - internal class AmbientLightningEffectViewModel : EffectViewModel, IHandle - { - public AmbientLightningEffectViewModel(MainManager mainManager) - { - // Subscribe to main model - MainManager = mainManager; - MainManager.Events.Subscribe(this); - - // Settings are loaded from file by class - EffectSettings = new AmbientLightningEffectSettings(); - - // Create effect model and add it to MainManager - EffectModel = new AmbientLightningEffectModel(mainManager, (AmbientLightningEffectSettings) EffectSettings); - MainManager.EffectManager.EffectModels.Add(EffectModel); - } - - - public static string Name => "Ambient Lightning"; - - public void Handle(ActiveEffectChanged message) - { - NotifyOfPropertyChange(() => EffectEnabled); - } - } +using Artemis.Events; +using Artemis.Managers; +using Artemis.ViewModels.Abstract; +using Caliburn.Micro; + +namespace Artemis.Modules.Effects.AmbientLightning +{ + internal class AmbientLightningEffectViewModel : EffectViewModel, IHandle + { + public AmbientLightningEffectViewModel(MainManager mainManager) + { + // Subscribe to main model + MainManager = mainManager; + MainManager.Events.Subscribe(this); + + // Settings are loaded from file by class + EffectSettings = new AmbientLightningEffectSettings(); + + // Create effect model and add it to MainManager + EffectModel = new AmbientLightningEffectModel(mainManager, (AmbientLightningEffectSettings) EffectSettings); + MainManager.EffectManager.EffectModels.Add(EffectModel); + } + + + public static string Name => "Ambient Lightning"; + + public void Handle(ActiveEffectChanged message) + { + NotifyOfPropertyChange(() => EffectEnabled); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualization.Designer.cs b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualization.Designer.cs index 259d054f2..e5342a3e7 100644 --- a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualization.Designer.cs +++ b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualization.Designer.cs @@ -1,110 +1,110 @@ -//------------------------------------------------------------------------------ -// -// 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. -// -//------------------------------------------------------------------------------ - -namespace Artemis.Modules.Effects.AudioVisualizer { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] - internal sealed partial class AudioVisualization : global::System.Configuration.ApplicationSettingsBase { - - private static AudioVisualization defaultInstance = ((AudioVisualization)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new AudioVisualization()))); - - public static AudioVisualization Default { - get { - return defaultInstance; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("4")] - public int Sensitivity { - get { - return ((int)(this["Sensitivity"])); - } - set { - this["Sensitivity"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("21")] - public int Bars { - get { - return ((int)(this["Bars"])); - } - set { - this["Bars"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("True")] - public bool FromBottom { - get { - return ((bool)(this["FromBottom"])); - } - set { - this["FromBottom"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("3")] - public int FadeSpeed { - get { - return ((int)(this["FadeSpeed"])); - } - set { - this["FadeSpeed"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("#FFF90000")] - public global::System.Windows.Media.Color TopColor { - get { - return ((global::System.Windows.Media.Color)(this["TopColor"])); - } - set { - this["TopColor"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("#FFFF761E")] - public global::System.Windows.Media.Color MiddleColor { - get { - return ((global::System.Windows.Media.Color)(this["MiddleColor"])); - } - set { - this["MiddleColor"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("#FF00DF00")] - public global::System.Windows.Media.Color BottomColor { - get { - return ((global::System.Windows.Media.Color)(this["BottomColor"])); - } - set { - this["BottomColor"] = value; - } - } - } -} +//------------------------------------------------------------------------------ +// +// 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. +// +//------------------------------------------------------------------------------ + +namespace Artemis.Modules.Effects.AudioVisualizer { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] + internal sealed partial class AudioVisualization : global::System.Configuration.ApplicationSettingsBase { + + private static AudioVisualization defaultInstance = ((AudioVisualization)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new AudioVisualization()))); + + public static AudioVisualization Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("4")] + public int Sensitivity { + get { + return ((int)(this["Sensitivity"])); + } + set { + this["Sensitivity"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("21")] + public int Bars { + get { + return ((int)(this["Bars"])); + } + set { + this["Bars"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool FromBottom { + get { + return ((bool)(this["FromBottom"])); + } + set { + this["FromBottom"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("3")] + public int FadeSpeed { + get { + return ((int)(this["FadeSpeed"])); + } + set { + this["FadeSpeed"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("#FFF90000")] + public global::System.Windows.Media.Color TopColor { + get { + return ((global::System.Windows.Media.Color)(this["TopColor"])); + } + set { + this["TopColor"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("#FFFF761E")] + public global::System.Windows.Media.Color MiddleColor { + get { + return ((global::System.Windows.Media.Color)(this["MiddleColor"])); + } + set { + this["MiddleColor"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("#FF00DF00")] + public global::System.Windows.Media.Color BottomColor { + get { + return ((global::System.Windows.Media.Color)(this["BottomColor"])); + } + set { + this["BottomColor"] = value; + } + } + } +} diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerModel.cs b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerModel.cs index 003645e62..db31d2341 100644 --- a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerModel.cs +++ b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerModel.cs @@ -1,203 +1,203 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Linq; -using Artemis.Managers; -using Artemis.Models; -using Artemis.Modules.Effects.AudioVisualizer.Utilities; -using Artemis.Utilities; -using Artemis.Utilities.Keyboard; -using NAudio.CoreAudioApi; -using NAudio.Wave; - -namespace Artemis.Modules.Effects.AudioVisualizer -{ - public class AudioVisualizerModel : EffectModel - { - private const int FftLength = 2048; - private readonly SampleAggregator _sampleAggregator = new SampleAggregator(FftLength); - private bool _fromBottom; - private bool _generating; - private int _sensitivity; - private IWaveIn _waveIn; - - public AudioVisualizerModel(MainManager mainManager, AudioVisualizerSettings settings) : base(mainManager) - { - Settings = settings; - Name = "Audiovisualizer"; - DeviceIds = new List(); - SpectrumData = new List(); - Scale = 4; - Initialized = false; - } - - public int Lines { get; set; } - - public int Scale { get; set; } - - public AudioVisualizerSettings Settings { get; set; } - public List SpectrumData { get; set; } - public List SoundRectangles { get; set; } - - public List DeviceIds { get; set; } - public string SelectedDeviceId { get; set; } - - public override void Dispose() - { - Initialized = false; - _sampleAggregator.PerformFFT = false; - _sampleAggregator.FftCalculated -= FftCalculated; - - _waveIn.StopRecording(); - _waveIn.DataAvailable -= OnDataAvailable; - _waveIn = null; - } - - public override void Enable() - { - Initialized = false; - Lines = MainManager.KeyboardManager.ActiveKeyboard.Width; - - // TODO: Device selection - SelectedDeviceId = new MMDeviceEnumerator() - .EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active) - .FirstOrDefault()?.ID; - - // Apply settings - SoundRectangles = new List(); - for (var i = 0; i < Lines; i++) - { - SoundRectangles.Add(new KeyboardRectangle( - MainManager.KeyboardManager.ActiveKeyboard, - 0, 0, new List - { - ColorHelpers.ToDrawingColor(Settings.TopColor), - ColorHelpers.ToDrawingColor(Settings.MiddleColor), - ColorHelpers.ToDrawingColor(Settings.BottomColor) - }, - LinearGradientMode.Vertical) {ContainedBrush = false, Height = 0}); - } - _sensitivity = Settings.Sensitivity; - _fromBottom = Settings.FromBottom; - _sampleAggregator.FftCalculated += FftCalculated; - _sampleAggregator.PerformFFT = true; - - // Start listening for sound data - _waveIn = new WasapiLoopbackCapture(); - _waveIn.DataAvailable += OnDataAvailable; - _waveIn.StartRecording(); - - Initialized = true; - } - - public override void Update() - { - // TODO: Use lock instead of a bool - // Start filling the model - _generating = true; - - if (SelectedDeviceId == null) - return; - - var device = new MMDeviceEnumerator() - .EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active) - .FirstOrDefault(d => d.ID == SelectedDeviceId); - - if (device == null || SpectrumData == null) - return; - if (!SpectrumData.Any()) - return; - - // Parse spectrum data - for (var i = 0; i < Lines; i++) - { - int height; - if (SpectrumData.Count - 1 < i || SpectrumData[i] == 0) - height = 0; - else - height = (int) Math.Round(SpectrumData[i]/2.55); - - // Apply Sensitivity setting - height = height*_sensitivity; - var keyboardHeight = - (int) Math.Round(MainManager.KeyboardManager.ActiveKeyboard.Height/100.00*height*Scale); - if (keyboardHeight > SoundRectangles[i].Height) - SoundRectangles[i].Height = keyboardHeight; - else - SoundRectangles[i].Height = SoundRectangles[i].Height - Settings.FadeSpeed; - // Apply Bars setting - SoundRectangles[i].X = i*Scale; - SoundRectangles[i].Width = Scale; - - if (_fromBottom) - SoundRectangles[i].Y = MainManager.KeyboardManager.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; - var bytesRecorded = e.BytesRecorded; - var bufferIncrement = _waveIn.WaveFormat.BlockAlign; - - for (var index = 0; index < bytesRecorded; index += bufferIncrement) - { - var sample32 = BitConverter.ToSingle(buffer, index); - _sampleAggregator.Add(sample32); - } - } - - private void FftCalculated(object sender, FftEventArgs e) - { - if (_generating) - return; - - int x; - var b0 = 0; - - SpectrumData.Clear(); - for (x = 0; x < Lines; x++) - { - float peak = 0; - var b1 = (int) Math.Pow(2, x*10.0/(Lines - 1)); - if (b1 > 2047) - b1 = 2047; - if (b1 <= b0) - b1 = b0 + 1; - for (; b0 < b1; b0++) - { - if (peak < e.Result[1 + b0].X) - peak = e.Result[1 + b0].X; - } - var y = (int) (Math.Sqrt(peak)*3*255 - 4); - if (y > 255) - y = 255; - if (y < 0) - y = 0; - SpectrumData.Add((byte) y); - } - } - } +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Linq; +using Artemis.Managers; +using Artemis.Models; +using Artemis.Modules.Effects.AudioVisualizer.Utilities; +using Artemis.Utilities; +using Artemis.Utilities.Keyboard; +using NAudio.CoreAudioApi; +using NAudio.Wave; + +namespace Artemis.Modules.Effects.AudioVisualizer +{ + public class AudioVisualizerModel : EffectModel + { + private const int FftLength = 2048; + private readonly SampleAggregator _sampleAggregator = new SampleAggregator(FftLength); + private bool _fromBottom; + private bool _generating; + private int _sensitivity; + private IWaveIn _waveIn; + + public AudioVisualizerModel(MainManager mainManager, AudioVisualizerSettings settings) : base(mainManager) + { + Settings = settings; + Name = "Audiovisualizer"; + DeviceIds = new List(); + SpectrumData = new List(); + Scale = 4; + Initialized = false; + } + + public int Lines { get; set; } + + public int Scale { get; set; } + + public AudioVisualizerSettings Settings { get; set; } + public List SpectrumData { get; set; } + public List SoundRectangles { get; set; } + + public List DeviceIds { get; set; } + public string SelectedDeviceId { get; set; } + + public override void Dispose() + { + Initialized = false; + _sampleAggregator.PerformFFT = false; + _sampleAggregator.FftCalculated -= FftCalculated; + + _waveIn.StopRecording(); + _waveIn.DataAvailable -= OnDataAvailable; + _waveIn = null; + } + + public override void Enable() + { + Initialized = false; + Lines = MainManager.KeyboardManager.ActiveKeyboard.Width; + + // TODO: Device selection + SelectedDeviceId = new MMDeviceEnumerator() + .EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active) + .FirstOrDefault()?.ID; + + // Apply settings + SoundRectangles = new List(); + for (var i = 0; i < Lines; i++) + { + SoundRectangles.Add(new KeyboardRectangle( + MainManager.KeyboardManager.ActiveKeyboard, + 0, 0, new List + { + ColorHelpers.ToDrawingColor(Settings.TopColor), + ColorHelpers.ToDrawingColor(Settings.MiddleColor), + ColorHelpers.ToDrawingColor(Settings.BottomColor) + }, + LinearGradientMode.Vertical) {ContainedBrush = false, Height = 0}); + } + _sensitivity = Settings.Sensitivity; + _fromBottom = Settings.FromBottom; + _sampleAggregator.FftCalculated += FftCalculated; + _sampleAggregator.PerformFFT = true; + + // Start listening for sound data + _waveIn = new WasapiLoopbackCapture(); + _waveIn.DataAvailable += OnDataAvailable; + _waveIn.StartRecording(); + + Initialized = true; + } + + public override void Update() + { + // TODO: Use lock instead of a bool + // Start filling the model + _generating = true; + + if (SelectedDeviceId == null) + return; + + var device = new MMDeviceEnumerator() + .EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active) + .FirstOrDefault(d => d.ID == SelectedDeviceId); + + if (device == null || SpectrumData == null) + return; + if (!SpectrumData.Any()) + return; + + // Parse spectrum data + for (var i = 0; i < Lines; i++) + { + int height; + if (SpectrumData.Count - 1 < i || SpectrumData[i] == 0) + height = 0; + else + height = (int) Math.Round(SpectrumData[i]/2.55); + + // Apply Sensitivity setting + height = height*_sensitivity; + var keyboardHeight = + (int) Math.Round(MainManager.KeyboardManager.ActiveKeyboard.Height/100.00*height*Scale); + if (keyboardHeight > SoundRectangles[i].Height) + SoundRectangles[i].Height = keyboardHeight; + else + SoundRectangles[i].Height = SoundRectangles[i].Height - Settings.FadeSpeed; + // Apply Bars setting + SoundRectangles[i].X = i*Scale; + SoundRectangles[i].Width = Scale; + + if (_fromBottom) + SoundRectangles[i].Y = MainManager.KeyboardManager.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; + var bytesRecorded = e.BytesRecorded; + var bufferIncrement = _waveIn.WaveFormat.BlockAlign; + + for (var index = 0; index < bytesRecorded; index += bufferIncrement) + { + var sample32 = BitConverter.ToSingle(buffer, index); + _sampleAggregator.Add(sample32); + } + } + + private void FftCalculated(object sender, FftEventArgs e) + { + if (_generating) + return; + + int x; + var b0 = 0; + + SpectrumData.Clear(); + for (x = 0; x < Lines; x++) + { + float peak = 0; + var b1 = (int) Math.Pow(2, x*10.0/(Lines - 1)); + if (b1 > 2047) + b1 = 2047; + if (b1 <= b0) + b1 = b0 + 1; + for (; b0 < b1; b0++) + { + if (peak < e.Result[1 + b0].X) + peak = e.Result[1 + b0].X; + } + var y = (int) (Math.Sqrt(peak)*3*255 - 4); + if (y > 255) + y = 255; + if (y < 0) + y = 0; + SpectrumData.Add((byte) y); + } + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerSettings.cs b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerSettings.cs index 22f2b6cfc..7c965870c 100644 --- a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerSettings.cs +++ b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerSettings.cs @@ -1,56 +1,56 @@ -using System.Windows.Media; -using Artemis.Models; - -namespace Artemis.Modules.Effects.AudioVisualizer -{ - public class AudioVisualizerSettings : EffectSettings - { - public AudioVisualizerSettings() - { - Load(); - } - - public int Sensitivity { get; set; } - public int Bars { get; set; } - public bool FromBottom { get; set; } - public int FadeSpeed { get; set; } - public Color TopColor { get; set; } - public Color MiddleColor { get; set; } - public Color BottomColor { get; set; } - - public sealed override void Load() - { - Sensitivity = AudioVisualization.Default.Sensitivity; - Bars = AudioVisualization.Default.Bars; - FromBottom = AudioVisualization.Default.FromBottom; - FadeSpeed = AudioVisualization.Default.FadeSpeed; - TopColor = AudioVisualization.Default.TopColor; - MiddleColor = AudioVisualization.Default.MiddleColor; - BottomColor = AudioVisualization.Default.BottomColor; - } - - public sealed override void Save() - { - AudioVisualization.Default.Sensitivity = Sensitivity; - AudioVisualization.Default.Bars = Bars; - AudioVisualization.Default.FromBottom = FromBottom; - AudioVisualization.Default.FadeSpeed = FadeSpeed; - AudioVisualization.Default.TopColor = TopColor; - AudioVisualization.Default.MiddleColor = MiddleColor; - AudioVisualization.Default.BottomColor = BottomColor; - - AudioVisualization.Default.Save(); - } - - public sealed override void ToDefault() - { - Sensitivity = 4; - Bars = 21; - FromBottom = true; - FadeSpeed = 3; - TopColor = Color.FromArgb(255, 249, 0, 0); - MiddleColor = Color.FromArgb(255, 255, 118, 30); - BottomColor = Color.FromArgb(255, 0, 223, 0); - } - } +using System.Windows.Media; +using Artemis.Models; + +namespace Artemis.Modules.Effects.AudioVisualizer +{ + public class AudioVisualizerSettings : EffectSettings + { + public AudioVisualizerSettings() + { + Load(); + } + + public int Sensitivity { get; set; } + public int Bars { get; set; } + public bool FromBottom { get; set; } + public int FadeSpeed { get; set; } + public Color TopColor { get; set; } + public Color MiddleColor { get; set; } + public Color BottomColor { get; set; } + + public sealed override void Load() + { + Sensitivity = AudioVisualization.Default.Sensitivity; + Bars = AudioVisualization.Default.Bars; + FromBottom = AudioVisualization.Default.FromBottom; + FadeSpeed = AudioVisualization.Default.FadeSpeed; + TopColor = AudioVisualization.Default.TopColor; + MiddleColor = AudioVisualization.Default.MiddleColor; + BottomColor = AudioVisualization.Default.BottomColor; + } + + public sealed override void Save() + { + AudioVisualization.Default.Sensitivity = Sensitivity; + AudioVisualization.Default.Bars = Bars; + AudioVisualization.Default.FromBottom = FromBottom; + AudioVisualization.Default.FadeSpeed = FadeSpeed; + AudioVisualization.Default.TopColor = TopColor; + AudioVisualization.Default.MiddleColor = MiddleColor; + AudioVisualization.Default.BottomColor = BottomColor; + + AudioVisualization.Default.Save(); + } + + public sealed override void ToDefault() + { + Sensitivity = 4; + Bars = 21; + FromBottom = true; + FadeSpeed = 3; + TopColor = Color.FromArgb(255, 249, 0, 0); + MiddleColor = Color.FromArgb(255, 255, 118, 30); + BottomColor = Color.FromArgb(255, 0, 223, 0); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerView.xaml.cs b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerView.xaml.cs index b5787d5b4..48d3709e2 100644 --- a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerView.xaml.cs +++ b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerView.xaml.cs @@ -1,15 +1,15 @@ -using System.Windows.Controls; - -namespace Artemis.Modules.Effects.AudioVisualizer -{ - /// - /// Interaction logic for AudioVisualizerView.xaml - /// - public partial class AudioVisualizerView : UserControl - { - public AudioVisualizerView() - { - InitializeComponent(); - } - } +using System.Windows.Controls; + +namespace Artemis.Modules.Effects.AudioVisualizer +{ + /// + /// Interaction logic for AudioVisualizerView.xaml + /// + public partial class AudioVisualizerView : UserControl + { + public AudioVisualizerView() + { + InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerViewModel.cs b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerViewModel.cs index ac7815048..bece0a893 100644 --- a/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerViewModel.cs +++ b/Artemis/Artemis/Modules/Effects/AudioVisualizer/AudioVisualizerViewModel.cs @@ -1,31 +1,31 @@ -using Artemis.Events; -using Artemis.Managers; -using Artemis.ViewModels.Abstract; -using Caliburn.Micro; - -namespace Artemis.Modules.Effects.AudioVisualizer -{ - public class AudioVisualizerViewModel : EffectViewModel, IHandle - { - public AudioVisualizerViewModel(MainManager mainManager) - { - // Subscribe to main model - MainManager = mainManager; - MainManager.Events.Subscribe(this); - - // Settings are loaded from file by class - EffectSettings = new AudioVisualizerSettings(); - - // Create effect model and add it to MainManager - EffectModel = new AudioVisualizerModel(mainManager, (AudioVisualizerSettings) EffectSettings); - MainManager.EffectManager.EffectModels.Add(EffectModel); - } - - public static string Name => "Audio Visualizer"; - - public void Handle(ActiveEffectChanged message) - { - NotifyOfPropertyChange(() => EffectEnabled); - } - } +using Artemis.Events; +using Artemis.Managers; +using Artemis.ViewModels.Abstract; +using Caliburn.Micro; + +namespace Artemis.Modules.Effects.AudioVisualizer +{ + public class AudioVisualizerViewModel : EffectViewModel, IHandle + { + public AudioVisualizerViewModel(MainManager mainManager) + { + // Subscribe to main model + MainManager = mainManager; + MainManager.Events.Subscribe(this); + + // Settings are loaded from file by class + EffectSettings = new AudioVisualizerSettings(); + + // Create effect model and add it to MainManager + EffectModel = new AudioVisualizerModel(mainManager, (AudioVisualizerSettings) EffectSettings); + MainManager.EffectManager.EffectModels.Add(EffectModel); + } + + public static string Name => "Audio Visualizer"; + + public void Handle(ActiveEffectChanged message) + { + NotifyOfPropertyChange(() => EffectEnabled); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/Utilities/FftEventArgs.cs b/Artemis/Artemis/Modules/Effects/AudioVisualizer/Utilities/FftEventArgs.cs index 69faaf373..01ce5163f 100644 --- a/Artemis/Artemis/Modules/Effects/AudioVisualizer/Utilities/FftEventArgs.cs +++ b/Artemis/Artemis/Modules/Effects/AudioVisualizer/Utilities/FftEventArgs.cs @@ -2,16 +2,16 @@ using System; using System.Diagnostics; using NAudio.Dsp; -namespace Artemis.Modules.Effects.AudioVisualizer.Utilities -{ - public class FftEventArgs : EventArgs - { - [DebuggerStepThrough] - public FftEventArgs(Complex[] result) - { - Result = result; - } - - public Complex[] Result { get; private set; } - } +namespace Artemis.Modules.Effects.AudioVisualizer.Utilities +{ + public class FftEventArgs : EventArgs + { + [DebuggerStepThrough] + public FftEventArgs(Complex[] result) + { + Result = result; + } + + public Complex[] Result { get; private set; } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/AudioVisualizer/Utilities/SampleAggregator.cs b/Artemis/Artemis/Modules/Effects/AudioVisualizer/Utilities/SampleAggregator.cs index ce68f4034..14599c6be 100644 --- a/Artemis/Artemis/Modules/Effects/AudioVisualizer/Utilities/SampleAggregator.cs +++ b/Artemis/Artemis/Modules/Effects/AudioVisualizer/Utilities/SampleAggregator.cs @@ -1,55 +1,55 @@ using System; using NAudio.Dsp; -namespace Artemis.Modules.Effects.AudioVisualizer.Utilities -{ // The Complex and FFT are here! - - public class SampleAggregator - { - private readonly FftEventArgs fftArgs; - - // This Complex is NAudio's own! - private readonly Complex[] fftBuffer; - private readonly int fftLength; - private readonly int m; - private int fftPos; - - public SampleAggregator(int fftLength) - { - if (!IsPowerOfTwo(fftLength)) - { - throw new ArgumentException("FFT Length must be a power of two"); - } - m = (int) Math.Log(fftLength, 2.0); - this.fftLength = fftLength; - fftBuffer = new Complex[fftLength]; - fftArgs = new FftEventArgs(fftBuffer); - } - - public bool PerformFFT { get; set; } - // FFT - public event EventHandler FftCalculated; - - private bool IsPowerOfTwo(int x) - { - return (x & (x - 1)) == 0; - } - - public void Add(float value) - { - if (PerformFFT && FftCalculated != null) - { - // Remember the window function! There are many others as well. - fftBuffer[fftPos].X = (float) (value*FastFourierTransform.HammingWindow(fftPos, fftLength)); - fftBuffer[fftPos].Y = 0; // This is always zero with audio. - fftPos++; - if (fftPos >= fftLength) - { - fftPos = 0; - FastFourierTransform.FFT(true, m, fftBuffer); - FftCalculated(this, fftArgs); - } - } - } - } +namespace Artemis.Modules.Effects.AudioVisualizer.Utilities +{ // The Complex and FFT are here! + + public class SampleAggregator + { + private readonly FftEventArgs fftArgs; + + // This Complex is NAudio's own! + private readonly Complex[] fftBuffer; + private readonly int fftLength; + private readonly int m; + private int fftPos; + + public SampleAggregator(int fftLength) + { + if (!IsPowerOfTwo(fftLength)) + { + throw new ArgumentException("FFT Length must be a power of two"); + } + m = (int) Math.Log(fftLength, 2.0); + this.fftLength = fftLength; + fftBuffer = new Complex[fftLength]; + fftArgs = new FftEventArgs(fftBuffer); + } + + public bool PerformFFT { get; set; } + // FFT + public event EventHandler FftCalculated; + + private bool IsPowerOfTwo(int x) + { + return (x & (x - 1)) == 0; + } + + public void Add(float value) + { + if (PerformFFT && FftCalculated != null) + { + // Remember the window function! There are many others as well. + fftBuffer[fftPos].X = (float) (value*FastFourierTransform.HammingWindow(fftPos, fftLength)); + fftBuffer[fftPos].Y = 0; // This is always zero with audio. + fftPos++; + if (fftPos >= fftLength) + { + fftPos = 0; + FastFourierTransform.FFT(true, m, fftBuffer); + FftCalculated(this, fftArgs); + } + } + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/Debug/DebugEffectModel.cs b/Artemis/Artemis/Modules/Effects/Debug/DebugEffectModel.cs index dc3456ed9..034f96077 100644 --- a/Artemis/Artemis/Modules/Effects/Debug/DebugEffectModel.cs +++ b/Artemis/Artemis/Modules/Effects/Debug/DebugEffectModel.cs @@ -1,71 +1,71 @@ -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 -{ - 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.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; - } - } +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 +{ + 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.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; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/Debug/DebugEffectSettings.cs b/Artemis/Artemis/Modules/Effects/Debug/DebugEffectSettings.cs index 5075b73cf..48e8a2767 100644 --- a/Artemis/Artemis/Modules/Effects/Debug/DebugEffectSettings.cs +++ b/Artemis/Artemis/Modules/Effects/Debug/DebugEffectSettings.cs @@ -1,37 +1,37 @@ -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; - } - } +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; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/Debug/DebugEffectView.xaml.cs b/Artemis/Artemis/Modules/Effects/Debug/DebugEffectView.xaml.cs index 289ffdcd2..465ac97e3 100644 --- a/Artemis/Artemis/Modules/Effects/Debug/DebugEffectView.xaml.cs +++ b/Artemis/Artemis/Modules/Effects/Debug/DebugEffectView.xaml.cs @@ -1,15 +1,15 @@ -using System.Windows.Controls; - -namespace Artemis.Modules.Effects.Debug -{ - /// - /// Interaction logic for DebugEffectView.xaml - /// - public partial class DebugEffectView : UserControl - { - public DebugEffectView() - { - InitializeComponent(); - } - } +using System.Windows.Controls; + +namespace Artemis.Modules.Effects.Debug +{ + /// + /// Interaction logic for DebugEffectView.xaml + /// + public partial class DebugEffectView : UserControl + { + public DebugEffectView() + { + InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/Debug/DebugEffectViewModel.cs b/Artemis/Artemis/Modules/Effects/Debug/DebugEffectViewModel.cs index 6ee3ad9ca..7a8d0f832 100644 --- a/Artemis/Artemis/Modules/Effects/Debug/DebugEffectViewModel.cs +++ b/Artemis/Artemis/Modules/Effects/Debug/DebugEffectViewModel.cs @@ -1,85 +1,85 @@ -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, IHandle - { - 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 RectangleTypes - => new BindableCollection(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; - } - } - } +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, IHandle + { + 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 RectangleTypes + => new BindableCollection(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; + } + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/TypeHole/TypeHoleModel.cs b/Artemis/Artemis/Modules/Effects/TypeHole/TypeHoleModel.cs index 40167d92a..ea6779209 100644 --- a/Artemis/Artemis/Modules/Effects/TypeHole/TypeHoleModel.cs +++ b/Artemis/Artemis/Modules/Effects/TypeHole/TypeHoleModel.cs @@ -1,40 +1,40 @@ -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; - } - } +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; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/TypeHole/TypeHoleView.xaml.cs b/Artemis/Artemis/Modules/Effects/TypeHole/TypeHoleView.xaml.cs index 82baded2b..34c16616a 100644 --- a/Artemis/Artemis/Modules/Effects/TypeHole/TypeHoleView.xaml.cs +++ b/Artemis/Artemis/Modules/Effects/TypeHole/TypeHoleView.xaml.cs @@ -1,15 +1,15 @@ -using System.Windows.Controls; - -namespace Artemis.Modules.Effects.TypeHole -{ - /// - /// Interaction logic for TypeHoleView.xaml - /// - public partial class TypeHoleView : UserControl - { - public TypeHoleView() - { - InitializeComponent(); - } - } +using System.Windows.Controls; + +namespace Artemis.Modules.Effects.TypeHole +{ + /// + /// Interaction logic for TypeHoleView.xaml + /// + public partial class TypeHoleView : UserControl + { + public TypeHoleView() + { + InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/TypeHole/TypeHoleViewModel.cs b/Artemis/Artemis/Modules/Effects/TypeHole/TypeHoleViewModel.cs index e748948ed..943548af3 100644 --- a/Artemis/Artemis/Modules/Effects/TypeHole/TypeHoleViewModel.cs +++ b/Artemis/Artemis/Modules/Effects/TypeHole/TypeHoleViewModel.cs @@ -1,28 +1,28 @@ -using Artemis.Events; -using Artemis.Managers; -using Artemis.ViewModels.Abstract; -using Caliburn.Micro; - -namespace Artemis.Modules.Effects.TypeHole -{ - public class TypeHoleViewModel : EffectViewModel, IHandle - { - 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); - } - } +using Artemis.Events; +using Artemis.Managers; +using Artemis.ViewModels.Abstract; +using Caliburn.Micro; + +namespace Artemis.Modules.Effects.TypeHole +{ + public class TypeHoleViewModel : EffectViewModel, IHandle + { + 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); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/TypeWave/TypeWave.Designer.cs b/Artemis/Artemis/Modules/Effects/TypeWave/TypeWave.Designer.cs index 7448c42dc..a40e4b8cd 100644 --- a/Artemis/Artemis/Modules/Effects/TypeWave/TypeWave.Designer.cs +++ b/Artemis/Artemis/Modules/Effects/TypeWave/TypeWave.Designer.cs @@ -1,98 +1,98 @@ -//------------------------------------------------------------------------------ -// -// 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. -// -//------------------------------------------------------------------------------ - -namespace Artemis.Settings { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] - internal sealed partial class TypeWave : global::System.Configuration.ApplicationSettingsBase { - - private static TypeWave defaultInstance = ((TypeWave)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new TypeWave()))); - - public static TypeWave Default { - get { - return defaultInstance; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("True")] - public bool IsRandomColors { - get { - return ((bool)(this["IsRandomColors"])); - } - set { - this["IsRandomColors"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("#FFFF0000")] - public global::System.Windows.Media.Color WaveColor { - get { - return ((global::System.Windows.Media.Color)(this["WaveColor"])); - } - set { - this["WaveColor"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("True")] - public bool IsShiftColors { - get { - return ((bool)(this["IsShiftColors"])); - } - set { - this["IsShiftColors"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("20")] - public int ShiftColorSpeed { - get { - return ((int)(this["ShiftColorSpeed"])); - } - set { - this["ShiftColorSpeed"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("500")] - public int TimeToLive { - get { - return ((int)(this["TimeToLive"])); - } - set { - this["TimeToLive"] = value; - } - } - - [global::System.Configuration.UserScopedSettingAttribute()] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Configuration.DefaultSettingValueAttribute("4")] - public int SpreadSpeed { - get { - return ((int)(this["SpreadSpeed"])); - } - set { - this["SpreadSpeed"] = value; - } - } - } -} +//------------------------------------------------------------------------------ +// +// 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. +// +//------------------------------------------------------------------------------ + +namespace Artemis.Settings { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] + internal sealed partial class TypeWave : global::System.Configuration.ApplicationSettingsBase { + + private static TypeWave defaultInstance = ((TypeWave)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new TypeWave()))); + + public static TypeWave Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool IsRandomColors { + get { + return ((bool)(this["IsRandomColors"])); + } + set { + this["IsRandomColors"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("#FFFF0000")] + public global::System.Windows.Media.Color WaveColor { + get { + return ((global::System.Windows.Media.Color)(this["WaveColor"])); + } + set { + this["WaveColor"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool IsShiftColors { + get { + return ((bool)(this["IsShiftColors"])); + } + set { + this["IsShiftColors"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("20")] + public int ShiftColorSpeed { + get { + return ((int)(this["ShiftColorSpeed"])); + } + set { + this["ShiftColorSpeed"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("500")] + public int TimeToLive { + get { + return ((int)(this["TimeToLive"])); + } + set { + this["TimeToLive"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("4")] + public int SpreadSpeed { + get { + return ((int)(this["SpreadSpeed"])); + } + set { + this["SpreadSpeed"] = value; + } + } + } +} diff --git a/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveModel.cs b/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveModel.cs index f61bd161a..046fd5315 100644 --- a/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveModel.cs +++ b/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveModel.cs @@ -1,152 +1,152 @@ -using System.Collections.Generic; -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.Managers; -using Artemis.Models; -using Artemis.Utilities; - -namespace Artemis.Modules.Effects.TypeWave -{ - public class TypeWaveModel : EffectModel - { - private readonly List _waves; - private Color _randomColor; - - public TypeWaveModel(MainManager mainManager, TypeWaveSettings settings) : base(mainManager) - { - Name = "TypeWave"; - _waves = new List(); - _randomColor = Color.Red; - Settings = settings; - Initialized = false; - Scale = 4; - } - - public int Scale { get; set; } - - public TypeWaveSettings Settings { get; set; } - - public override void Dispose() - { - Initialized = false; - MainManager.KeyboardHook.KeyDownCallback -= KeyboardHookOnKeyDownCallback; - } - - private void KeyboardHookOnKeyDownCallback(KeyEventArgs e) - { - // More than 25 waves is pointless - if (_waves.Count >= 25) - return; - - var keyMatch = KeyMap.UsEnglishOrionKeys.FirstOrDefault(k => k.KeyCode == e.KeyCode); - if (keyMatch == null) - return; - - _waves.Add(Settings.IsRandomColors - ? new Wave(new Point(keyMatch.PosX * Scale, keyMatch.PosY * Scale), 0, _randomColor) - : new Wave(new Point(keyMatch.PosX * Scale, keyMatch.PosY * Scale), 0, - ColorHelpers.ToDrawingColor(Settings.WaveColor))); - } - - public override void Enable() - { - Initialized = false; - - // Listener won't start unless the effect is active - MainManager.KeyboardHook.KeyDownCallback += KeyboardHookOnKeyDownCallback; - - Initialized = true; - } - - public override void Update() - { - if (Settings.IsRandomColors) - _randomColor = ColorHelpers.ShiftColor(_randomColor, 25); - - for (var i = 0; i < _waves.Count; i++) - { - // TODO: Get from settings - var fps = 25; - - _waves[i].Size += Settings.SpreadSpeed * Scale; - - if (Settings.IsShiftColors) - _waves[i].Color = ColorHelpers.ShiftColor(_waves[i].Color, Settings.ShiftColorSpeed); - - var decreaseAmount = 255/(Settings.TimeToLive/fps); - _waves[i].Color = Color.FromArgb( - _waves[i].Color.A - decreaseAmount, _waves[i].Color.R, - _waves[i].Color.G, - _waves[i].Color.B); - - if (_waves[i].Color.A >= decreaseAmount) - continue; - - _waves.RemoveAt(i); - i--; - } - } - - public override Bitmap GenerateBitmap() - { - if (_waves.Count == 0) - return null; - - var bitmap = MainManager.KeyboardManager.ActiveKeyboard.KeyboardBitmap(Scale); - using (var g = Graphics.FromImage(bitmap)) - { - g.Clear(Color.Transparent); - g.SmoothingMode = SmoothingMode.HighQuality; - - // Don't want a for-each, collection is changed in different thread - // ReSharper disable once ForCanBeConvertedToForeach - for (var i = 0; i < _waves.Count; i++) - { - if (_waves[i].Size == 0) - continue; - var path = new GraphicsPath(); - path.AddEllipse(_waves[i].Point.X - _waves[i].Size/2, _waves[i].Point.Y - _waves[i].Size/2, - _waves[i].Size, _waves[i].Size); - - Color fillColor; - if (MainManager.KeyboardManager.ActiveKeyboard is CorsairRGB) - fillColor = Color.Black; - else - fillColor = Color.Transparent; - - var pthGrBrush = new PathGradientBrush(path) - { - SurroundColors = new[] {_waves[i].Color}, - CenterColor = fillColor - }; - - g.FillPath(pthGrBrush, path); - pthGrBrush.FocusScales = new PointF(0.3f, 0.8f); - - g.FillPath(pthGrBrush, path); - g.DrawEllipse(new Pen(pthGrBrush, 1), _waves[i].Point.X - _waves[i].Size/2, - _waves[i].Point.Y - _waves[i].Size/2, _waves[i].Size, _waves[i].Size); - } - } - return bitmap; - } - } - - public class Wave - { - public Wave(Point point, int size, Color color) - { - Point = point; - Size = size; - Color = color; - } - - public Point Point { get; set; } - public int Size { get; set; } - public Color Color { get; set; } - } +using System.Collections.Generic; +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.Managers; +using Artemis.Models; +using Artemis.Utilities; + +namespace Artemis.Modules.Effects.TypeWave +{ + public class TypeWaveModel : EffectModel + { + private readonly List _waves; + private Color _randomColor; + + public TypeWaveModel(MainManager mainManager, TypeWaveSettings settings) : base(mainManager) + { + Name = "TypeWave"; + _waves = new List(); + _randomColor = Color.Red; + Settings = settings; + Initialized = false; + Scale = 4; + } + + public int Scale { get; set; } + + public TypeWaveSettings Settings { get; set; } + + public override void Dispose() + { + Initialized = false; + MainManager.KeyboardHook.KeyDownCallback -= KeyboardHookOnKeyDownCallback; + } + + private void KeyboardHookOnKeyDownCallback(KeyEventArgs e) + { + // More than 25 waves is pointless + if (_waves.Count >= 25) + return; + + var keyMatch = KeyMap.UsEnglishOrionKeys.FirstOrDefault(k => k.KeyCode == e.KeyCode); + if (keyMatch == null) + return; + + _waves.Add(Settings.IsRandomColors + ? new Wave(new Point(keyMatch.PosX * Scale, keyMatch.PosY * Scale), 0, _randomColor) + : new Wave(new Point(keyMatch.PosX * Scale, keyMatch.PosY * Scale), 0, + ColorHelpers.ToDrawingColor(Settings.WaveColor))); + } + + public override void Enable() + { + Initialized = false; + + // Listener won't start unless the effect is active + MainManager.KeyboardHook.KeyDownCallback += KeyboardHookOnKeyDownCallback; + + Initialized = true; + } + + public override void Update() + { + if (Settings.IsRandomColors) + _randomColor = ColorHelpers.ShiftColor(_randomColor, 25); + + for (var i = 0; i < _waves.Count; i++) + { + // TODO: Get from settings + var fps = 25; + + _waves[i].Size += Settings.SpreadSpeed * Scale; + + if (Settings.IsShiftColors) + _waves[i].Color = ColorHelpers.ShiftColor(_waves[i].Color, Settings.ShiftColorSpeed); + + var decreaseAmount = 255/(Settings.TimeToLive/fps); + _waves[i].Color = Color.FromArgb( + _waves[i].Color.A - decreaseAmount, _waves[i].Color.R, + _waves[i].Color.G, + _waves[i].Color.B); + + if (_waves[i].Color.A >= decreaseAmount) + continue; + + _waves.RemoveAt(i); + i--; + } + } + + public override Bitmap GenerateBitmap() + { + if (_waves.Count == 0) + return null; + + var bitmap = MainManager.KeyboardManager.ActiveKeyboard.KeyboardBitmap(Scale); + using (var g = Graphics.FromImage(bitmap)) + { + g.Clear(Color.Transparent); + g.SmoothingMode = SmoothingMode.HighQuality; + + // Don't want a for-each, collection is changed in different thread + // ReSharper disable once ForCanBeConvertedToForeach + for (var i = 0; i < _waves.Count; i++) + { + if (_waves[i].Size == 0) + continue; + var path = new GraphicsPath(); + path.AddEllipse(_waves[i].Point.X - _waves[i].Size/2, _waves[i].Point.Y - _waves[i].Size/2, + _waves[i].Size, _waves[i].Size); + + Color fillColor; + if (MainManager.KeyboardManager.ActiveKeyboard is CorsairRGB) + fillColor = Color.Black; + else + fillColor = Color.Transparent; + + var pthGrBrush = new PathGradientBrush(path) + { + SurroundColors = new[] {_waves[i].Color}, + CenterColor = fillColor + }; + + g.FillPath(pthGrBrush, path); + pthGrBrush.FocusScales = new PointF(0.3f, 0.8f); + + g.FillPath(pthGrBrush, path); + g.DrawEllipse(new Pen(pthGrBrush, 1), _waves[i].Point.X - _waves[i].Size/2, + _waves[i].Point.Y - _waves[i].Size/2, _waves[i].Size, _waves[i].Size); + } + } + return bitmap; + } + } + + public class Wave + { + public Wave(Point point, int size, Color color) + { + Point = point; + Size = size; + Color = color; + } + + public Point Point { get; set; } + public int Size { get; set; } + public Color Color { get; set; } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveSettings.cs b/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveSettings.cs index cc776298d..2f8876e4e 100644 --- a/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveSettings.cs +++ b/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveSettings.cs @@ -1,52 +1,52 @@ -using System.Windows.Media; -using Artemis.Models; - -namespace Artemis.Modules.Effects.TypeWave -{ - public class TypeWaveSettings : EffectSettings - { - public TypeWaveSettings() - { - Load(); - } - - public bool IsRandomColors { get; set; } - public Color WaveColor { get; set; } - public bool IsShiftColors { get; set; } - public int ShiftColorSpeed { get; set; } - public int TimeToLive { get; set; } - public int SpreadSpeed { get; set; } - - public sealed override void Load() - { - IsRandomColors = Settings.TypeWave.Default.IsRandomColors; - WaveColor = Settings.TypeWave.Default.WaveColor; - IsShiftColors = Settings.TypeWave.Default.IsShiftColors; - ShiftColorSpeed = Settings.TypeWave.Default.ShiftColorSpeed; - TimeToLive = Settings.TypeWave.Default.TimeToLive; - SpreadSpeed = Settings.TypeWave.Default.SpreadSpeed; - } - - public sealed override void Save() - { - Settings.TypeWave.Default.IsRandomColors = IsRandomColors; - Settings.TypeWave.Default.WaveColor = WaveColor; - Settings.TypeWave.Default.IsShiftColors = IsShiftColors; - Settings.TypeWave.Default.ShiftColorSpeed = ShiftColorSpeed; - Settings.TypeWave.Default.TimeToLive = TimeToLive; - Settings.TypeWave.Default.SpreadSpeed = SpreadSpeed; - - Settings.TypeWave.Default.Save(); - } - - public sealed override void ToDefault() - { - IsRandomColors = true; - WaveColor = Color.FromArgb(255, 255, 0, 0); - IsShiftColors = true; - ShiftColorSpeed = 20; - TimeToLive = 500; - SpreadSpeed = 4; - } - } +using System.Windows.Media; +using Artemis.Models; + +namespace Artemis.Modules.Effects.TypeWave +{ + public class TypeWaveSettings : EffectSettings + { + public TypeWaveSettings() + { + Load(); + } + + public bool IsRandomColors { get; set; } + public Color WaveColor { get; set; } + public bool IsShiftColors { get; set; } + public int ShiftColorSpeed { get; set; } + public int TimeToLive { get; set; } + public int SpreadSpeed { get; set; } + + public sealed override void Load() + { + IsRandomColors = Settings.TypeWave.Default.IsRandomColors; + WaveColor = Settings.TypeWave.Default.WaveColor; + IsShiftColors = Settings.TypeWave.Default.IsShiftColors; + ShiftColorSpeed = Settings.TypeWave.Default.ShiftColorSpeed; + TimeToLive = Settings.TypeWave.Default.TimeToLive; + SpreadSpeed = Settings.TypeWave.Default.SpreadSpeed; + } + + public sealed override void Save() + { + Settings.TypeWave.Default.IsRandomColors = IsRandomColors; + Settings.TypeWave.Default.WaveColor = WaveColor; + Settings.TypeWave.Default.IsShiftColors = IsShiftColors; + Settings.TypeWave.Default.ShiftColorSpeed = ShiftColorSpeed; + Settings.TypeWave.Default.TimeToLive = TimeToLive; + Settings.TypeWave.Default.SpreadSpeed = SpreadSpeed; + + Settings.TypeWave.Default.Save(); + } + + public sealed override void ToDefault() + { + IsRandomColors = true; + WaveColor = Color.FromArgb(255, 255, 0, 0); + IsShiftColors = true; + ShiftColorSpeed = 20; + TimeToLive = 500; + SpreadSpeed = 4; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveView.xaml.cs b/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveView.xaml.cs index 17d71a874..687158fd5 100644 --- a/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveView.xaml.cs +++ b/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveView.xaml.cs @@ -1,15 +1,15 @@ -using System.Windows.Controls; - -namespace Artemis.Modules.Effects.TypeWave -{ - /// - /// Interaction logic for TypeWaveView.xaml - /// - public partial class TypeWaveView : UserControl - { - public TypeWaveView() - { - InitializeComponent(); - } - } +using System.Windows.Controls; + +namespace Artemis.Modules.Effects.TypeWave +{ + /// + /// Interaction logic for TypeWaveView.xaml + /// + public partial class TypeWaveView : UserControl + { + public TypeWaveView() + { + InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveViewModel.cs b/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveViewModel.cs index 4e335092f..c8dde369b 100644 --- a/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveViewModel.cs +++ b/Artemis/Artemis/Modules/Effects/TypeWave/TypeWaveViewModel.cs @@ -1,31 +1,31 @@ -using Artemis.Events; -using Artemis.Managers; -using Artemis.ViewModels.Abstract; -using Caliburn.Micro; - -namespace Artemis.Modules.Effects.TypeWave -{ - public class TypeWaveViewModel : EffectViewModel, IHandle - { - public TypeWaveViewModel(MainManager mainManager) - { - // Subscribe to main model - MainManager = mainManager; - MainManager.Events.Subscribe(this); - - // Settings are loaded from file by class - EffectSettings = new TypeWaveSettings(); - - // Create effect model and add it to MainManager - EffectModel = new TypeWaveModel(mainManager, (TypeWaveSettings) EffectSettings); - MainManager.EffectManager.EffectModels.Add(EffectModel); - } - - public static string Name => "Type Waves"; - - public void Handle(ActiveEffectChanged message) - { - NotifyOfPropertyChange(() => EffectEnabled); - } - } +using Artemis.Events; +using Artemis.Managers; +using Artemis.ViewModels.Abstract; +using Caliburn.Micro; + +namespace Artemis.Modules.Effects.TypeWave +{ + public class TypeWaveViewModel : EffectViewModel, IHandle + { + public TypeWaveViewModel(MainManager mainManager) + { + // Subscribe to main model + MainManager = mainManager; + MainManager.Events.Subscribe(this); + + // Settings are loaded from file by class + EffectSettings = new TypeWaveSettings(); + + // Create effect model and add it to MainManager + EffectModel = new TypeWaveModel(mainManager, (TypeWaveSettings) EffectSettings); + MainManager.EffectManager.EffectModels.Add(EffectModel); + } + + public static string Name => "Type Waves"; + + public void Handle(ActiveEffectChanged message) + { + NotifyOfPropertyChange(() => EffectEnabled); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeDataModel.cs b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeDataModel.cs new file mode 100644 index 000000000..de5d12920 --- /dev/null +++ b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeDataModel.cs @@ -0,0 +1,124 @@ +using Artemis.Models.Interfaces; + +namespace Artemis.Modules.Games.CounterStrike +{ + public class CounterStrikeDataModel : IGameDataModel + { + public Provider provider { get; set; } + public Map map { get; set; } + public Round round { get; set; } + public Player player { 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 string steamid { get; set; } + public int timestamp { get; set; } + } + + public class TeamCt + { + public int score { get; set; } + } + + public class TeamT + { + public int score { get; set; } + } + + public class Map + { + public string mode { get; set; } + public string name { get; set; } + public string phase { get; set; } + public int round { get; set; } + public TeamCt team_ct { get; set; } + public TeamT team_t { get; set; } + } + + public class Round + { + public string phase { get; set; } + } + + public class State + { + public int health { get; set; } + public int armor { get; set; } + public bool helmet { get; set; } + public int flashed { get; set; } + public int smoked { get; set; } + public int burning { get; set; } + public int money { get; set; } + public int round_kills { get; set; } + public int round_killhs { get; set; } + } + + public class Weapon0 + { + public string name { get; set; } + public string paintkit { get; set; } + public string type { get; set; } + public string state { get; set; } + } + + public class Weapon1 + { + public string name { get; set; } + public string paintkit { get; set; } + public string type { get; set; } + public int ammo_clip { get; set; } + public int ammo_clip_max { get; set; } + public int ammo_reserve { get; set; } + public string state { get; set; } + } + + public class Weapon2 + { + public string name { get; set; } + public string paintkit { get; set; } + public string type { get; set; } + public string state { get; set; } + } + + public class Weapons + { + public Weapon0 weapon_0 { get; set; } + public Weapon1 weapon_1 { get; set; } + public Weapon2 weapon_2 { get; set; } + } + + public class MatchStats + { + public int kills { get; set; } + public int assists { get; set; } + public int deaths { get; set; } + public int mvps { get; set; } + public int score { get; set; } + } + + public class Player + { + public string steamid { get; set; } + public string name { get; set; } + public string team { get; set; } + public string activity { get; set; } + public State state { get; set; } + public Weapons weapons { get; set; } + public MatchStats match_stats { get; set; } + } + + public class Round2 + { + public string phase { get; set; } + } + + public class Previously + { + public Round2 round { get; set; } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs index 1c0a280c3..4bf2f6d78 100644 --- a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs +++ b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs @@ -1,209 +1,72 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Linq; -using Artemis.KeyboardProviders; -using Artemis.Managers; -using Artemis.Models; -using Artemis.Utilities; -using Artemis.Utilities.GameState; -using Artemis.Utilities.Keyboard; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace Artemis.Modules.Games.CounterStrike -{ - public class CounterStrikeModel : GameModel - { - private KeyboardRegion _topRow; - - public CounterStrikeModel(MainManager mainManager, CounterStrikeSettings settings) : base(mainManager) - { - Settings = settings; - Name = "CounterStrike"; - ProcessName = "csgo"; - Scale = 4; - Enabled = Settings.Enabled; - Initialized = false; - } - - public CounterStrikeSettings Settings { get; set; } - - public KeyboardRectangle EventRect { get; set; } - public KeyboardRectangle TeamRect { get; set; } - public KeyboardRectangle AmmoRect { get; set; } - public JObject CsJson { get; set; } - - public bool DrawingSmoke { get; set; } - public bool DrawingFlash { get; set; } - - public int Scale { get; set; } - - public override void Dispose() - { - Initialized = false; - MainManager.GameStateWebServer.GameDataReceived -= HandleGameData; - } - - public override void Enable() - { - Initialized = false; - - // Some keyboards have a different baseline, Corsair F-keys start at row 1 - _topRow = MainManager.KeyboardManager.ActiveKeyboard.KeyboardRegions.First(r => r.RegionName == "TopRow"); - AmmoRect = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0, _topRow.TopLeft.X, - new List(), - LinearGradientMode.Horizontal) {Height = Scale, ContainedBrush = false}; - TeamRect = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0, _topRow.TopLeft.X + 1, - new List(), - LinearGradientMode.Horizontal) - { - Height = MainManager.KeyboardManager.ActiveKeyboard.Height*Scale - Scale - }; - EventRect = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0, _topRow.TopLeft.X + 1, - new List(), - LinearGradientMode.Horizontal) - { - Height = MainManager.KeyboardManager.ActiveKeyboard.Height*Scale - Scale - }; - MainManager.GameStateWebServer.GameDataReceived += HandleGameData; - - Initialized = true; - } - - public override void Update() - { - if (CsJson == null) - return; - - if (Settings.AmmoEnabled) - UpdateAmmo(); - if (Settings.TeamColorEnabled) - UpdateTeam(); - if (Settings.LowHpEnabled) - UpdateHealth(); - if (Settings.FlashEnabled) - UpdateFlash(); - if (Settings.SmokeEnabled) - UpdateSmoke(); - } - - private void UpdateHealth() - { - if (CsJson["player"]?["state"]?["health"] == null) - return; - - var health = CsJson["player"]["state"]["health"].Value(); - if (health > 25 || health < 1) - return; - - TeamRect.Colors = new List {Color.Red, Color.OrangeRed, Color.Red, Color.OrangeRed}; - } - - private void UpdateSmoke() - { - if (CsJson["player"]?["state"]?["smoked"] == null) - return; - - var smoked = CsJson["player"]["state"]["smoked"].Value(); - if (smoked == 0 && !DrawingSmoke) - return; - - EventRect.Colors = new List {Color.FromArgb(smoked, 255, 255, 255)}; - DrawingSmoke = smoked != 0; - } - - private void UpdateFlash() - { - if (CsJson["player"]?["state"]?["flashed"] == null) - return; - - var flashed = CsJson["player"]["state"]["flashed"].Value(); - if (flashed == 0 && !DrawingFlash) - return; - - EventRect.Colors = new List {Color.FromArgb(flashed, 255, 255, 255)}; - DrawingFlash = flashed != 0; - } - - private void UpdateTeam() - { - var currentTeam = CsJson["player"]?["team"]; - if (currentTeam == null) - return; - - var t1 = Color.FromArgb(255, 255, 129, 0); - var t2 = Color.FromArgb(255, 255, 170, 125); - - var ct1 = Color.FromArgb(255, 203, 238, 255); - var ct2 = Color.FromArgb(255, 0, 173, 255); - - TeamRect.Colors = currentTeam.Value() == "T" - ? new List {t1, t2, t1, t2} - : new List {ct1, ct2, ct1, ct2}; - TeamRect.Rotate = true; - } - - private void UpdateAmmo() - { - if (CsJson["player"]["weapons"] == null) - return; - - var activeWeapon = - CsJson["player"]["weapons"].Children() - .Select(c => c.First) - .FirstOrDefault(w => w["state"]?.Value() == "active"); - - // Update the ammo display - if (activeWeapon?["ammo_clip_max"] == null || activeWeapon["ammo_clip"] == null) - return; - - var maxAmmo = activeWeapon["ammo_clip_max"].Value(); - var ammo = activeWeapon["ammo_clip"].Value(); - - if (maxAmmo < 0) - return; - - var ammoPercentage = (int) Math.Ceiling(100.00/maxAmmo)*ammo; - AmmoRect.Width = (int) Math.Floor(_topRow.BottomRight.Y/100.00*ammoPercentage)*Scale; - AmmoRect.Colors = new List - { - ColorHelpers.ToDrawingColor(Settings.AmmoMainColor), - ColorHelpers.ToDrawingColor(Settings.AmmoSecondaryColor) - }; - - // Low ammo indicator - if (ammoPercentage < 37) - AmmoRect.StartBlink(1000); - else - AmmoRect.StopBlink(); - } - - public override Bitmap GenerateBitmap() - { - var bitmap = MainManager.KeyboardManager.ActiveKeyboard.KeyboardBitmap(Scale); - - using (var g = Graphics.FromImage(bitmap)) - { - g.Clear(Color.Transparent); - AmmoRect.Draw(g); - TeamRect.Draw(g); - EventRect.Draw(g); - } - return bitmap; - } - - public void HandleGameData(object sender, GameDataReceivedEventArgs e) - { - var jsonString = e.Json.ToString(); - - // Ensure it's CS:GO JSON - if (!jsonString.Contains("Counter-Strike: Global Offensive")) - return; - - // Parse the JSON - CsJson = JsonConvert.DeserializeObject(jsonString); - } - } +using System.Diagnostics; +using System.Drawing; +using Artemis.Managers; +using Artemis.Models; +using Artemis.Utilities.GameState; +using Newtonsoft.Json; + +namespace Artemis.Modules.Games.CounterStrike +{ + public class CounterStrikeModel : GameModel + { + public CounterStrikeModel(MainManager mainManager, CounterStrikeSettings settings) : base(mainManager) + { + Settings = settings; + Name = "CounterStrike"; + ProcessName = "csgo"; + Scale = 4; + Enabled = Settings.Enabled; + Initialized = false; + } + + public CounterStrikeSettings Settings { get; set; } + + public int Scale { get; set; } + + public override void Dispose() + { + Initialized = false; + MainManager.GameStateWebServer.GameDataReceived -= HandleGameData; + } + + public override void Enable() + { + Initialized = false; + + GameDataModel = new CounterStrikeDataModel(); + MainManager.GameStateWebServer.GameDataReceived += HandleGameData; + + Initialized = true; + } + + public override void Update() + { + if (Profile == null || GameDataModel == null) + return; + + foreach (var layerModel in Profile.Layers) + layerModel.Update(GameDataModel); + } + + public override Bitmap GenerateBitmap() + { + if (Profile == null || GameDataModel == null) + return null; + + var keyboardRect = MainManager.KeyboardManager.ActiveKeyboard.KeyboardRectangle(Scale); + return Profile.GenerateBitmap(keyboardRect, GameDataModel); + } + + public void HandleGameData(object sender, GameDataReceivedEventArgs e) + { + var jsonString = e.Json.ToString(); + + // Ensure it's CS:GO JSON + if (!jsonString.Contains("Counter-Strike: Global Offensive")) + return; + + // Parse the JSON + GameDataModel = JsonConvert.DeserializeObject(jsonString); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeSettings.cs b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeSettings.cs index 224c1088c..ec32679d9 100644 --- a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeSettings.cs +++ b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeSettings.cs @@ -1,71 +1,71 @@ -using System.Windows.Media; -using Artemis.Models; - -namespace Artemis.Modules.Games.CounterStrike -{ - public class CounterStrikeSettings : GameSettings - { - public CounterStrikeSettings() - { - Load(); - } - - public string GameDirectory { get; set; } - - public bool AmmoEnabled { get; set; } - public Color AmmoMainColor { get; set; } - public Color AmmoSecondaryColor { get; set; } - - public bool TeamColorEnabled { get; set; } - public bool FlashEnabled { get; set; } - public bool SmokeEnabled { get; set; } - public bool LowHpEnabled { get; set; } - - public sealed override void Load() - { - Enabled = CounterStrike.Default.Enabled; - GameDirectory = CounterStrike.Default.GameDirectory; - - AmmoEnabled = CounterStrike.Default.AmmoEnabled; - AmmoMainColor = CounterStrike.Default.AmmoMainColor; - AmmoSecondaryColor = CounterStrike.Default.AmmoSecondaryColor; - - TeamColorEnabled = CounterStrike.Default.TeamColorEnabled; - FlashEnabled = CounterStrike.Default.FlashEnabled; - SmokeEnabled = CounterStrike.Default.SmokeEnabled; - LowHpEnabled = CounterStrike.Default.LowHpEnabled; - } - - public sealed override void Save() - { - CounterStrike.Default.Enabled = Enabled; - CounterStrike.Default.GameDirectory = GameDirectory; - - CounterStrike.Default.AmmoEnabled = AmmoEnabled; - CounterStrike.Default.AmmoMainColor = AmmoMainColor; - CounterStrike.Default.AmmoSecondaryColor = AmmoSecondaryColor; - - CounterStrike.Default.TeamColorEnabled = TeamColorEnabled; - CounterStrike.Default.FlashEnabled = FlashEnabled; - CounterStrike.Default.SmokeEnabled = SmokeEnabled; - CounterStrike.Default.LowHpEnabled = LowHpEnabled; - - CounterStrike.Default.Save(); - } - - public sealed override void ToDefault() - { - Enabled = true; - GameDirectory = string.Empty; - - AmmoEnabled = true; - AmmoMainColor = Color.FromArgb(255, 38, 246, 0); - AmmoSecondaryColor = Color.FromArgb(255, 255, 41, 0); - - TeamColorEnabled = true; - FlashEnabled = true; - SmokeEnabled = true; - LowHpEnabled = true; - } - } +using System.Windows.Media; +using Artemis.Models; + +namespace Artemis.Modules.Games.CounterStrike +{ + public class CounterStrikeSettings : GameSettings + { + public CounterStrikeSettings() + { + Load(); + } + + public string GameDirectory { get; set; } + + public bool AmmoEnabled { get; set; } + public Color AmmoMainColor { get; set; } + public Color AmmoSecondaryColor { get; set; } + + public bool TeamColorEnabled { get; set; } + public bool FlashEnabled { get; set; } + public bool SmokeEnabled { get; set; } + public bool LowHpEnabled { get; set; } + + public sealed override void Load() + { + Enabled = CounterStrike.Default.Enabled; + GameDirectory = CounterStrike.Default.GameDirectory; + + AmmoEnabled = CounterStrike.Default.AmmoEnabled; + AmmoMainColor = CounterStrike.Default.AmmoMainColor; + AmmoSecondaryColor = CounterStrike.Default.AmmoSecondaryColor; + + TeamColorEnabled = CounterStrike.Default.TeamColorEnabled; + FlashEnabled = CounterStrike.Default.FlashEnabled; + SmokeEnabled = CounterStrike.Default.SmokeEnabled; + LowHpEnabled = CounterStrike.Default.LowHpEnabled; + } + + public sealed override void Save() + { + CounterStrike.Default.Enabled = Enabled; + CounterStrike.Default.GameDirectory = GameDirectory; + + CounterStrike.Default.AmmoEnabled = AmmoEnabled; + CounterStrike.Default.AmmoMainColor = AmmoMainColor; + CounterStrike.Default.AmmoSecondaryColor = AmmoSecondaryColor; + + CounterStrike.Default.TeamColorEnabled = TeamColorEnabled; + CounterStrike.Default.FlashEnabled = FlashEnabled; + CounterStrike.Default.SmokeEnabled = SmokeEnabled; + CounterStrike.Default.LowHpEnabled = LowHpEnabled; + + CounterStrike.Default.Save(); + } + + public sealed override void ToDefault() + { + Enabled = true; + GameDirectory = string.Empty; + + AmmoEnabled = true; + AmmoMainColor = Color.FromArgb(255, 38, 246, 0); + AmmoSecondaryColor = Color.FromArgb(255, 255, 41, 0); + + TeamColorEnabled = true; + FlashEnabled = true; + SmokeEnabled = true; + LowHpEnabled = true; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeView.xaml b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeView.xaml index 449c1a6ec..fcf198769 100644 --- a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeView.xaml +++ b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeView.xaml @@ -19,11 +19,6 @@ - - - - - @@ -58,73 +53,11 @@ - - - Display ammo on F-keys - - - - - - Main ammo color - - - - - - Secondary ammo color - - - - - - Display smoked effect - - - - - - Display flashed effect - - - - - - Color keyboard according to team - - - - - - Color keyboard red on low HP - - + + - + - public partial class CounterStrikeView : UserControl - { - public CounterStrikeView() - { - InitializeComponent(); - } - } +using System.Windows.Controls; + +namespace Artemis.Modules.Games.CounterStrike +{ + /// + /// Interaction logic for CounterStrikeView.xaml + /// + public partial class CounterStrikeView : UserControl + { + public CounterStrikeView() + { + InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeViewModel.cs b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeViewModel.cs index 56031a7e0..982bb1136 100644 --- a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeViewModel.cs +++ b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeViewModel.cs @@ -1,64 +1,78 @@ -using System.IO; -using System.Windows.Forms; -using Artemis.Managers; -using Artemis.Properties; -using Artemis.ViewModels.Abstract; - -namespace Artemis.Modules.Games.CounterStrike -{ - public class CounterStrikeViewModel : GameViewModel - { - public CounterStrikeViewModel(MainManager mainManager) - { - MainManager = mainManager; - - // Settings are loaded from file by class - GameSettings = new CounterStrikeSettings(); - - // Create effect model and add it to MainManager - GameModel = new CounterStrikeModel(mainManager, (CounterStrikeSettings) GameSettings); - MainManager.EffectManager.EffectModels.Add(GameModel); - PlaceConfigFile(); - } - - public static string Name => "CS:GO"; - public string Content => "Counter-Strike: GO Content"; - - public void BrowseDirectory() - { - var dialog = new FolderBrowserDialog {SelectedPath = ((CounterStrikeSettings) GameSettings).GameDirectory}; - var result = dialog.ShowDialog(); - if (result != DialogResult.OK) - return; - - ((CounterStrikeSettings) GameSettings).GameDirectory = dialog.SelectedPath; - NotifyOfPropertyChange(() => GameSettings); - - GameSettings.Save(); - PlaceConfigFile(); - } - - public void PlaceConfigFile() - { - if (((CounterStrikeSettings) GameSettings).GameDirectory == string.Empty) - return; - if (Directory.Exists(((CounterStrikeSettings) GameSettings).GameDirectory + "/csgo/cfg")) - { - var cfgFile = Resources.csgoGamestateConfiguration.Replace("{{port}}", - MainManager.GameStateWebServer.Port.ToString()); - File.WriteAllText( - ((CounterStrikeSettings) GameSettings).GameDirectory + "/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"); - ((CounterStrikeSettings) GameSettings).GameDirectory = string.Empty; - NotifyOfPropertyChange(() => GameSettings); - - GameSettings.Save(); - } - } +using System.ComponentModel; +using System.IO; +using System.Windows.Forms; +using Artemis.Managers; +using Artemis.Properties; +using Artemis.ViewModels; +using Artemis.ViewModels.Abstract; + +namespace Artemis.Modules.Games.CounterStrike +{ + public class CounterStrikeViewModel : GameViewModel + { + public CounterStrikeViewModel(MainManager mainManager) + { + MainManager = mainManager; + + // Settings are loaded from file by class + GameSettings = new CounterStrikeSettings(); + + // Create effect model and add it to MainManager + GameModel = new CounterStrikeModel(mainManager, (CounterStrikeSettings) GameSettings); + MainManager.EffectManager.EffectModels.Add(GameModel); + PlaceConfigFile(); + + ProfileEditor = new ProfileEditorViewModel(MainManager, GameModel); + ProfileEditor.PropertyChanged += ProfileUpdater; + GameModel.Profile = ProfileEditor.SelectedProfile; + } + + private void ProfileUpdater(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "SelectedProfile") + GameModel.Profile = ProfileEditor.SelectedProfile; + } + + public ProfileEditorViewModel ProfileEditor { get; set; } + + public static string Name => "CS:GO"; + public string Content => "Counter-Strike: GO Content"; + + public void BrowseDirectory() + { + var dialog = new FolderBrowserDialog {SelectedPath = ((CounterStrikeSettings) GameSettings).GameDirectory}; + var result = dialog.ShowDialog(); + if (result != DialogResult.OK) + return; + + ((CounterStrikeSettings) GameSettings).GameDirectory = dialog.SelectedPath; + NotifyOfPropertyChange(() => GameSettings); + + GameSettings.Save(); + PlaceConfigFile(); + } + + public void PlaceConfigFile() + { + if (((CounterStrikeSettings) GameSettings).GameDirectory == string.Empty) + return; + if (Directory.Exists(((CounterStrikeSettings) GameSettings).GameDirectory + "/csgo/cfg")) + { + var cfgFile = Resources.csgoGamestateConfiguration.Replace("{{port}}", + MainManager.GameStateWebServer.Port.ToString()); + File.WriteAllText( + ((CounterStrikeSettings) GameSettings).GameDirectory + "/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"); + ((CounterStrikeSettings) GameSettings).GameDirectory = string.Empty; + NotifyOfPropertyChange(() => GameSettings); + + GameSettings.Save(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/Dota2/Dota2View.xaml.cs b/Artemis/Artemis/Modules/Games/Dota2/Dota2View.xaml.cs index 31cc81d99..6ccd64a3d 100644 --- a/Artemis/Artemis/Modules/Games/Dota2/Dota2View.xaml.cs +++ b/Artemis/Artemis/Modules/Games/Dota2/Dota2View.xaml.cs @@ -1,15 +1,15 @@ -using System.Windows.Controls; - -namespace Artemis.Modules.Games.Dota2 -{ - /// - /// Interaction logic for Dota2View.xaml - /// - public partial class Dota2View : UserControl - { - public Dota2View() - { - InitializeComponent(); - } - } +using System.Windows.Controls; + +namespace Artemis.Modules.Games.Dota2 +{ + /// + /// Interaction logic for Dota2View.xaml + /// + public partial class Dota2View : UserControl + { + public Dota2View() + { + InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueDataModel.cs b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueDataModel.cs new file mode 100644 index 000000000..9b2cf86b8 --- /dev/null +++ b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueDataModel.cs @@ -0,0 +1,9 @@ +using Artemis.Models.Interfaces; + +namespace Artemis.Modules.Games.RocketLeague +{ + public class RocketLeagueDataModel : IGameDataModel + { + public int Boost { get; set; } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs index ce2d997a0..089552d02 100644 --- a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs +++ b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs @@ -1,15 +1,10 @@ using System; -using System.Collections.Generic; using System.Drawing; -using System.Drawing.Drawing2D; using System.Linq; -using System.Threading; -using System.Threading.Tasks; using Artemis.Managers; using Artemis.Models; using Artemis.Settings; using Artemis.Utilities; -using Artemis.Utilities.Keyboard; using Artemis.Utilities.Memory; using Newtonsoft.Json; @@ -17,13 +12,8 @@ namespace Artemis.Modules.Games.RocketLeague { public class RocketLeagueModel : GameModel { - private int _boostAmount; - private bool _boostGrowing; - private KeyboardRectangle _boostRect; - private bool _contextualColor; private Memory _memory; private GamePointersCollection _pointer; - private int _previousBoost; public RocketLeagueModel(MainManager mainManager, RocketLeagueSettings settings) : base(mainManager) { @@ -49,105 +39,44 @@ namespace Artemis.Modules.Games.RocketLeague { Initialized = false; - _contextualColor = Settings.ContextualColor; - - _boostRect = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0, 0, new List - { - ColorHelpers.ToDrawingColor(Settings.MainColor), - ColorHelpers.ToDrawingColor(Settings.SecondaryColor) - }, LinearGradientMode.Horizontal); - Updater.GetPointers(); _pointer = JsonConvert.DeserializeObject(Offsets.Default.RocketLeague); var tempProcess = MemoryHelpers.GetProcessIfRunning(ProcessName); _memory = new Memory(tempProcess); + GameDataModel = new RocketLeagueDataModel(); Initialized = true; } public override void Update() { - if (_boostGrowing) - return; - if (_memory == null) + if (Profile == null || GameDataModel == null || _memory == null) return; var offsets = _pointer.GameAddresses.First(ga => ga.Description == "Boost").ToString(); var boostAddress = _memory.GetAddress("\"RocketLeague.exe\"" + offsets); var boostFloat = _memory.ReadFloat(boostAddress)*100/3; - _previousBoost = _boostAmount; - _boostAmount = (int) Math.Ceiling(boostFloat); + ((RocketLeagueDataModel) GameDataModel).Boost = (int) Math.Ceiling(boostFloat); // Take care of any reading errors resulting in an OutOfMemory on draw - if (_boostAmount < 0) - _boostAmount = 0; - if (_boostAmount > 100) - _boostAmount = 100; + if (((RocketLeagueDataModel) GameDataModel).Boost < 0) + ((RocketLeagueDataModel) GameDataModel).Boost = 0; + if (((RocketLeagueDataModel) GameDataModel).Boost > 100) + ((RocketLeagueDataModel) GameDataModel).Boost = 100; - _boostRect.Width = - (int) Math.Ceiling(MainManager.KeyboardManager.ActiveKeyboard.Width*Scale/100.00*_boostAmount); - - if (_contextualColor) - { - if (_boostAmount < 33) - _boostRect.Colors = new List {Color.Red}; - else if (_boostAmount >= 33 && _boostAmount < 66) - _boostRect.Colors = new List {Color.Yellow}; - else if (_boostAmount >= 66) - _boostRect.Colors = new List {Color.Lime}; - } - - Task.Run(() => GrowIfHigher()); - } - - private void GrowIfHigher() - { - if (_boostAmount <= _previousBoost || _boostGrowing) - return; - - _boostGrowing = true; - const int amountOfSteps = 6; - - var difference = _boostAmount - _previousBoost; - var differenceStep = difference/amountOfSteps; - var differenceStepRest = difference%amountOfSteps; - _boostAmount = _previousBoost; - _boostRect.Width = - (int) Math.Ceiling(MainManager.KeyboardManager.ActiveKeyboard.Width*Scale/100.00*_boostAmount); - - for (var i = 0; i < amountOfSteps; i++) - { - if (differenceStepRest > 0) - { - differenceStepRest -= 1; - _boostAmount += 1; - _boostRect.Width = - (int) Math.Ceiling(MainManager.KeyboardManager.ActiveKeyboard.Width*Scale/100.00*_boostAmount); - } - _boostAmount += differenceStep; - _boostRect.Width = - (int) Math.Ceiling(MainManager.KeyboardManager.ActiveKeyboard.Width*Scale/100.00*_boostAmount); - - Thread.Sleep(50); - } - - _boostGrowing = false; + foreach (var layerModel in Profile.Layers) + layerModel.Update(GameDataModel); } public override Bitmap GenerateBitmap() { - var bitmap = MainManager.KeyboardManager.ActiveKeyboard.KeyboardBitmap(Scale); - if (_boostRect == null) + if (Profile == null || GameDataModel == null) return null; - using (var g = Graphics.FromImage(bitmap)) - { - g.Clear(Color.Transparent); - _boostRect.Draw(g); - } - return bitmap; + var keyboardRect = MainManager.KeyboardManager.ActiveKeyboard.KeyboardRectangle(Scale); + return Profile.GenerateBitmap(keyboardRect, GameDataModel); } } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueSettings.cs b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueSettings.cs index f35a17507..0c3cbc662 100644 --- a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueSettings.cs +++ b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueSettings.cs @@ -1,43 +1,43 @@ -using System.Windows.Media; -using Artemis.Models; - -namespace Artemis.Modules.Games.RocketLeague -{ - public class RocketLeagueSettings : GameSettings - { - public RocketLeagueSettings() - { - Load(); - } - - public Color MainColor { get; set; } - public Color SecondaryColor { get; set; } - public bool ContextualColor { get; set; } - - public sealed override void Load() - { - Enabled = RocketLeague.Default.Enabled; - MainColor = RocketLeague.Default.MainColor; - SecondaryColor = RocketLeague.Default.SecondaryColor; - ContextualColor = RocketLeague.Default.ContextualColor; - } - - public sealed override void Save() - { - RocketLeague.Default.Enabled = Enabled; - RocketLeague.Default.MainColor = MainColor; - RocketLeague.Default.SecondaryColor = SecondaryColor; - RocketLeague.Default.ContextualColor = ContextualColor; - - RocketLeague.Default.Save(); - } - - public sealed override void ToDefault() - { - Enabled = true; - MainColor = Color.FromArgb(255, 255, 80, 0); - SecondaryColor = Color.FromArgb(255, 255, 0, 0); - ContextualColor = false; - } - } +using System.Windows.Media; +using Artemis.Models; + +namespace Artemis.Modules.Games.RocketLeague +{ + public class RocketLeagueSettings : GameSettings + { + public RocketLeagueSettings() + { + Load(); + } + + public Color MainColor { get; set; } + public Color SecondaryColor { get; set; } + public bool ContextualColor { get; set; } + + public sealed override void Load() + { + Enabled = RocketLeague.Default.Enabled; + MainColor = RocketLeague.Default.MainColor; + SecondaryColor = RocketLeague.Default.SecondaryColor; + ContextualColor = RocketLeague.Default.ContextualColor; + } + + public sealed override void Save() + { + RocketLeague.Default.Enabled = Enabled; + RocketLeague.Default.MainColor = MainColor; + RocketLeague.Default.SecondaryColor = SecondaryColor; + RocketLeague.Default.ContextualColor = ContextualColor; + + RocketLeague.Default.Save(); + } + + public sealed override void ToDefault() + { + Enabled = true; + MainColor = Color.FromArgb(255, 255, 80, 0); + SecondaryColor = Color.FromArgb(255, 255, 0, 0); + ContextualColor = false; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueView.xaml b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueView.xaml index a971d629d..f1ecb05bb 100644 --- a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueView.xaml +++ b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueView.xaml @@ -40,46 +40,8 @@ - - - Main boost display color - - - - - - Secondary boost display color - - - - - - Color bar according to boost amount - - - - - - Tip: To find a color combination you like, start an exhibition match, pickup 100 boost and play around with the colors. - They'll appear on your keyboard immediately! Once you're satisfied don't forget to click save changes. - - + + diff --git a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueView.xaml.cs b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueView.xaml.cs index 8a3795be1..3f653148d 100644 --- a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueView.xaml.cs +++ b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueView.xaml.cs @@ -1,15 +1,15 @@ -using System.Windows.Controls; - -namespace Artemis.Modules.Games.RocketLeague -{ - /// - /// Interaction logic for RocketLeagueView.xaml - /// - public partial class RocketLeagueView : UserControl - { - public RocketLeagueView() - { - InitializeComponent(); - } - } +using System.Windows.Controls; + +namespace Artemis.Modules.Games.RocketLeague +{ + /// + /// Interaction logic for RocketLeagueView.xaml + /// + public partial class RocketLeagueView : UserControl + { + public RocketLeagueView() + { + InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueViewModel.cs b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueViewModel.cs index f9235b924..d91f9a4d3 100644 --- a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueViewModel.cs +++ b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueViewModel.cs @@ -1,60 +1,73 @@ -using Artemis.Managers; -using Artemis.Settings; -using Artemis.Utilities; -using Artemis.Utilities.Memory; -using Artemis.ViewModels.Abstract; -using Newtonsoft.Json; - -namespace Artemis.Modules.Games.RocketLeague -{ - public class RocketLeagueViewModel : GameViewModel - { - private string _versionText; - - public RocketLeagueViewModel(MainManager mainManager) - { - MainManager = mainManager; - - // Settings are loaded from file by class - GameSettings = new RocketLeagueSettings(); - - // Create effect model and add it to MainManager - GameModel = new RocketLeagueModel(mainManager, (RocketLeagueSettings) GameSettings); - MainManager.EffectManager.EffectModels.Add(GameModel); - - SetVersionText(); - } - - public static string Name => "Rocket League"; - - public string VersionText - { - get { return _versionText; } - set - { - if (value == _versionText) return; - _versionText = value; - NotifyOfPropertyChange(() => VersionText); - } - } - - public RocketLeagueModel RocketLeagueModel { get; set; } - - private void SetVersionText() - { - if (!General.Default.EnablePointersUpdate) - { - VersionText = "Note: You disabled pointer updates, this could result in the " + - "Rocket League effect not working after a game update."; - return; - } - - Updater.GetPointers(); - var version = JsonConvert - .DeserializeObject(Offsets.Default.RocketLeague) - .GameVersion; - VersionText = $"Note: Requires patch {version}. When a new patch is released Artemis downloads " + - "new pointers for the latest version (unless disabled in settings)."; - } - } +using System.ComponentModel; +using Artemis.Managers; +using Artemis.Settings; +using Artemis.Utilities; +using Artemis.Utilities.Memory; +using Artemis.ViewModels; +using Artemis.ViewModels.Abstract; +using Newtonsoft.Json; + +namespace Artemis.Modules.Games.RocketLeague +{ + public class RocketLeagueViewModel : GameViewModel + { + private string _versionText; + + public RocketLeagueViewModel(MainManager mainManager) + { + MainManager = mainManager; + + // Settings are loaded from file by class + GameSettings = new RocketLeagueSettings(); + + // Create effect model and add it to MainManager + GameModel = new RocketLeagueModel(mainManager, (RocketLeagueSettings) GameSettings); + MainManager.EffectManager.EffectModels.Add(GameModel); + SetVersionText(); + + ProfileEditor = new ProfileEditorViewModel(MainManager, GameModel); + ProfileEditor.PropertyChanged += ProfileUpdater; + GameModel.Profile = ProfileEditor.SelectedProfile; + } + + public ProfileEditorViewModel ProfileEditor { get; set; } + + public static string Name => "Rocket League"; + + public string VersionText + { + get { return _versionText; } + set + { + if (value == _versionText) return; + _versionText = value; + NotifyOfPropertyChange(() => VersionText); + } + } + + public RocketLeagueModel RocketLeagueModel { get; set; } + + private void ProfileUpdater(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "SelectedProfile") + GameModel.Profile = ProfileEditor.SelectedProfile; + } + + private void SetVersionText() + { + if (!General.Default.EnablePointersUpdate) + { + VersionText = "Note: You disabled pointer updates, this could result in the " + + "Rocket League effect not working after a game update."; + return; + } + + Updater.GetPointers(); + var version = JsonConvert + .DeserializeObject(Offsets.Default.RocketLeague) + .GameVersion; + VersionText = $"Note: Requires patch {version}. When a new patch is released Artemis downloads " + + "new pointers for the latest version (unless disabled in settings)."; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionDataModel.cs b/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionDataModel.cs index f2a6390d5..2ffc9d0e8 100644 --- a/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionDataModel.cs +++ b/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionDataModel.cs @@ -1,29 +1,31 @@ -using System.Collections.Generic; +using System; +using Artemis.Models.Interfaces; namespace Artemis.Modules.Games.TheDivision { - public class TheDivisionDataModel + public class TheDivisionDataModel : IGameDataModel { - public List DivisionPlayers { get; set; } - public GrenadeState GrenadeState { get; set; } - public bool LowAmmo { get; set; } - public bool LowHp { get; set; } - public TheDivisionDataModel() { - DivisionPlayers = new List(); + TestyTest = new TestTest(); } + + public PlayerState PartyMember1 { get; set; } + public PlayerState PartyMember2 { get; set; } + public PlayerState PartyMember3 { get; set; } + + public bool LowAmmo { get; set; } + public bool LowHp { get; set; } + public GrenadeState GrenadeState { get; set; } + + public TestTest TestyTest { get; set; } } - public class DivisionPlayer + + public class TestTest { - public int Id { get; set; } - public PlayerState PlayerState { get; set; } - - public DivisionPlayer(int id) - { - Id = id; - } + public string TestS { get; set; } + public int TestI { get; set; } } public enum GrenadeState diff --git a/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionModel.cs b/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionModel.cs index 3c65d41c2..906ab4980 100644 --- a/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionModel.cs +++ b/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionModel.cs @@ -1,257 +1,246 @@ -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Linq; -using Artemis.Managers; -using Artemis.Models; -using Artemis.Modules.Effects.TypeWave; -using Artemis.Utilities; -using Artemis.Utilities.Keyboard; -using Artemis.Utilities.LogitechDll; -using CUE.NET; - -namespace Artemis.Modules.Games.TheDivision -{ - public class TheDivisionModel : GameModel - { - private Wave _ammoWave; - private TheDivisionDataModel _dataModel; - private KeyboardRectangle _hpRect; - private KeyboardRectangle _p2; - private KeyboardRectangle _p3; - private KeyboardRectangle _p4; - private StickyValue _stickyAmmo; - private StickyValue _stickyHp; - private int _trans; - - public TheDivisionModel(MainManager mainManager, TheDivisionSettings settings) : base(mainManager) - { - Settings = settings; - Name = "TheDivision"; - ProcessName = "TheDivision"; - Scale = 4; - Enabled = Settings.Enabled; - Initialized = false; - } - - public TheDivisionSettings Settings { get; set; } - - public int Scale { get; set; } - - public override void Dispose() - { - Initialized = false; - DllManager.RestoreDll(); - - _stickyAmmo.Dispose(); - _stickyHp.Dispose(); - } - - public override void Enable() - { - Initialized = false; - - _ammoWave = new Wave(new Point(30, 14), 0, Color.Transparent); - _hpRect = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 3*Scale, 0*Scale, - new List(), - LinearGradientMode.Horizontal) - { - Height = 7*Scale, - Width = 21*Scale, - Rotate = true, - ContainedBrush = false - }; - - _p2 = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0*Scale, 1*Scale, - new List(), - LinearGradientMode.Horizontal) - { - Height = 2*Scale, - Width = 3*Scale, - Rotate = true, - ContainedBrush = false - }; - _p3 = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0*Scale, 3*Scale, - new List(), - LinearGradientMode.Horizontal) - { - Height = 2*Scale, - Width = 3*Scale, - Rotate = true, - ContainedBrush = false - }; - _p4 = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0*Scale, 5*Scale, - new List(), - LinearGradientMode.Horizontal) - { - Height = 2*Scale, - Width = 3*Scale, - Rotate = true, - ContainedBrush = false - }; - - _stickyAmmo = new StickyValue(200); - _stickyHp = new StickyValue(200); - - DllManager.PlaceDll(); - _dataModel = new TheDivisionDataModel(); - for (var i = 1; i < 5; i++) - _dataModel.DivisionPlayers.Add(new DivisionPlayer(i)); - - MainManager.PipeServer.PipeMessage += PipeServerOnPipeMessage; - Initialized = true; - } - - private void PipeServerOnPipeMessage(string reply) - { - if (!Initialized) - return; - - // Convert the given string to a list of ints - var stringParts = reply.Split(' '); - var parts = new int[stringParts.Length]; - for (var i = 0; i < stringParts.Length; i++) - parts[i] = int.Parse(stringParts[i]); - - if (parts[0] == 1) - InterpertrateDivisionKey(parts); - } - - // Parses Division key data to game data - private void InterpertrateDivisionKey(int[] parts) - { - var keyCode = parts[1]; - var rPer = parts[2]; - var gPer = parts[3]; - var bPer = parts[4]; - - // F1 to F4 indicate the player and his party. Blinks red on damage taken - if (keyCode >= 59 && keyCode <= 62) - { - var playerId = keyCode - 58; - var playerDataModel = _dataModel.DivisionPlayers.FirstOrDefault(p => p.Id == playerId); - if (playerDataModel == null) - return; - - if (gPer > 10) - playerDataModel.PlayerState = PlayerState.Online; - else if (rPer > 10) - playerDataModel.PlayerState = PlayerState.Hit; - else - playerDataModel.PlayerState = PlayerState.Offline; - } - // R blinks white when low on ammo - else if (keyCode == 19) - { - _stickyAmmo.Value = rPer == 100 && gPer > 1 && bPer > 1; - _dataModel.LowAmmo = _stickyAmmo.Value; - } - // G turns white when holding a grenade, turns off when out of grenades - else if (keyCode == 34) - { - if (rPer == 100 && gPer < 10 && bPer < 10) - _dataModel.GrenadeState = GrenadeState.HasGrenade; - else if (rPer == 100 && gPer > 10 && bPer > 10) - _dataModel.GrenadeState = GrenadeState.GrenadeEquipped; - else - _dataModel.GrenadeState = GrenadeState.HasNoGrenade; - } - // V blinks on low HP - else if (keyCode == 47) - { - _stickyHp.Value = rPer == 100 && gPer > 1 && bPer > 1; - _dataModel.LowHp = _stickyHp.Value; - } - } - - public override void Update() - { - if (_dataModel.LowAmmo) - { - _ammoWave.Size++; - if (_ammoWave.Size > 30) - { - _ammoWave.Size = 0; - _trans = 255; - } - } - else - _ammoWave.Size = 0; - - _hpRect.Colors = _dataModel.LowHp - ? new List {Color.Red, Color.Orange} - : new List {Color.FromArgb(10, 255, 0), Color.FromArgb(80, 255, 45) }; - - if (_dataModel.DivisionPlayers[1].PlayerState == PlayerState.Offline) - _p2.Colors = new List {Color.Gray, Color.White}; - else if (_dataModel.DivisionPlayers[1].PlayerState == PlayerState.Online) - _p2.Colors = new List { Color.FromArgb(10, 255, 0), Color.FromArgb(80, 255, 45) }; - else - _p2.Colors = new List {Color.Red, Color.Orange}; - - if (_dataModel.DivisionPlayers[2].PlayerState == PlayerState.Offline) - _p3.Colors = new List {Color.Gray, Color.White}; - else if (_dataModel.DivisionPlayers[2].PlayerState == PlayerState.Online) - _p3.Colors = new List { Color.FromArgb(10, 255, 0), Color.FromArgb(80, 255, 45) }; - else - _p3.Colors = new List {Color.Red, Color.Orange}; - - if (_dataModel.DivisionPlayers[3].PlayerState == PlayerState.Offline) - _p4.Colors = new List {Color.Gray, Color.White}; - else if (_dataModel.DivisionPlayers[3].PlayerState == PlayerState.Online) - _p4.Colors = new List { Color.FromArgb(10, 255, 0), Color.FromArgb(80, 255, 45) }; - else - _p4.Colors = new List {Color.Red, Color.Orange}; - - if (!_dataModel.LowAmmo) - { - foreach (var corsairLed in CueSDK.MouseSDK.Leds) - corsairLed.Color = Color.Green; - } - else - { - foreach (var corsairLed in CueSDK.MouseSDK.Leds) - corsairLed.Color = Color.Red; - } - CueSDK.MouseSDK.Update(); - } - - public override Bitmap GenerateBitmap() - { - var bitmap = MainManager.KeyboardManager.ActiveKeyboard.KeyboardBitmap(Scale); - using (var g = Graphics.FromImage(bitmap)) - { - g.Clear(Color.Transparent); - _hpRect.Draw(g); - _p2.Draw(g); - _p3.Draw(g); - _p4.Draw(g); - // Very, very PH - if (_ammoWave.Size != 0) - { - var path = new GraphicsPath(); - path.AddEllipse(_ammoWave.Point.X - _ammoWave.Size/2, _ammoWave.Point.Y - _ammoWave.Size/2, - _ammoWave.Size, _ammoWave.Size); - - if (_ammoWave.Size > 15) - _trans = _trans - 16; - if (_trans < 1) - _trans = 255; - var pthGrBrush = new PathGradientBrush(path) - { - SurroundColors = new[] {_ammoWave.Color}, - CenterColor = Color.FromArgb(_trans, 255, 0, 0) - }; - - g.FillPath(pthGrBrush, path); - pthGrBrush.FocusScales = new PointF(0.3f, 0.8f); - - g.FillPath(pthGrBrush, path); - g.DrawEllipse(new Pen(pthGrBrush, 1), _ammoWave.Point.X - _ammoWave.Size/2, - _ammoWave.Point.Y - _ammoWave.Size/2, _ammoWave.Size, _ammoWave.Size); - } - } - return bitmap; - } - } +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using Artemis.Managers; +using Artemis.Models; +using Artemis.Modules.Effects.TypeWave; +using Artemis.Utilities; +using Artemis.Utilities.Keyboard; +using Artemis.Utilities.LogitechDll; + +namespace Artemis.Modules.Games.TheDivision +{ + public class TheDivisionModel : GameModel + { + private Wave _ammoWave; + private TheDivisionDataModel _dataModel; + private KeyboardRectangle _hpRect; + private KeyboardRectangle _p2; + private KeyboardRectangle _p3; + private KeyboardRectangle _p4; + private StickyValue _stickyAmmo; + private StickyValue _stickyHp; + private int _trans; + + public TheDivisionModel(MainManager mainManager, TheDivisionSettings settings) : base(mainManager) + { + Settings = settings; + Name = "TheDivision"; + ProcessName = "TheDivision"; + Scale = 4; + Enabled = Settings.Enabled; + Initialized = false; + } + + public TheDivisionSettings Settings { get; set; } + + public int Scale { get; set; } + + public override void Dispose() + { + Initialized = false; + DllManager.RestoreDll(); + + _stickyAmmo.Dispose(); + _stickyHp.Dispose(); + } + + public override void Enable() + { + Initialized = false; + + _ammoWave = new Wave(new Point(30, 14), 0, Color.Transparent); + _hpRect = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 3*Scale, 0*Scale, + new List(), + LinearGradientMode.Horizontal) + { + Height = 7*Scale, + Width = 21*Scale, + Rotate = true, + ContainedBrush = false + }; + + _p2 = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0*Scale, 1*Scale, + new List(), + LinearGradientMode.Horizontal) + { + Height = 2*Scale, + Width = 3*Scale, + Rotate = true, + ContainedBrush = false + }; + _p3 = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0*Scale, 3*Scale, + new List(), + LinearGradientMode.Horizontal) + { + Height = 2*Scale, + Width = 3*Scale, + Rotate = true, + ContainedBrush = false + }; + _p4 = new KeyboardRectangle(MainManager.KeyboardManager.ActiveKeyboard, 0*Scale, 5*Scale, + new List(), + LinearGradientMode.Horizontal) + { + Height = 2*Scale, + Width = 3*Scale, + Rotate = true, + ContainedBrush = false + }; + + _stickyAmmo = new StickyValue(200); + _stickyHp = new StickyValue(200); + + DllManager.PlaceDll(); + _dataModel = new TheDivisionDataModel(); + + MainManager.PipeServer.PipeMessage += PipeServerOnPipeMessage; + Initialized = true; + } + + private void PipeServerOnPipeMessage(string reply) + { + if (!Initialized) + return; + + // Convert the given string to a list of ints + var stringParts = reply.Split(' '); + var parts = new int[stringParts.Length]; + for (var i = 0; i < stringParts.Length; i++) + parts[i] = int.Parse(stringParts[i]); + + if (parts[0] == 1) + InterpertrateDivisionKey(parts); + } + + // Parses Division key data to game data + private void InterpertrateDivisionKey(IReadOnlyList parts) + { + var keyCode = parts[1]; + var rPer = parts[2]; + var gPer = parts[3]; + var bPer = parts[4]; + + // F1 to F4 indicate the player and his party. Blinks red on damage taken + if (keyCode >= 59 && keyCode <= 62) + { + var playerId = keyCode - 58; + + PlayerState newState; + if (gPer > 10) + newState = PlayerState.Online; + else if (rPer > 10) + newState = PlayerState.Hit; + else + newState = PlayerState.Offline; + + if (playerId == 1) + _dataModel.PartyMember1 = newState; + else if (playerId == 2) + _dataModel.PartyMember2 = newState; + else if (playerId == 3) + _dataModel.PartyMember3 = newState; + } + // R blinks white when low on ammo + else if (keyCode == 19) + { + _stickyAmmo.Value = rPer == 100 && gPer > 1 && bPer > 1; + _dataModel.LowAmmo = _stickyAmmo.Value; + } + // G turns white when holding a grenade, turns off when out of grenades + else if (keyCode == 34) + { + if (rPer == 100 && gPer < 10 && bPer < 10) + _dataModel.GrenadeState = GrenadeState.HasGrenade; + else if (rPer == 100 && gPer > 10 && bPer > 10) + _dataModel.GrenadeState = GrenadeState.GrenadeEquipped; + else + _dataModel.GrenadeState = GrenadeState.HasNoGrenade; + } + // V blinks on low HP + else if (keyCode == 47) + { + _stickyHp.Value = rPer == 100 && gPer > 1 && bPer > 1; + _dataModel.LowHp = _stickyHp.Value; + } + } + + public override void Update() + { + if (_dataModel.LowAmmo) + { + _ammoWave.Size++; + if (_ammoWave.Size > 30) + { + _ammoWave.Size = 0; + _trans = 255; + } + } + else + _ammoWave.Size = 0; + + _hpRect.Colors = _dataModel.LowHp + ? new List {Color.Red, Color.Orange} + : new List {Color.FromArgb(10, 255, 0), Color.FromArgb(80, 255, 45)}; + + if (_dataModel.PartyMember1 == PlayerState.Offline) + _p2.Colors = new List {Color.Gray, Color.White}; + else if (_dataModel.PartyMember1 == PlayerState.Online) + _p2.Colors = new List {Color.FromArgb(10, 255, 0), Color.FromArgb(80, 255, 45)}; + else + _p2.Colors = new List {Color.Red, Color.Orange}; + + if (_dataModel.PartyMember2 == PlayerState.Offline) + _p3.Colors = new List {Color.Gray, Color.White}; + else if (_dataModel.PartyMember2 == PlayerState.Online) + _p3.Colors = new List {Color.FromArgb(10, 255, 0), Color.FromArgb(80, 255, 45)}; + else + _p3.Colors = new List {Color.Red, Color.Orange}; + + if (_dataModel.PartyMember3 == PlayerState.Offline) + _p4.Colors = new List {Color.Gray, Color.White}; + else if (_dataModel.PartyMember3 == PlayerState.Online) + _p4.Colors = new List {Color.FromArgb(10, 255, 0), Color.FromArgb(80, 255, 45)}; + else + _p4.Colors = new List {Color.Red, Color.Orange}; + } + + public override Bitmap GenerateBitmap() + { + var bitmap = MainManager.KeyboardManager.ActiveKeyboard.KeyboardBitmap(Scale); + using (var g = Graphics.FromImage(bitmap)) + { + g.Clear(Color.Transparent); + _hpRect.Draw(g); + _p2.Draw(g); + _p3.Draw(g); + _p4.Draw(g); + // Very, very PH + if (_ammoWave.Size != 0) + { + var path = new GraphicsPath(); + path.AddEllipse(_ammoWave.Point.X - _ammoWave.Size/2, _ammoWave.Point.Y - _ammoWave.Size/2, + _ammoWave.Size, _ammoWave.Size); + + if (_ammoWave.Size > 15) + _trans = _trans - 16; + if (_trans < 1) + _trans = 255; + var pthGrBrush = new PathGradientBrush(path) + { + SurroundColors = new[] {_ammoWave.Color}, + CenterColor = Color.FromArgb(_trans, 255, 0, 0) + }; + + g.FillPath(pthGrBrush, path); + pthGrBrush.FocusScales = new PointF(0.3f, 0.8f); + + g.FillPath(pthGrBrush, path); + g.DrawEllipse(new Pen(pthGrBrush, 1), _ammoWave.Point.X - _ammoWave.Size/2, + _ammoWave.Point.Y - _ammoWave.Size/2, _ammoWave.Size, _ammoWave.Size); + } + } + return bitmap; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionSettings.cs b/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionSettings.cs index 8eaf0f65c..ee1f005ea 100644 --- a/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionSettings.cs +++ b/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionSettings.cs @@ -1,29 +1,29 @@ -using Artemis.Models; - -namespace Artemis.Modules.Games.TheDivision -{ - public class TheDivisionSettings : GameSettings - { - public TheDivisionSettings() - { - Load(); - } - - public sealed override void Load() - { - Enabled = TheDivision.Default.Enabled; - } - - public sealed override void Save() - { - TheDivision.Default.Enabled = Enabled; - - TheDivision.Default.Save(); - } - - public sealed override void ToDefault() - { - Enabled = true; - } - } +using Artemis.Models; + +namespace Artemis.Modules.Games.TheDivision +{ + public class TheDivisionSettings : GameSettings + { + public TheDivisionSettings() + { + Load(); + } + + public sealed override void Load() + { + Enabled = TheDivision.Default.Enabled; + } + + public sealed override void Save() + { + TheDivision.Default.Enabled = Enabled; + + TheDivision.Default.Save(); + } + + public sealed override void ToDefault() + { + Enabled = true; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionView.xaml b/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionView.xaml index 5bd90ab14..f1ece3e0d 100644 --- a/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionView.xaml +++ b/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionView.xaml @@ -7,48 +7,52 @@ xmlns:cal="http://www.caliburnproject.org" mc:Ignorable="d" d:DesignHeight="416.495" d:DesignWidth="553.608"> - - - - - - - - - - - - - - - - - - - - Note: For this game to work with Artemis, please open up your Division settings, navigate to 3rd Party and set LED keyboard support to Yes. (This only works if you have Artemis running before starting the game) - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/ColorHelpers.cs b/Artemis/Artemis/Utilities/ColorHelpers.cs index 7d2654773..bdefa0ec5 100644 --- a/Artemis/Artemis/Utilities/ColorHelpers.cs +++ b/Artemis/Artemis/Utilities/ColorHelpers.cs @@ -1,83 +1,100 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; - -namespace Artemis.Utilities -{ - public static class ColorHelpers - { - /// - /// Comes up with a 'pure' psuedo-random color - /// - /// The color - public static Color GetRandomRainbowColor() - { - var colors = new List(); - var rand = new Random(); - for (var i = 0; i < 3; i++) - colors.Add(rand.Next(0, 256)); - - var highest = colors.Max(); - var lowest = colors.Min(); - colors[colors.FindIndex(c => c == highest)] = 255; - colors[colors.FindIndex(c => c == lowest)] = 0; - - var returnColor = Color.FromArgb(255, colors[0], colors[1], colors[2]); - - return returnColor; - } - - public static Color ShiftColor(Color c, int shiftAmount) - { - int newRed = c.R; - int newGreen = c.G; - int newBlue = c.B; - - // Red to purple - if (c.R == 255 && c.B < 255 && c.G == 0) - newBlue = newBlue + shiftAmount; - // Purple to blue - else if (c.B == 255 && c.R > 0) - newRed = newRed - shiftAmount; - // Blue to light-blue - else if (c.B == 255 && c.G < 255) - newGreen = newGreen + shiftAmount; - // Light-blue to green - else if (c.G == 255 && c.B > 0) - newBlue = newBlue - shiftAmount; - // Green to yellow - else if (c.G == 255 && c.R < 255) - newRed = newRed + shiftAmount; - // Yellow to red - else if (c.R == 255 && c.G > 0) - newGreen = newGreen - shiftAmount; - - newRed = BringIntInColorRange(newRed); - newGreen = BringIntInColorRange(newGreen); - newBlue = BringIntInColorRange(newBlue); - - return Color.FromArgb(c.A, newRed, newGreen, newBlue); - } - - private static int BringIntInColorRange(int i) - { - if (i < 0) - return 0; - if (i > 255) - return 255; - - return i; - } - - public static Color ToDrawingColor(System.Windows.Media.Color mColor) - { - return Color.FromArgb(mColor.A, mColor.R, mColor.G, mColor.B); - } - - public static System.Windows.Media.Color ToMediaColor(Color dColor) - { - return System.Windows.Media.Color.FromArgb(dColor.A, dColor.R, dColor.G, dColor.B); - } - } +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; + +namespace Artemis.Utilities +{ + public static class ColorHelpers + { + /// + /// Comes up with a 'pure' psuedo-random color + /// + /// The color + public static Color GetRandomRainbowColor() + { + var colors = new List(); + var rand = new Random(); + for (var i = 0; i < 3; i++) + colors.Add(rand.Next(0, 256)); + + var highest = colors.Max(); + var lowest = colors.Min(); + colors[colors.FindIndex(c => c == highest)] = 255; + colors[colors.FindIndex(c => c == lowest)] = 0; + + var returnColor = Color.FromArgb(255, colors[0], colors[1], colors[2]); + + return returnColor; + } + + public static System.Windows.Media.Color GetRandomRainbowMediaColor() + { + var colors = new List(); + var rand = new Random(); + for (var i = 0; i < 3; i++) + colors.Add((byte) rand.Next(0, 256)); + + var highest = colors.Max(); + var lowest = colors.Min(); + colors[colors.FindIndex(c => c == highest)] = 255; + colors[colors.FindIndex(c => c == lowest)] = 0; + + var returnColor = System.Windows.Media.Color.FromArgb(255, colors[0], colors[1], colors[2]); + + return returnColor; + } + + public static Color ShiftColor(Color c, int shiftAmount) + { + int newRed = c.R; + int newGreen = c.G; + int newBlue = c.B; + + // Red to purple + if (c.R == 255 && c.B < 255 && c.G == 0) + newBlue = newBlue + shiftAmount; + // Purple to blue + else if (c.B == 255 && c.R > 0) + newRed = newRed - shiftAmount; + // Blue to light-blue + else if (c.B == 255 && c.G < 255) + newGreen = newGreen + shiftAmount; + // Light-blue to green + else if (c.G == 255 && c.B > 0) + newBlue = newBlue - shiftAmount; + // Green to yellow + else if (c.G == 255 && c.R < 255) + newRed = newRed + shiftAmount; + // Yellow to red + else if (c.R == 255 && c.G > 0) + newGreen = newGreen - shiftAmount; + + newRed = BringIntInColorRange(newRed); + newGreen = BringIntInColorRange(newGreen); + newBlue = BringIntInColorRange(newBlue); + + return Color.FromArgb(c.A, newRed, newGreen, newBlue); + } + + private static int BringIntInColorRange(int i) + { + if (i < 0) + return 0; + if (i > 255) + return 255; + + return i; + } + + public static Color ToDrawingColor(System.Windows.Media.Color mColor) + { + return Color.FromArgb(mColor.A, mColor.R, mColor.G, mColor.B); + } + + public static System.Windows.Media.Color ToMediaColor(Color dColor) + { + return System.Windows.Media.Color.FromArgb(dColor.A, dColor.R, dColor.G, dColor.B); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/ExtensionMethods.cs b/Artemis/Artemis/Utilities/ExtensionMethods.cs new file mode 100644 index 000000000..16d37edd9 --- /dev/null +++ b/Artemis/Artemis/Utilities/ExtensionMethods.cs @@ -0,0 +1,74 @@ +using System.Text.RegularExpressions; + +namespace Artemis.Utilities +{ + public static class ExtensionMethods + { + #region String + + /// + /// Takes a string LikeThisOne and turns it into Like This One. + /// ZombieSheep - http://stackoverflow.com/a/5796793/5015269 + /// + /// + /// + public static string SplitCamelCase(this string str) + { + return Regex.Replace(Regex.Replace(str, @"(\P{Ll})(\P{Ll}\p{Ll})", "$1 $2"), @"(\p{Ll})(\P{Ll})", "$1 $2"); + } + + #endregion + + #region Color + + // TODO: Convert ColorHelpers to ExtensionMethods + + #endregion + + #region Reflection + + /// + /// Gets a value by path + /// jheddings - http://stackoverflow.com/a/1954663/5015269 + /// + /// + /// Path, such as "TimeOfDay.Minutes" + /// + public static object GetPropValue(this object obj, string name) + { + foreach (var part in name.Split('.')) + { + if (obj == null) + return null; + + var type = obj.GetType(); + var info = type.GetProperty(part); + if (info == null) + return null; + + obj = info.GetValue(obj, null); + } + return obj; + } + + /// + /// Gets a value by path + /// jheddings - http://stackoverflow.com/a/1954663/5015269 + /// + /// + /// + /// + /// + public static T GetPropValue(this object obj, string name) + { + var retVal = GetPropValue(obj, name); + if (retVal == null) + return default(T); + + // throws InvalidCastException if types are incompatible + return (T) retVal; + } + + #endregion + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/GameState/GameDataReceivedEventArgs.cs b/Artemis/Artemis/Utilities/GameState/GameDataReceivedEventArgs.cs index 9352fe3ee..c24f92de0 100644 --- a/Artemis/Artemis/Utilities/GameState/GameDataReceivedEventArgs.cs +++ b/Artemis/Artemis/Utilities/GameState/GameDataReceivedEventArgs.cs @@ -1,14 +1,14 @@ -using System; - -namespace Artemis.Utilities.GameState -{ - public class GameDataReceivedEventArgs : EventArgs - { - public GameDataReceivedEventArgs(object json) - { - Json = json; - } - - public object Json { get; set; } - } +using System; + +namespace Artemis.Utilities.GameState +{ + public class GameDataReceivedEventArgs : EventArgs + { + public GameDataReceivedEventArgs(object json) + { + Json = json; + } + + public object Json { get; set; } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/GameState/GameStateWebServer.cs b/Artemis/Artemis/Utilities/GameState/GameStateWebServer.cs index bfddd675b..44a39c4c4 100644 --- a/Artemis/Artemis/Utilities/GameState/GameStateWebServer.cs +++ b/Artemis/Artemis/Utilities/GameState/GameStateWebServer.cs @@ -1,7 +1,6 @@ using System; using System.IO; using System.Net; -using System.Text; using System.Threading; using System.Windows.Forms; using Artemis.Settings; @@ -9,12 +8,18 @@ using Newtonsoft.Json; namespace Artemis.Utilities.GameState { + /// + /// Listens for JSON calls, parses them and raises an event. + /// Includes some code from https://github.com/rakijah/CSGSI + /// public class GameStateWebServer { public delegate void GameDataReceivedEventHandler( object sender, GameDataReceivedEventArgs gameDataReceivedEventArgs); - private readonly HttpListener _listener = new HttpListener(); + private readonly AutoResetEvent _waitForConnection = new AutoResetEvent(false); + + private HttpListener _listener; public GameStateWebServer() { @@ -31,64 +36,69 @@ namespace Artemis.Utilities.GameState if (Running) return; + Port = General.Default.GamestatePort; + + _listener = new HttpListener(); + _listener.Prefixes.Add($"http://localhost:{Port}/"); + var listenerThread = new Thread(ListenerRun); try { - _listener.Prefixes.Clear(); - Port = General.Default.GamestatePort; - _listener.Prefixes.Add($"http://localhost:{Port}/"); - _listener.Start(); } - catch (Exception) + catch (HttpListenerException) { - MessageBox.Show("Couldn't start the webserver. CS:GO/Dota2 effects won't work :c \n\nTry changing the port in Settings and restart Artemis."); + MessageBox.Show( + "Couldn't start the webserver. CS:GO/Dota2 effects won't work :c \n\nTry changing the port in Settings and restart Artemis."); } - ThreadPool.QueueUserWorkItem(o => - { - try - { - while (_listener.IsListening) - { - ThreadPool.QueueUserWorkItem(c => - { - var ctx = c as HttpListenerContext; - if (ctx == null) - return; - try - { - var rstr = HandleRequest(ctx.Request); - var buf = Encoding.UTF8.GetBytes(rstr); - ctx.Response.ContentLength64 = buf.Length; - ctx.Response.OutputStream.Write(buf, 0, buf.Length); - } - catch - { - // ignored - } - finally - { - // always close the stream - ctx.Response.OutputStream.Close(); - } - }, _listener.GetContext()); - } - } - catch - { - // ignored - } - }); - Running = true; + listenerThread.Start(); + } + + private void ListenerRun() + { + while (Running) + { + _listener.BeginGetContext(HandleRequest, _listener); + _waitForConnection.WaitOne(); + _waitForConnection.Reset(); + } + } + + private void HandleRequest(IAsyncResult ar) + { + HttpListenerContext context = null; + try + { + context = _listener.EndGetContext(ar); + } + catch (ObjectDisposedException) + { + // Listener was Closed due to call of Stop(); + } + catch (HttpListenerException) + { + // Listener was Closed due to call of Stop(); + } + finally + { + _waitForConnection.Set(); + } + + if (context != null) + { + HandleRequest(context.Request); + context.Response.OutputStream.Close(); + } } public void Stop() { - _listener.Stop(); + _listener.Close(); + Running = false; } - private string HandleRequest(HttpListenerRequest request) + private void HandleRequest(HttpListenerRequest request) { object json; using (var reader = new StreamReader(request.InputStream, request.ContentEncoding)) @@ -99,7 +109,6 @@ namespace Artemis.Utilities.GameState if (json != null) OnGameDataReceived(new GameDataReceivedEventArgs(json)); - return JsonConvert.SerializeObject(json); } protected virtual void OnGameDataReceived(GameDataReceivedEventArgs e) diff --git a/Artemis/Artemis/Utilities/GeneralHelpers.cs b/Artemis/Artemis/Utilities/GeneralHelpers.cs index b83ed3751..25fd04a0e 100644 --- a/Artemis/Artemis/Utilities/GeneralHelpers.cs +++ b/Artemis/Artemis/Utilities/GeneralHelpers.cs @@ -1,12 +1,15 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; -using System.Linq; +using System.IO; using System.Reflection; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; using System.Security.Principal; -using System.Text; -using System.Threading.Tasks; using System.Windows; +using System.Xml.Serialization; +using static System.String; namespace Artemis.Utilities { @@ -37,12 +40,108 @@ namespace Artemis.Utilities Environment.Exit(0); } - public static bool IsRunAsAdministrator() - { - var wi = WindowsIdentity.GetCurrent(); - var wp = new WindowsPrincipal(wi); - - return wp.IsInRole(WindowsBuiltInRole.Administrator); + public static bool IsRunAsAdministrator() + { + var wi = WindowsIdentity.GetCurrent(); + var wp = new WindowsPrincipal(wi); + + return wp.IsInRole(WindowsBuiltInRole.Administrator); + } + + public static void CopyProperties(object dest, object src) + { + foreach (PropertyDescriptor item in TypeDescriptor.GetProperties(src)) + { + item.SetValue(dest, item.GetValue(src)); + } + } + + /// + /// Perform a deep Copy of the object. + /// + /// The type of object being copied. + /// The object instance to copy. + /// The copied object. + public static T Clone(T source) + { + // Don't serialize a null object, simply return the default for that object + if (ReferenceEquals(source, null)) + return default(T); + + var serializer = new XmlSerializer(typeof(T)); + Stream stream = new MemoryStream(); + using (stream) + { + serializer.Serialize(stream, source); + stream.Seek(0, SeekOrigin.Begin); + return (T)serializer.Deserialize(stream); + } + } + + public static object GetPropertyValue(object o, string path) + { + var propertyNames = path.Split('.'); + var value = o.GetType().GetProperty(propertyNames[0]).GetValue(o, null); + + if (propertyNames.Length == 1 || value == null) + return value; + return GetPropertyValue(value, path.Replace(propertyNames[0] + ".", "")); + } + + public static List GenerateTypeMap(object o) => GenerateTypeMap(o.GetType().GetProperties()); + public static List GenerateTypeMap() => GenerateTypeMap(typeof (T).GetProperties()); + + private static List GenerateTypeMap(IEnumerable getProperties, + string path = "") + { + var list = new List(); + foreach (var propertyInfo in getProperties) + { + var friendlyName = Empty; + if (propertyInfo.PropertyType.Name == "Int32") + friendlyName = "(Number)"; + else if (propertyInfo.PropertyType.Name == "String") + friendlyName = "(Text)"; + if (propertyInfo.PropertyType.BaseType?.Name == "Enum") + friendlyName = "(Choice)"; + + var parent = new PropertyCollection + { + Type = propertyInfo.PropertyType.Name, + DisplayType = friendlyName, + Display = $"{path.Replace(".", " → ")}{propertyInfo.Name}", + Path = $"{path}{propertyInfo.Name}" + }; + + if (propertyInfo.PropertyType.BaseType?.Name == "Enum") + { + parent.EnumValues = Enum.GetNames(propertyInfo.PropertyType); + parent.Type = "Enum"; + } + + if (friendlyName != Empty) + list.Add(parent); + + if (propertyInfo.PropertyType.Name != "String") + list.AddRange(GenerateTypeMap(propertyInfo.PropertyType.GetProperties(), + path + $"{propertyInfo.Name}.")); + } + return list; + } + + public struct PropertyCollection + { + public string Display { get; set; } + public string Path { get; set; } + public string Type { get; set; } + + /// + /// Only used if Type is an enumerable + /// + public string[] EnumValues { get; set; } + + public List Children { get; set; } + public string DisplayType { get; set; } } } -} +} \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/ImageUtilities.cs b/Artemis/Artemis/Utilities/ImageUtilities.cs index 464bffc17..8aead1b5f 100644 --- a/Artemis/Artemis/Utilities/ImageUtilities.cs +++ b/Artemis/Artemis/Utilities/ImageUtilities.cs @@ -1,54 +1,16 @@ using System; -using System.Collections.Generic; using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; +using System.IO; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using PixelFormat = System.Drawing.Imaging.PixelFormat; namespace Artemis.Utilities { internal class ImageUtilities { - private static Dictionary encoders; - - /// - /// A lock to prevent concurrency issues loading the encoders. - /// - private static readonly object encodersLock = new object(); - - /// - /// A quick lookup for getting image encoders - /// - public static Dictionary Encoders - { - //get accessor that creates the dictionary on demand - get - { - //if the quick lookup isn't initialised, initialise it - if (encoders == null) - { - //protect against concurrency issues - lock (encodersLock) - { - //check again, we might not have been the first person to acquire the lock (see the double checked lock pattern) - if (encoders == null) - { - encoders = new Dictionary(); - - //get all the codecs - foreach (var codec in ImageCodecInfo.GetImageEncoders()) - { - //add each codec to the quick lookup - encoders.Add(codec.MimeType.ToLower(), codec); - } - } - } - } - - //return the lookup - return encoders; - } - } - /// /// Resize the image to the specified width and height. /// @@ -73,5 +35,46 @@ namespace Artemis.Utilities //return the resulting bitmap return result; } + + public static Bitmap BitmapSourceToBitmap(BitmapSource srs) + { + var width = srs.PixelWidth; + var height = srs.PixelHeight; + var stride = width*((srs.Format.BitsPerPixel + 7)/8); + var ptr = IntPtr.Zero; + try + { + ptr = Marshal.AllocHGlobal(height*stride); + srs.CopyPixels(new Int32Rect(0, 0, width, height), ptr, height*stride, stride); + using (var btm = new Bitmap(width, height, stride, PixelFormat.Format1bppIndexed, ptr)) + { + // Clone the bitmap so that we can dispose it and + // release the unmanaged memory at ptr + return new Bitmap(btm); + } + } + finally + { + if (ptr != IntPtr.Zero) + Marshal.FreeHGlobal(ptr); + } + } + + public static Bitmap DrawinVisualToBitmap(DrawingVisual visual, Rect rect) + { + var bmp = new RenderTargetBitmap((int) rect.Width, (int) rect.Height, 96, 96, PixelFormats.Pbgra32); + bmp.Render(visual); + + var encoder = new PngBitmapEncoder(); + encoder.Frames.Add(BitmapFrame.Create(bmp)); + + Bitmap bitmap; + using (var stream = new MemoryStream()) + { + encoder.Save(stream); + bitmap = new Bitmap(stream); + } + return bitmap; + } } } \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/Keyboard/Key.cs b/Artemis/Artemis/Utilities/Keyboard/Key.cs index 269f9d2e0..d671ac13c 100644 --- a/Artemis/Artemis/Utilities/Keyboard/Key.cs +++ b/Artemis/Artemis/Utilities/Keyboard/Key.cs @@ -1,18 +1,18 @@ -using System.Windows.Forms; - -namespace Artemis.Utilities.Keyboard -{ - public class Key - { - public Key(Keys keyCode, int posX, int posY) - { - KeyCode = keyCode; - PosX = posX; - PosY = posY; - } - - public Keys KeyCode { get; set; } - public int PosX { get; set; } - public int PosY { get; set; } - } +using System.Windows.Forms; + +namespace Artemis.Utilities.Keyboard +{ + public class Key + { + public Key(Keys keyCode, int posX, int posY) + { + KeyCode = keyCode; + PosX = posX; + PosY = posY; + } + + public Keys KeyCode { get; set; } + public int PosX { get; set; } + public int PosY { get; set; } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/Keyboard/KeyboardHook.cs b/Artemis/Artemis/Utilities/Keyboard/KeyboardHook.cs index ddac34a73..eca41626a 100644 --- a/Artemis/Artemis/Utilities/Keyboard/KeyboardHook.cs +++ b/Artemis/Artemis/Utilities/Keyboard/KeyboardHook.cs @@ -1,24 +1,24 @@ -using System.Threading.Tasks; -using System.Windows.Forms; -using VirtualInput; - -namespace Artemis.Utilities.Keyboard -{ - public class KeyboardHook - { - public delegate void KeyDownCallbackHandler(KeyEventArgs e); - - public KeyboardHook() - { - VirtualKeyboard.KeyDown += VirtualKeyboardOnKeyDown; - VirtualKeyboard.StartInterceptor(); - } - - private void VirtualKeyboardOnKeyDown(object sender, KeyEventArgs keyEventArgs) - { - Task.Factory.StartNew(() => { KeyDownCallback?.Invoke(keyEventArgs); }); - } - - public event KeyDownCallbackHandler KeyDownCallback; - } +using System.Threading.Tasks; +using System.Windows.Forms; +using VirtualInput; + +namespace Artemis.Utilities.Keyboard +{ + public class KeyboardHook + { + public delegate void KeyDownCallbackHandler(KeyEventArgs e); + + public KeyboardHook() + { + VirtualKeyboard.KeyDown += VirtualKeyboardOnKeyDown; + VirtualKeyboard.StartInterceptor(); + } + + private void VirtualKeyboardOnKeyDown(object sender, KeyEventArgs keyEventArgs) + { + Task.Factory.StartNew(() => { KeyDownCallback?.Invoke(keyEventArgs); }); + } + + public event KeyDownCallbackHandler KeyDownCallback; + } } \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/Keyboard/KeyboardRectangle.cs b/Artemis/Artemis/Utilities/Keyboard/KeyboardRectangle.cs index 38668e097..16c351d89 100644 --- a/Artemis/Artemis/Utilities/Keyboard/KeyboardRectangle.cs +++ b/Artemis/Artemis/Utilities/Keyboard/KeyboardRectangle.cs @@ -1,194 +1,194 @@ -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Artemis.KeyboardProviders; - -namespace Artemis.Utilities.Keyboard -{ - public class KeyboardRectangle - { - private readonly BackgroundWorker _blinkWorker = new BackgroundWorker {WorkerSupportsCancellation = true}; - private readonly KeyboardProvider _keyboard; - private int _blinkDelay; - private double _rotationProgress; - - /// - /// Represents a Rectangle on the keyboard which can be drawn to a Bitmap. - /// By default, a rectangle is the entire keyboard's size. - /// - /// The keyboard this rectangle will be used for - /// - /// - /// An array of colors the ColorBlend will use - /// - public KeyboardRectangle(KeyboardProvider keyboard, int x, int y, List colors, - LinearGradientMode gradientMode) - { - _keyboard = keyboard; - _rotationProgress = 0; - _blinkWorker.DoWork += BlinkWorker_DoWork; - - Scale = 4; - X = x; - Y = y; - Width = keyboard.Width*Scale; - Height = keyboard.Height*Scale; - Visible = true; - Opacity = 255; - - ContainedBrush = true; - GradientMode = gradientMode; - Rotate = false; - LoopSpeed = 1; - Colors = colors; - } - - public int X { get; set; } - public int Y { get; set; } - public int Width { get; set; } - public int Height { get; set; } - public bool Visible { get; set; } - public byte Opacity { get; set; } // TODO: Remove - - /// - /// Sets wether or not the colors should be contained within the rectangle, or span the entire keyboard. - /// - public bool ContainedBrush { get; set; } - - /// - /// Used when ContainedBrush is set to false to make sure the colors span the entire keyboard on a higher scale. - /// - public int Scale { get; set; } - - /// - /// Determines what grientmode to use in the LinearGradientBrush. - /// - public LinearGradientMode GradientMode { get; set; } - - /// - /// Wether or not to rotate the colors over the brush. - /// - public bool Rotate { get; set; } - - /// - /// What speed to ratate the colors on. - /// - public double LoopSpeed { get; set; } - - /// - /// Colors used on the brush. - /// - public List Colors { get; set; } - - public void StartBlink(int delay) - { - _blinkDelay = delay; - - if (!_blinkWorker.IsBusy) - _blinkWorker.RunWorkerAsync(); - } - - public void StartBlink(int delay, int time) - { - StartBlink(delay); - Task.Factory.StartNew(() => - { - Thread.Sleep(delay); - StopBlink(); - }); - } - - public void StopBlink() - { - if (_blinkWorker.IsBusy) - _blinkWorker.CancelAsync(); - } - - private void BlinkWorker_DoWork(object sender, DoWorkEventArgs e) - { - while (!_blinkWorker.CancellationPending) - { - Thread.Sleep(_blinkDelay); - Visible = !Visible; - } - Visible = true; - } - - public void Draw(Graphics g) - { - if (!Visible || Height < 1 || Width < 1 || !Colors.Any()) - return; - - var brush = CreateBrush(); - var baseRect = new Rectangle(X, Y, Width, Height); - - g.FillRectangle(brush, baseRect); - if (!Rotate) - return; - - _rotationProgress = _rotationProgress + LoopSpeed; - if (ContainedBrush && _rotationProgress > Width) - _rotationProgress = LoopSpeed; - else if (!ContainedBrush && _rotationProgress > _keyboard.Width*Scale) - _rotationProgress = LoopSpeed; - } - - private LinearGradientBrush CreateBrush() - { - var colorBlend = CreateColorBlend(); - RectangleF rect; - if (Rotate) - rect = ContainedBrush - ? new Rectangle((int) _rotationProgress, Y, Width*2, Height*2) - : new Rectangle((int) _rotationProgress, 0, _keyboard.Width*Scale*2, _keyboard.Height*Scale*2); - else - rect = ContainedBrush - ? new Rectangle(X, Y, Width, Height) - : new Rectangle(0, 0, _keyboard.Width*Scale, _keyboard.Height*Scale); - - return new LinearGradientBrush(rect, Color.Transparent, Color.Transparent, GradientMode) - { - InterpolationColors = colorBlend - }; - } - - private ColorBlend CreateColorBlend() - { - if (Colors.Count == 1) - return new ColorBlend {Colors = new[] {Colors[0], Colors[0]}, Positions = new[] {0F, 1F}}; - var colorBlend = Rotate - ? new ColorBlend {Colors = CreateTilebleColors(Colors).ToArray()} - : new ColorBlend {Colors = Colors.ToArray()}; - - // If needed, apply opacity to the colors in the blend - if (Opacity < 255) - for (var i = 0; i < colorBlend.Colors.Length; i++) - colorBlend.Colors[i] = Color.FromArgb(Opacity, colorBlend.Colors[i]); - - // Devide the colors over the colorblend - var devider = (float) colorBlend.Colors.Length - 1; - var positions = new List(); - for (var i = 0; i < colorBlend.Colors.Length; i++) - positions.Add(i/devider); - - // Apply the devided positions - colorBlend.Positions = positions.ToArray(); - return colorBlend; - } - - private List CreateTilebleColors(List sourceColors) - { - // Create a list using the original colors - var tilebleColors = new List(sourceColors); - // Add the original colors again - tilebleColors.AddRange(sourceColors); - // Add the first color, smoothing the transition - tilebleColors.Add(sourceColors.FirstOrDefault()); - return tilebleColors; - } - } +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Artemis.KeyboardProviders; + +namespace Artemis.Utilities.Keyboard +{ + public class KeyboardRectangle + { + private readonly BackgroundWorker _blinkWorker = new BackgroundWorker {WorkerSupportsCancellation = true}; + private readonly KeyboardProvider _keyboard; + private int _blinkDelay; + private double _rotationProgress; + + /// + /// Represents a Rectangle on the keyboard which can be drawn to a Bitmap. + /// By default, a rectangle is the entire keyboard's size. + /// + /// The keyboard this rectangle will be used for + /// + /// + /// An array of colors the ColorBlend will use + /// + public KeyboardRectangle(KeyboardProvider keyboard, int x, int y, List colors, + LinearGradientMode gradientMode) + { + _keyboard = keyboard; + _rotationProgress = 0; + _blinkWorker.DoWork += BlinkWorker_DoWork; + + Scale = 4; + X = x; + Y = y; + Width = keyboard.Width*Scale; + Height = keyboard.Height*Scale; + Visible = true; + Opacity = 255; + + ContainedBrush = true; + GradientMode = gradientMode; + Rotate = false; + LoopSpeed = 1; + Colors = colors; + } + + public int X { get; set; } + public int Y { get; set; } + public int Width { get; set; } + public int Height { get; set; } + public bool Visible { get; set; } + public byte Opacity { get; set; } // TODO: Remove + + /// + /// Sets wether or not the colors should be contained within the rectangle, or span the entire keyboard. + /// + public bool ContainedBrush { get; set; } + + /// + /// Used when ContainedBrush is set to false to make sure the colors span the entire keyboard on a higher scale. + /// + public int Scale { get; set; } + + /// + /// Determines what grientmode to use in the LinearGradientBrush. + /// + public LinearGradientMode GradientMode { get; set; } + + /// + /// Wether or not to rotate the colors over the brush. + /// + public bool Rotate { get; set; } + + /// + /// What speed to ratate the colors on. + /// + public double LoopSpeed { get; set; } + + /// + /// Colors used on the brush. + /// + public List Colors { get; set; } + + public void StartBlink(int delay) + { + _blinkDelay = delay; + + if (!_blinkWorker.IsBusy) + _blinkWorker.RunWorkerAsync(); + } + + public void StartBlink(int delay, int time) + { + StartBlink(delay); + Task.Factory.StartNew(() => + { + Thread.Sleep(delay); + StopBlink(); + }); + } + + public void StopBlink() + { + if (_blinkWorker.IsBusy) + _blinkWorker.CancelAsync(); + } + + private void BlinkWorker_DoWork(object sender, DoWorkEventArgs e) + { + while (!_blinkWorker.CancellationPending) + { + Thread.Sleep(_blinkDelay); + Visible = !Visible; + } + Visible = true; + } + + public void Draw(Graphics g) + { + if (!Visible || Height < 1 || Width < 1 || !Colors.Any()) + return; + + var brush = CreateBrush(); + var baseRect = new Rectangle(X, Y, Width, Height); + + g.FillRectangle(brush, baseRect); + if (!Rotate) + return; + + _rotationProgress = _rotationProgress + LoopSpeed; + if (ContainedBrush && _rotationProgress > Width) + _rotationProgress = LoopSpeed; + else if (!ContainedBrush && _rotationProgress > _keyboard.Width*Scale) + _rotationProgress = LoopSpeed; + } + + private LinearGradientBrush CreateBrush() + { + var colorBlend = CreateColorBlend(); + RectangleF rect; + if (Rotate) + rect = ContainedBrush + ? new Rectangle((int) _rotationProgress, Y, Width*2, Height*2) + : new Rectangle((int) _rotationProgress, 0, _keyboard.Width*Scale*2, _keyboard.Height*Scale*2); + else + rect = ContainedBrush + ? new Rectangle(X, Y, Width, Height) + : new Rectangle(0, 0, _keyboard.Width*Scale, _keyboard.Height*Scale); + + return new LinearGradientBrush(rect, Color.Transparent, Color.Transparent, GradientMode) + { + InterpolationColors = colorBlend + }; + } + + private ColorBlend CreateColorBlend() + { + if (Colors.Count == 1) + return new ColorBlend {Colors = new[] {Colors[0], Colors[0]}, Positions = new[] {0F, 1F}}; + var colorBlend = Rotate + ? new ColorBlend {Colors = CreateTilebleColors(Colors).ToArray()} + : new ColorBlend {Colors = Colors.ToArray()}; + + // If needed, apply opacity to the colors in the blend + if (Opacity < 255) + for (var i = 0; i < colorBlend.Colors.Length; i++) + colorBlend.Colors[i] = Color.FromArgb(Opacity, colorBlend.Colors[i]); + + // Devide the colors over the colorblend + var devider = (float) colorBlend.Colors.Length - 1; + var positions = new List(); + for (var i = 0; i < colorBlend.Colors.Length; i++) + positions.Add(i/devider); + + // Apply the devided positions + colorBlend.Positions = positions.ToArray(); + return colorBlend; + } + + private List CreateTilebleColors(List sourceColors) + { + // Create a list using the original colors + var tilebleColors = new List(sourceColors); + // Add the original colors again + tilebleColors.AddRange(sourceColors); + // Add the first color, smoothing the transition + tilebleColors.Add(sourceColors.FirstOrDefault()); + return tilebleColors; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/LayerDrawer.cs b/Artemis/Artemis/Utilities/LayerDrawer.cs new file mode 100644 index 000000000..bb5ff25aa --- /dev/null +++ b/Artemis/Artemis/Utilities/LayerDrawer.cs @@ -0,0 +1,168 @@ +using System; +using System.Windows; +using System.Windows.Media; +using Artemis.Models.Profiles; + +namespace Artemis.Utilities +{ + internal class LayerDrawer + { + private readonly LayerModel _layerModel; + private double _animationProgress; + private Rect _firstRect; + private Rect _rectangle; + private Rect _secondRect; + + public LayerDrawer(LayerModel layerModel, int scale) + { + Scale = scale; + _layerModel = layerModel; + _animationProgress = 0; + } + + public int Scale { get; set; } + + public void Draw(DrawingContext c, bool update = true) + { + if (_layerModel.CalcProps.Brush == null || !_layerModel.Enabled) + return; + + if (!update) + _layerModel.CalcProps.Animation = LayerAnimation.None; + + UpdateAnimation(); + + // Set up variables for this frame + _rectangle = new Rect(_layerModel.CalcProps.X*Scale, + _layerModel.CalcProps.Y*Scale, _layerModel.CalcProps.Width*Scale, + _layerModel.CalcProps.Height*Scale); + + if (_layerModel.LayerType == LayerType.Keyboard) + _layerModel.CalcProps.Brush.Dispatcher.Invoke(() => DrawRectangle(c)); + } + + private void UpdateAnimation() + { + if (!_layerModel.Enabled) + return; + + // Slide right animation + if (_layerModel.CalcProps.Animation == LayerAnimation.SlideRight) + { + _firstRect = new Rect(new Point(_rectangle.X + _animationProgress, _rectangle.Y), + new Size(_rectangle.Width, _rectangle.Height)); + _secondRect = new Rect(new Point(_firstRect.X - _rectangle.Width, _rectangle.Y), + new Size(_rectangle.Width + 1, _rectangle.Height)); + + if (_animationProgress > _layerModel.CalcProps.Width*4) + _animationProgress = 0; + } + + // Slide left animation + if (_layerModel.CalcProps.Animation == LayerAnimation.SlideLeft) + { + _firstRect = new Rect(new Point(_rectangle.X - _animationProgress, _rectangle.Y), + new Size(_rectangle.Width + 1, _rectangle.Height)); + _secondRect = new Rect(new Point(_firstRect.X + _rectangle.Width, _rectangle.Y), + new Size(_rectangle.Width, _rectangle.Height)); + + if (_animationProgress > _layerModel.CalcProps.Width*4) + _animationProgress = 0; + } + + // Slide down animation + if (_layerModel.CalcProps.Animation == LayerAnimation.SlideDown) + { + _firstRect = new Rect(new Point(_rectangle.X, _rectangle.Y + _animationProgress), + new Size(_rectangle.Width, _rectangle.Height)); + _secondRect = new Rect(new Point(_firstRect.X, _firstRect.Y - _rectangle.Height), + new Size(_rectangle.Width, _rectangle.Height)); + + if (_animationProgress > _layerModel.CalcProps.Height*4) + _animationProgress = 0; + } + + // Slide up animation + if (_layerModel.CalcProps.Animation == LayerAnimation.SlideUp) + { + _firstRect = new Rect(new Point(_rectangle.X, _rectangle.Y - _animationProgress), + new Size(_rectangle.Width, _rectangle.Height)); + _secondRect = new Rect(new Point(_firstRect.X, _firstRect.Y + _rectangle.Height), + new Size(_rectangle.Width, _rectangle.Height)); + + if (_animationProgress > _layerModel.CalcProps.Height*4) + _animationProgress = 0; + } + + // Pulse animation + if (_layerModel.CalcProps.Animation == LayerAnimation.Pulse) + { + var opac = (Math.Sin(_animationProgress*Math.PI) + 1)*(_layerModel.UserProps.Opacity/2); + _layerModel.CalcProps.Opacity = opac; + if (_animationProgress > 2) + _animationProgress = 0; + + _animationProgress = _animationProgress + _layerModel.CalcProps.AnimationSpeed/2; + } + else + { + // Update the animation progress + _animationProgress = _animationProgress + _layerModel.CalcProps.AnimationSpeed; + } + } + + public DrawingImage GetThumbnail() + { + if (_layerModel.UserProps.Brush == null) + return null; + + var visual = new DrawingVisual(); + using (var c = visual.RenderOpen()) + c.DrawRectangle(_layerModel.UserProps.Brush, new Pen(new SolidColorBrush(Colors.White), 1), + new Rect(0, 0, 18, 18)); + + var image = new DrawingImage(visual.Drawing); + return image; + } + + public void DrawRectangle(DrawingContext c) + { + var brush = _layerModel.CalcProps.Brush.CloneCurrentValue(); + brush.Opacity = _layerModel.CalcProps.Opacity; + + if (_layerModel.CalcProps.Animation == LayerAnimation.SlideDown || + _layerModel.CalcProps.Animation == LayerAnimation.SlideLeft || + _layerModel.CalcProps.Animation == LayerAnimation.SlideRight || + _layerModel.CalcProps.Animation == LayerAnimation.SlideUp) + { + // TODO: if (_layerModel.CalcProps.ContainedBrush) + c.PushClip(new RectangleGeometry(_rectangle)); + c.DrawRectangle(brush, null, _firstRect); + c.DrawRectangle(brush, null, _secondRect); + c.Pop(); + } + else + { + c.DrawRectangle(brush, null, _rectangle); + } + } + + public void DrawEllipse(DrawingContext c) + { + c.DrawEllipse(_layerModel.CalcProps.Brush, null, + new Point(_rectangle.Width/2, _rectangle.Height/2), _rectangle.Width, _rectangle.Height); + } + + public void DrawGif(DrawingContext bmp) + { + } + + public void UpdateMouse() + { + } + + public void UpdateHeadset() + { + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/Memory/Memory.cs b/Artemis/Artemis/Utilities/Memory/Memory.cs index 88e0b16e2..9eade6091 100644 --- a/Artemis/Artemis/Utilities/Memory/Memory.cs +++ b/Artemis/Artemis/Utilities/Memory/Memory.cs @@ -1,425 +1,425 @@ -using System; -using System.Diagnostics; -using System.Text.RegularExpressions; - -namespace Artemis.Utilities.Memory -{ - /// - /// Represents an access to a remote process memory - /// - public class Memory : IDisposable - { - public const string OffsetPattern = "(\\+|\\-){0,1}(0x){0,1}[a-fA-F0-9]{1,}"; - private bool isDisposed; - private IntPtr processHandle; - - /// - /// Initializes a new instance of the Memory - /// - /// Remote process - public Memory(Process process) - { - if (process == null) - throw new ArgumentNullException("process"); - - Process = process; - processHandle = Win32.OpenProcess( - Win32.ProcessAccessType.PROCESS_VM_READ | Win32.ProcessAccessType.PROCESS_VM_WRITE | - Win32.ProcessAccessType.PROCESS_VM_OPERATION, true, (uint) process.Id); - if (processHandle == IntPtr.Zero) - throw new InvalidOperationException("Could not open the process"); - } - - #region Properties - - /// - /// Gets the process to which this memory is attached to - /// - public Process Process { get; private set; } - - #endregion - - /// - /// Finds module with the given name - /// - /// Module name - /// - protected ProcessModule FindModule(string name) - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentNullException("name"); - foreach (ProcessModule module in Process.Modules) - { - if (module.ModuleName.ToLower() == name.ToLower()) - return module; - } - return null; - } - - /// - /// Gets module based address - /// - /// Module name - /// Base address - /// Collection of offsets - /// - public IntPtr GetAddress(string moduleName, IntPtr baseAddress, int[] offsets) - { - if (string.IsNullOrEmpty(moduleName)) - throw new ArgumentNullException("moduleName"); - - var module = FindModule(moduleName); - if (module == null) - return IntPtr.Zero; - var address = module.BaseAddress.ToInt32() + baseAddress.ToInt32(); - return GetAddress((IntPtr) address, offsets); - } - - /// - /// Gets module based address - /// - /// Module name - /// Base address - /// Collection of offsets - /// - public IntPtr GetAddressX64(string moduleName, IntPtr baseAddress, int[] offsets) - { - if (string.IsNullOrEmpty(moduleName)) - throw new ArgumentNullException("moduleName"); - - var module = FindModule(moduleName); - if (module == null) - return IntPtr.Zero; - var address = module.BaseAddress.ToInt64() + baseAddress.ToInt64(); - return GetAddressX64((IntPtr) address, offsets); - } - - /// - /// Gets address - /// - /// Base address - /// Collection of offsets - /// - public IntPtr GetAddress(IntPtr baseAddress, int[] offsets) - { - if (baseAddress == IntPtr.Zero) - throw new ArgumentException("Invalid base address"); - - var address = baseAddress.ToInt32(); - - if (offsets != null && offsets.Length > 0) - { - var buffer = new byte[4]; - foreach (var offset in offsets) - address = ReadInt32((IntPtr) address) + offset; - } - - return (IntPtr) address; - } - - /// - /// Gets address - /// - /// Base address - /// Collection of offsets - /// - public IntPtr GetAddressX64(IntPtr baseAddress, int[] offsets) - { - if (baseAddress == IntPtr.Zero) - throw new ArgumentException("Invalid base address"); - - var address = baseAddress.ToInt64(); - - if (offsets != null && offsets.Length > 0) - { - var buffer = new byte[4]; - foreach (var offset in offsets) - address = ReadInt32((IntPtr) address) + offset; - } - - return (IntPtr) address; - } - - /// - /// Gets address pointer - /// - /// Address - /// - public IntPtr GetAddressX64(string address) - { - if (string.IsNullOrEmpty(address)) - throw new ArgumentNullException("address"); - - string moduleName = null; - var index = address.IndexOf('"'); - if (index != -1) - { - // Module name at the beginning - var endIndex = address.IndexOf('"', index + 1); - if (endIndex == -1) - throw new ArgumentException("Invalid module name. Could not find matching \""); - moduleName = address.Substring(index + 1, endIndex - 1); - address = address.Substring(endIndex + 1); - } - - var offsets = GetAddressOffsets(address); - int[] _offsets = null; - var baseAddress = offsets != null && offsets.Length > 0 - ? (IntPtr) offsets[0] - : IntPtr.Zero; - if (offsets != null && offsets.Length > 1) - { - _offsets = new int[offsets.Length - 1]; - for (var i = 0; i < offsets.Length - 1; i++) - _offsets[i] = offsets[i + 1]; - } - - if (moduleName != null) - return GetAddressX64(moduleName, baseAddress, _offsets); - return GetAddressX64(baseAddress, _offsets); - } - - /// - /// Gets address pointer - /// - /// Address - /// - public IntPtr GetAddress(string address) - { - if (string.IsNullOrEmpty(address)) - throw new ArgumentNullException("address"); - - string moduleName = null; - var index = address.IndexOf('"'); - if (index != -1) - { - // Module name at the beginning - var endIndex = address.IndexOf('"', index + 1); - if (endIndex == -1) - throw new ArgumentException("Invalid module name. Could not find matching \""); - moduleName = address.Substring(index + 1, endIndex - 1); - address = address.Substring(endIndex + 1); - } - - var offsets = GetAddressOffsets(address); - int[] _offsets = null; - var baseAddress = offsets != null && offsets.Length > 0 - ? (IntPtr) offsets[0] - : IntPtr.Zero; - if (offsets != null && offsets.Length > 1) - { - _offsets = new int[offsets.Length - 1]; - for (var i = 0; i < offsets.Length - 1; i++) - _offsets[i] = offsets[i + 1]; - } - - if (moduleName != null) - return GetAddress(moduleName, baseAddress, _offsets); - return GetAddress(baseAddress, _offsets); - } - - /// - /// Gets address offsets - /// - /// Address - /// - protected static int[] GetAddressOffsets(string address) - { - if (string.IsNullOrEmpty(address)) - return new int[0]; - var matches = Regex.Matches(address, OffsetPattern); - var offsets = new int[matches.Count]; - string value; - char ch; - for (var i = 0; i < matches.Count; i++) - { - ch = matches[i].Value[0]; - if (ch == '+' || ch == '-') - value = matches[i].Value.Substring(1); - else - value = matches[i].Value; - offsets[i] = Convert.ToInt32(value, 16); - if (ch == '-') - offsets[i] = -offsets[i]; - } - return offsets; - } - - /// - /// Reads memory at the address - /// - /// Memory address - /// Buffer - /// Size in bytes - public void ReadMemory(IntPtr address, byte[] buffer, int size) - { - if (isDisposed) - throw new ObjectDisposedException("Memory"); - if (buffer == null) - throw new ArgumentNullException("buffer"); - if (size <= 0) - throw new ArgumentException("Size must be greater than zero"); - if (address == IntPtr.Zero) - throw new ArgumentException("Invalid address"); - - uint read = 0; - Win32.ReadProcessMemory(processHandle, address, buffer, (uint) size, ref read); - } - - /// - /// Writes memory at the address - /// - /// Memory address - /// Buffer - /// Size in bytes - public void WriteMemory(IntPtr address, byte[] buffer, int size) - { - if (isDisposed) - throw new ObjectDisposedException("Memory"); - if (buffer == null) - throw new ArgumentNullException("buffer"); - if (size <= 0) - throw new ArgumentException("Size must be greater than zero"); - if (address == IntPtr.Zero) - throw new ArgumentException("Invalid address"); - - uint write = 0; - if (!Win32.WriteProcessMemory(processHandle, address, buffer, (uint) size, ref write) || - write != size) - throw new AccessViolationException(); - } - - /// - /// Reads 32 bit signed integer at the address - /// - /// Memory address - /// - public int ReadInt32(IntPtr address) - { - var buffer = new byte[4]; - ReadMemory(address, buffer, 4); - return BitConverter.ToInt32(buffer, 0); - } - - /// - /// Reads 32 bit signed integer at the address - /// - /// Memory address - /// - public long ReadInt64(IntPtr address) - { - var buffer = new byte[8]; - ReadMemory(address, buffer, 8); - return BitConverter.ToInt64(buffer, 0); - } - - /// - /// Reads 32 bit unsigned integer at the address - /// - /// Memory address - /// - public uint ReadUInt32(IntPtr address) - { - var buffer = new byte[4]; - ReadMemory(address, buffer, 4); - return BitConverter.ToUInt32(buffer, 0); - } - - /// - /// Reads single precision value at the address - /// - /// Memory address - /// - public float ReadFloat(IntPtr address) - { - var buffer = new byte[4]; - ReadMemory(address, buffer, 4); - return BitConverter.ToSingle(buffer, 0); - } - - /// - /// Reads double precision value at the address - /// - /// Memory address - /// - public double ReadDouble(IntPtr address) - { - var buffer = new byte[8]; - ReadMemory(address, buffer, 8); - return BitConverter.ToDouble(buffer, 0); - } - - /// - /// Writes 32 bit unsigned integer at the address - /// - /// Memory address - /// Value - /// - public void WriteUInt32(IntPtr address, uint value) - { - var buffer = BitConverter.GetBytes(value); - WriteMemory(address, buffer, 4); - } - - /// - /// Writes 32 bit signed integer at the address - /// - /// Memory address - /// Value - /// - public void WriteInt32(IntPtr address, int value) - { - var buffer = BitConverter.GetBytes(value); - WriteMemory(address, buffer, 4); - } - - /// - /// Writes single precision value at the address - /// - /// Memory address - /// Value - /// - public void WriteFloat(IntPtr address, float value) - { - var buffer = BitConverter.GetBytes(value); - WriteMemory(address, buffer, 4); - } - - /// - /// Writes double precision value at the address - /// - /// Memory address - /// Value - /// - public void WriteDouble(IntPtr address, double value) - { - var buffer = BitConverter.GetBytes(value); - WriteMemory(address, buffer, 8); - } - - #region IDisposable - - ~Memory() - { - Dispose(false); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (isDisposed) - return; - Win32.CloseHandle(processHandle); - Process = null; - processHandle = IntPtr.Zero; - isDisposed = true; - } - - #endregion - } +using System; +using System.Diagnostics; +using System.Text.RegularExpressions; + +namespace Artemis.Utilities.Memory +{ + /// + /// Represents an access to a remote process memory + /// + public class Memory : IDisposable + { + public const string OffsetPattern = "(\\+|\\-){0,1}(0x){0,1}[a-fA-F0-9]{1,}"; + private bool isDisposed; + private IntPtr processHandle; + + /// + /// Initializes a new instance of the Memory + /// + /// Remote process + public Memory(Process process) + { + if (process == null) + throw new ArgumentNullException("process"); + + Process = process; + processHandle = Win32.OpenProcess( + Win32.ProcessAccessType.PROCESS_VM_READ | Win32.ProcessAccessType.PROCESS_VM_WRITE | + Win32.ProcessAccessType.PROCESS_VM_OPERATION, true, (uint) process.Id); + if (processHandle == IntPtr.Zero) + throw new InvalidOperationException("Could not open the process"); + } + + #region Properties + + /// + /// Gets the process to which this memory is attached to + /// + public Process Process { get; private set; } + + #endregion + + /// + /// Finds module with the given name + /// + /// Module name + /// + protected ProcessModule FindModule(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + foreach (ProcessModule module in Process.Modules) + { + if (module.ModuleName.ToLower() == name.ToLower()) + return module; + } + return null; + } + + /// + /// Gets module based address + /// + /// Module name + /// Base address + /// Collection of offsets + /// + public IntPtr GetAddress(string moduleName, IntPtr baseAddress, int[] offsets) + { + if (string.IsNullOrEmpty(moduleName)) + throw new ArgumentNullException("moduleName"); + + var module = FindModule(moduleName); + if (module == null) + return IntPtr.Zero; + var address = module.BaseAddress.ToInt32() + baseAddress.ToInt32(); + return GetAddress((IntPtr) address, offsets); + } + + /// + /// Gets module based address + /// + /// Module name + /// Base address + /// Collection of offsets + /// + public IntPtr GetAddressX64(string moduleName, IntPtr baseAddress, int[] offsets) + { + if (string.IsNullOrEmpty(moduleName)) + throw new ArgumentNullException("moduleName"); + + var module = FindModule(moduleName); + if (module == null) + return IntPtr.Zero; + var address = module.BaseAddress.ToInt64() + baseAddress.ToInt64(); + return GetAddressX64((IntPtr) address, offsets); + } + + /// + /// Gets address + /// + /// Base address + /// Collection of offsets + /// + public IntPtr GetAddress(IntPtr baseAddress, int[] offsets) + { + if (baseAddress == IntPtr.Zero) + throw new ArgumentException("Invalid base address"); + + var address = baseAddress.ToInt32(); + + if (offsets != null && offsets.Length > 0) + { + var buffer = new byte[4]; + foreach (var offset in offsets) + address = ReadInt32((IntPtr) address) + offset; + } + + return (IntPtr) address; + } + + /// + /// Gets address + /// + /// Base address + /// Collection of offsets + /// + public IntPtr GetAddressX64(IntPtr baseAddress, int[] offsets) + { + if (baseAddress == IntPtr.Zero) + throw new ArgumentException("Invalid base address"); + + var address = baseAddress.ToInt64(); + + if (offsets != null && offsets.Length > 0) + { + var buffer = new byte[4]; + foreach (var offset in offsets) + address = ReadInt32((IntPtr) address) + offset; + } + + return (IntPtr) address; + } + + /// + /// Gets address pointer + /// + /// Address + /// + public IntPtr GetAddressX64(string address) + { + if (string.IsNullOrEmpty(address)) + throw new ArgumentNullException("address"); + + string moduleName = null; + var index = address.IndexOf('"'); + if (index != -1) + { + // Module name at the beginning + var endIndex = address.IndexOf('"', index + 1); + if (endIndex == -1) + throw new ArgumentException("Invalid module name. Could not find matching \""); + moduleName = address.Substring(index + 1, endIndex - 1); + address = address.Substring(endIndex + 1); + } + + var offsets = GetAddressOffsets(address); + int[] _offsets = null; + var baseAddress = offsets != null && offsets.Length > 0 + ? (IntPtr) offsets[0] + : IntPtr.Zero; + if (offsets != null && offsets.Length > 1) + { + _offsets = new int[offsets.Length - 1]; + for (var i = 0; i < offsets.Length - 1; i++) + _offsets[i] = offsets[i + 1]; + } + + if (moduleName != null) + return GetAddressX64(moduleName, baseAddress, _offsets); + return GetAddressX64(baseAddress, _offsets); + } + + /// + /// Gets address pointer + /// + /// Address + /// + public IntPtr GetAddress(string address) + { + if (string.IsNullOrEmpty(address)) + throw new ArgumentNullException("address"); + + string moduleName = null; + var index = address.IndexOf('"'); + if (index != -1) + { + // Module name at the beginning + var endIndex = address.IndexOf('"', index + 1); + if (endIndex == -1) + throw new ArgumentException("Invalid module name. Could not find matching \""); + moduleName = address.Substring(index + 1, endIndex - 1); + address = address.Substring(endIndex + 1); + } + + var offsets = GetAddressOffsets(address); + int[] _offsets = null; + var baseAddress = offsets != null && offsets.Length > 0 + ? (IntPtr) offsets[0] + : IntPtr.Zero; + if (offsets != null && offsets.Length > 1) + { + _offsets = new int[offsets.Length - 1]; + for (var i = 0; i < offsets.Length - 1; i++) + _offsets[i] = offsets[i + 1]; + } + + if (moduleName != null) + return GetAddress(moduleName, baseAddress, _offsets); + return GetAddress(baseAddress, _offsets); + } + + /// + /// Gets address offsets + /// + /// Address + /// + protected static int[] GetAddressOffsets(string address) + { + if (string.IsNullOrEmpty(address)) + return new int[0]; + var matches = Regex.Matches(address, OffsetPattern); + var offsets = new int[matches.Count]; + string value; + char ch; + for (var i = 0; i < matches.Count; i++) + { + ch = matches[i].Value[0]; + if (ch == '+' || ch == '-') + value = matches[i].Value.Substring(1); + else + value = matches[i].Value; + offsets[i] = Convert.ToInt32(value, 16); + if (ch == '-') + offsets[i] = -offsets[i]; + } + return offsets; + } + + /// + /// Reads memory at the address + /// + /// Memory address + /// Buffer + /// Size in bytes + public void ReadMemory(IntPtr address, byte[] buffer, int size) + { + if (isDisposed) + throw new ObjectDisposedException("Memory"); + if (buffer == null) + throw new ArgumentNullException("buffer"); + if (size <= 0) + throw new ArgumentException("Size must be greater than zero"); + if (address == IntPtr.Zero) + throw new ArgumentException("Invalid address"); + + uint read = 0; + Win32.ReadProcessMemory(processHandle, address, buffer, (uint) size, ref read); + } + + /// + /// Writes memory at the address + /// + /// Memory address + /// Buffer + /// Size in bytes + public void WriteMemory(IntPtr address, byte[] buffer, int size) + { + if (isDisposed) + throw new ObjectDisposedException("Memory"); + if (buffer == null) + throw new ArgumentNullException("buffer"); + if (size <= 0) + throw new ArgumentException("Size must be greater than zero"); + if (address == IntPtr.Zero) + throw new ArgumentException("Invalid address"); + + uint write = 0; + if (!Win32.WriteProcessMemory(processHandle, address, buffer, (uint) size, ref write) || + write != size) + throw new AccessViolationException(); + } + + /// + /// Reads 32 bit signed integer at the address + /// + /// Memory address + /// + public int ReadInt32(IntPtr address) + { + var buffer = new byte[4]; + ReadMemory(address, buffer, 4); + return BitConverter.ToInt32(buffer, 0); + } + + /// + /// Reads 32 bit signed integer at the address + /// + /// Memory address + /// + public long ReadInt64(IntPtr address) + { + var buffer = new byte[8]; + ReadMemory(address, buffer, 8); + return BitConverter.ToInt64(buffer, 0); + } + + /// + /// Reads 32 bit unsigned integer at the address + /// + /// Memory address + /// + public uint ReadUInt32(IntPtr address) + { + var buffer = new byte[4]; + ReadMemory(address, buffer, 4); + return BitConverter.ToUInt32(buffer, 0); + } + + /// + /// Reads single precision value at the address + /// + /// Memory address + /// + public float ReadFloat(IntPtr address) + { + var buffer = new byte[4]; + ReadMemory(address, buffer, 4); + return BitConverter.ToSingle(buffer, 0); + } + + /// + /// Reads double precision value at the address + /// + /// Memory address + /// + public double ReadDouble(IntPtr address) + { + var buffer = new byte[8]; + ReadMemory(address, buffer, 8); + return BitConverter.ToDouble(buffer, 0); + } + + /// + /// Writes 32 bit unsigned integer at the address + /// + /// Memory address + /// Value + /// + public void WriteUInt32(IntPtr address, uint value) + { + var buffer = BitConverter.GetBytes(value); + WriteMemory(address, buffer, 4); + } + + /// + /// Writes 32 bit signed integer at the address + /// + /// Memory address + /// Value + /// + public void WriteInt32(IntPtr address, int value) + { + var buffer = BitConverter.GetBytes(value); + WriteMemory(address, buffer, 4); + } + + /// + /// Writes single precision value at the address + /// + /// Memory address + /// Value + /// + public void WriteFloat(IntPtr address, float value) + { + var buffer = BitConverter.GetBytes(value); + WriteMemory(address, buffer, 4); + } + + /// + /// Writes double precision value at the address + /// + /// Memory address + /// Value + /// + public void WriteDouble(IntPtr address, double value) + { + var buffer = BitConverter.GetBytes(value); + WriteMemory(address, buffer, 8); + } + + #region IDisposable + + ~Memory() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (isDisposed) + return; + Win32.CloseHandle(processHandle); + Process = null; + processHandle = IntPtr.Zero; + isDisposed = true; + } + + #endregion + } } \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/Memory/MemoryHelpers.cs b/Artemis/Artemis/Utilities/Memory/MemoryHelpers.cs index 47cf6cdad..42fd85158 100644 --- a/Artemis/Artemis/Utilities/Memory/MemoryHelpers.cs +++ b/Artemis/Artemis/Utilities/Memory/MemoryHelpers.cs @@ -1,41 +1,41 @@ -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace Artemis.Utilities.Memory -{ - public static class MemoryHelpers - { - [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, - int dwSize, ref int lpNumberOfBytesRead); - - public static Process GetProcessIfRunning(string processName) - { - var processes = Process.GetProcessesByName(processName); - return processes.Length >= 1 ? processes[0] : null; - } - - public static IntPtr FindAddress(IntPtr pHandle, IntPtr baseAddress, IntPtr staticPointer, int[] offsets) - { - // Create a buffer that is 4 bytes on a 32-bit system or 8 bytes on a 64-bit system. - var tmp = new byte[IntPtr.Size]; - var address = baseAddress; - // We must check for 32-bit vs 64-bit. - address = IntPtr.Size == 4 - ? new IntPtr(address.ToInt32() + staticPointer.ToInt32()) - : new IntPtr(address.ToInt64() + staticPointer.ToInt64()); - - // Loop through each offset to find the address - foreach (IntPtr t in offsets) - { - var lpNumberOfBytesRead = 0; - ReadProcessMemory(pHandle, address, tmp, IntPtr.Size, ref lpNumberOfBytesRead); - address = IntPtr.Size == 4 - ? new IntPtr(BitConverter.ToInt32(tmp, 0) + t.ToInt32()) - : new IntPtr(BitConverter.ToInt64(tmp, 0) + t.ToInt64()); - } - return address; - } - } +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Artemis.Utilities.Memory +{ + public static class MemoryHelpers + { + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, + int dwSize, ref int lpNumberOfBytesRead); + + public static Process GetProcessIfRunning(string processName) + { + var processes = Process.GetProcessesByName(processName); + return processes.Length >= 1 ? processes[0] : null; + } + + public static IntPtr FindAddress(IntPtr pHandle, IntPtr baseAddress, IntPtr staticPointer, int[] offsets) + { + // Create a buffer that is 4 bytes on a 32-bit system or 8 bytes on a 64-bit system. + var tmp = new byte[IntPtr.Size]; + var address = baseAddress; + // We must check for 32-bit vs 64-bit. + address = IntPtr.Size == 4 + ? new IntPtr(address.ToInt32() + staticPointer.ToInt32()) + : new IntPtr(address.ToInt64() + staticPointer.ToInt64()); + + // Loop through each offset to find the address + foreach (IntPtr t in offsets) + { + var lpNumberOfBytesRead = 0; + ReadProcessMemory(pHandle, address, tmp, IntPtr.Size, ref lpNumberOfBytesRead); + address = IntPtr.Size == 4 + ? new IntPtr(BitConverter.ToInt32(tmp, 0) + t.ToInt32()) + : new IntPtr(BitConverter.ToInt64(tmp, 0) + t.ToInt64()); + } + return address; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/Memory/Win32.cs b/Artemis/Artemis/Utilities/Memory/Win32.cs index 20a5c9b1f..b94f22549 100644 --- a/Artemis/Artemis/Utilities/Memory/Win32.cs +++ b/Artemis/Artemis/Utilities/Memory/Win32.cs @@ -1,43 +1,43 @@ -using System; -using System.Runtime.InteropServices; - -namespace Artemis.Utilities.Memory -{ - /// - /// Win32 methods - /// - public static class Win32 - { - [Flags] - public enum ProcessAccessType - { - PROCESS_TERMINATE = 0x0001, - PROCESS_CREATE_THREAD = 0x0002, - PROCESS_SET_SESSIONID = 0x0004, - PROCESS_VM_OPERATION = 0x0008, - PROCESS_VM_READ = 0x0010, - PROCESS_VM_WRITE = 0x0020, - PROCESS_DUP_HANDLE = 0x0040, - PROCESS_CREATE_PROCESS = 0x0080, - PROCESS_SET_QUOTA = 0x0100, - PROCESS_SET_INFORMATION = 0x0200, - PROCESS_QUERY_INFORMATION = 0x0400 - } - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool WriteProcessMemory( - IntPtr process, IntPtr address, byte[] buffer, uint size, ref uint written); - - [DllImport("Kernel32.dll", SetLastError = true)] - public static extern bool ReadProcessMemory( - IntPtr process, IntPtr address, byte[] buffer, uint size, ref uint read); - - [DllImport("kernel32.dll")] - public static extern IntPtr OpenProcess( - [MarshalAs(UnmanagedType.U4)] ProcessAccessType access, - [MarshalAs(UnmanagedType.Bool)] bool inheritHandler, uint processId); - - [DllImport("kernel32.dll")] - public static extern int CloseHandle(IntPtr objectHandle); - } +using System; +using System.Runtime.InteropServices; + +namespace Artemis.Utilities.Memory +{ + /// + /// Win32 methods + /// + public static class Win32 + { + [Flags] + public enum ProcessAccessType + { + PROCESS_TERMINATE = 0x0001, + PROCESS_CREATE_THREAD = 0x0002, + PROCESS_SET_SESSIONID = 0x0004, + PROCESS_VM_OPERATION = 0x0008, + PROCESS_VM_READ = 0x0010, + PROCESS_VM_WRITE = 0x0020, + PROCESS_DUP_HANDLE = 0x0040, + PROCESS_CREATE_PROCESS = 0x0080, + PROCESS_SET_QUOTA = 0x0100, + PROCESS_SET_INFORMATION = 0x0200, + PROCESS_QUERY_INFORMATION = 0x0400 + } + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool WriteProcessMemory( + IntPtr process, IntPtr address, byte[] buffer, uint size, ref uint written); + + [DllImport("Kernel32.dll", SetLastError = true)] + public static extern bool ReadProcessMemory( + IntPtr process, IntPtr address, byte[] buffer, uint size, ref uint read); + + [DllImport("kernel32.dll")] + public static extern IntPtr OpenProcess( + [MarshalAs(UnmanagedType.U4)] ProcessAccessType access, + [MarshalAs(UnmanagedType.Bool)] bool inheritHandler, uint processId); + + [DllImport("kernel32.dll")] + public static extern int CloseHandle(IntPtr objectHandle); + } } \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/ParentChild/ChildItemCollection.cs b/Artemis/Artemis/Utilities/ParentChild/ChildItemCollection.cs new file mode 100644 index 000000000..c5840962c --- /dev/null +++ b/Artemis/Artemis/Utilities/ParentChild/ChildItemCollection.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace Artemis.Utilities.ParentChild +{ + /// + /// Collection of child items. This collection automatically set the + /// Parent property of the child items when they are added or removed + /// Thomas Levesque - http://www.thomaslevesque.com/2009/06/12/c-parentchild-relationship-and-xml-serialization/ + /// + /// Type of the parent object + /// Type of the child items + public class ChildItemCollection : IList + where P : class + where T : IChildItem

+ { + private IList _collection; + private readonly P _parent; + + public ChildItemCollection(P parent) + { + _parent = parent; + _collection = new List(); + } + + public ChildItemCollection(P parent, IList collection) + { + _parent = parent; + _collection = collection; + } + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return _collection.GetEnumerator(); + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return (_collection as IEnumerable).GetEnumerator(); + } + + #endregion + + #region IList Members + + public int IndexOf(T item) + { + return _collection.IndexOf(item); + } + + public void Insert(int index, T item) + { + if (item != null) + item.Parent = _parent; + _collection.Insert(index, item); + } + + public void RemoveAt(int index) + { + var oldItem = _collection[index]; + _collection.RemoveAt(index); + if (oldItem != null) + oldItem.Parent = null; + } + + public T this[int index] + { + get { return _collection[index]; } + set + { + var oldItem = _collection[index]; + if (value != null) + value.Parent = _parent; + _collection[index] = value; + if (oldItem != null) + oldItem.Parent = null; + } + } + + #endregion + + #region ICollection Members + + public void Add(T item) + { + if (item != null) + item.Parent = _parent; + _collection.Add(item); + } + + public void Clear() + { + foreach (var item in _collection) + { + if (item != null) + item.Parent = null; + } + _collection.Clear(); + } + + public bool Contains(T item) + { + return _collection.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + _collection.CopyTo(array, arrayIndex); + } + + public int Count => _collection.Count; + + public bool IsReadOnly => _collection.IsReadOnly; + + public bool Remove(T item) + { + var b = _collection.Remove(item); + if (item != null) + item.Parent = null; + return b; + } + + #endregion + + public void Sort(Func func) + { + _collection = _collection.OrderBy(func).ToList(); + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/ParentChild/IChildItem.cs b/Artemis/Artemis/Utilities/ParentChild/IChildItem.cs new file mode 100644 index 000000000..f4a59c0a5 --- /dev/null +++ b/Artemis/Artemis/Utilities/ParentChild/IChildItem.cs @@ -0,0 +1,12 @@ +namespace Artemis.Utilities.ParentChild +{ + ///

+ /// Defines the contract for an object that has a parent object + /// Thomas Levesque - http://www.thomaslevesque.com/2009/06/12/c-parentchild-relationship-and-xml-serialization/ + /// + /// Type of the parent object + public interface IChildItem

where P : class + { + P Parent { get; set; } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/ShellLink.cs b/Artemis/Artemis/Utilities/ShellLink.cs index 7e3996986..fa0632d02 100644 --- a/Artemis/Artemis/Utilities/ShellLink.cs +++ b/Artemis/Artemis/Utilities/ShellLink.cs @@ -1,46 +1,46 @@ -using System; -using System.Runtime.InteropServices; -using System.Text; - -namespace Artemis.Utilities -{ - ///

- /// Creates a shortcut (.lnk) file. - /// Source: http://stackoverflow.com/a/14632782/5015269 - /// - [ComImport] - [Guid("00021401-0000-0000-C000-000000000046")] - internal class ShellLink - { - } - - [ComImport] - [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - [Guid("000214F9-0000-0000-C000-000000000046")] - internal interface IShellLink - { - void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out IntPtr pfd, - int fFlags); - - void GetIDList(out IntPtr ppidl); - void SetIDList(IntPtr pidl); - void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName); - void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); - void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); - void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); - void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); - void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); - void GetHotkey(out short pwHotkey); - void SetHotkey(short wHotkey); - void GetShowCmd(out int piShowCmd); - void SetShowCmd(int iShowCmd); - - void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, - out int piIcon); - - void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); - void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved); - void Resolve(IntPtr hwnd, int fFlags); - void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); - } +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Artemis.Utilities +{ + /// + /// Creates a shortcut (.lnk) file. + /// Source: http://stackoverflow.com/a/14632782/5015269 + /// + [ComImport] + [Guid("00021401-0000-0000-C000-000000000046")] + internal class ShellLink + { + } + + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("000214F9-0000-0000-C000-000000000046")] + internal interface IShellLink + { + void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out IntPtr pfd, + int fFlags); + + void GetIDList(out IntPtr ppidl); + void SetIDList(IntPtr pidl); + void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName); + void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); + void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); + void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); + void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); + void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); + void GetHotkey(out short pwHotkey); + void SetHotkey(short wHotkey); + void GetShowCmd(out int piShowCmd); + void SetShowCmd(int iShowCmd); + + void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, + out int piIcon); + + void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); + void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved); + void Resolve(IntPtr hwnd, int fFlags); + void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); + } } \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/ValueConverters.cs b/Artemis/Artemis/Utilities/ValueConverters.cs new file mode 100644 index 000000000..bd60915d0 --- /dev/null +++ b/Artemis/Artemis/Utilities/ValueConverters.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections; +using System.ComponentModel; +using System.Globalization; +using System.Linq; +using System.Windows.Data; +using Artemis.Models.Profiles; +using Artemis.Utilities.ParentChild; + +namespace Artemis.Utilities +{ + /// + /// Fredrik Hedblad - http://stackoverflow.com/a/3987099/5015269 + /// + public class EnumDescriptionConverter : IValueConverter + { + object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var myEnum = (Enum) value; + var description = GetEnumDescription(myEnum); + return description; + } + + object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return string.Empty; + } + + private string GetEnumDescription(Enum enumObj) + { + var fieldInfo = enumObj.GetType().GetField(enumObj.ToString()); + + var attribArray = fieldInfo.GetCustomAttributes(false); + + if (attribArray.Length == 0) + { + return enumObj.ToString(); + } + var attrib = attribArray[0] as DescriptionAttribute; + return attrib?.Description; + } + } + + public class LayerOrderConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + IList collection; + if (value is ChildItemCollection) + collection = ((ChildItemCollection) value).ToList(); + else + collection = (IList) value; + + var view = new ListCollectionView(collection); + var sort = new SortDescription(parameter.ToString(), ListSortDirection.Ascending); + view.SortDescriptions.Add(sort); + + return view; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return null; + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs b/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs index 857c35b46..ba58d6dc6 100644 --- a/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs +++ b/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs @@ -1,4 +1,5 @@ -using Artemis.Managers; +using System.ComponentModel; +using Artemis.Managers; using Artemis.Models; using Caliburn.Micro; @@ -10,7 +11,7 @@ namespace Artemis.ViewModels.Abstract public GameModel GameModel { get; set; } public MainManager MainManager { get; set; } - + public event OnLayersUpdatedCallback OnLayersUpdatedCallback; public GameSettings GameSettings { get { return _gameSettings; } @@ -54,4 +55,6 @@ namespace Artemis.ViewModels.Abstract SaveSettings(); } } + + public delegate void OnLayersUpdatedCallback(object sender); } \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/EffectsViewModel.cs b/Artemis/Artemis/ViewModels/EffectsViewModel.cs index 4a89893b5..8c2319e64 100644 --- a/Artemis/Artemis/ViewModels/EffectsViewModel.cs +++ b/Artemis/Artemis/ViewModels/EffectsViewModel.cs @@ -1,39 +1,39 @@ -using Artemis.Managers; -using Artemis.Modules.Effects.AmbientLightning; -using Artemis.Modules.Effects.AudioVisualizer; -using Artemis.Modules.Effects.Debug; -using Artemis.Modules.Effects.TypeHole; -using Artemis.Modules.Effects.TypeWave; -using Caliburn.Micro; - -namespace Artemis.ViewModels -{ - public class EffectsViewModel : Conductor.Collection.OneActive - { - private readonly AudioVisualizerViewModel _audioVisualizerVm; - private readonly DebugEffectViewModel _debugVm; - private readonly TypeHoleViewModel _typeHoleVm; - private readonly TypeWaveViewModel _typeWaveVm; - //private readonly AmbientLightningEffectViewModel _ambientLightningVm; - - public EffectsViewModel(MainManager mainManager) - { - _typeWaveVm = new TypeWaveViewModel(mainManager) {DisplayName = "Type Waves"}; - //_typeHoleVm = new TypeHoleViewModel(MainManager) {DisplayName = "Type Holes (NYI)"}; - _audioVisualizerVm = new AudioVisualizerViewModel(mainManager) {DisplayName = "Audio Visualization"}; - //_ambientLightningVm = new AmbientLightningEffectViewModel(mainManager) {DisplayName = "Ambient Lightning"}; - _debugVm = new DebugEffectViewModel(mainManager) {DisplayName = "Debug Effect"}; - } - - protected override void OnActivate() - { - base.OnActivate(); - - ActivateItem(_typeWaveVm); - //ActivateItem(_typeHoleVm); - ActivateItem(_audioVisualizerVm); - //ActivateItem(_ambientLightningVm); - ActivateItem(_debugVm); - } - } +using Artemis.Managers; +using Artemis.Modules.Effects.AmbientLightning; +using Artemis.Modules.Effects.AudioVisualizer; +using Artemis.Modules.Effects.Debug; +using Artemis.Modules.Effects.TypeHole; +using Artemis.Modules.Effects.TypeWave; +using Caliburn.Micro; + +namespace Artemis.ViewModels +{ + public class EffectsViewModel : Conductor.Collection.OneActive + { + private readonly AudioVisualizerViewModel _audioVisualizerVm; + private readonly DebugEffectViewModel _debugVm; + private readonly TypeHoleViewModel _typeHoleVm; + private readonly TypeWaveViewModel _typeWaveVm; + //private readonly AmbientLightningEffectViewModel _ambientLightningVm; + + public EffectsViewModel(MainManager mainManager) + { + _typeWaveVm = new TypeWaveViewModel(mainManager) {DisplayName = "Type Waves"}; + //_typeHoleVm = new TypeHoleViewModel(MainManager) {DisplayName = "Type Holes (NYI)"}; + _audioVisualizerVm = new AudioVisualizerViewModel(mainManager) {DisplayName = "Audio Visualization"}; + //_ambientLightningVm = new AmbientLightningEffectViewModel(mainManager) {DisplayName = "Ambient Lightning"}; + _debugVm = new DebugEffectViewModel(mainManager) {DisplayName = "Debug Effect"}; + } + + protected override void OnActivate() + { + base.OnActivate(); + + ActivateItem(_typeWaveVm); + //ActivateItem(_typeHoleVm); + ActivateItem(_audioVisualizerVm); + //ActivateItem(_ambientLightningVm); + ActivateItem(_debugVm); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/FlyoutBaseViewModel.cs b/Artemis/Artemis/ViewModels/FlyoutBaseViewModel.cs index 26ad9231e..723dc3af2 100644 --- a/Artemis/Artemis/ViewModels/FlyoutBaseViewModel.cs +++ b/Artemis/Artemis/ViewModels/FlyoutBaseViewModel.cs @@ -1,57 +1,57 @@ -using Caliburn.Micro; -using MahApps.Metro.Controls; - -namespace Artemis.ViewModels -{ - public abstract class FlyoutBaseViewModel : PropertyChangedBase - { - private string _header; - private bool _isOpen; - private Position _position; - - public string Header - { - get { return _header; } - - set - { - if (value == _header) - return; - - _header = value; - NotifyOfPropertyChange(() => Header); - } - } - - public bool IsOpen - { - get { return _isOpen; } - - set - { - if (value.Equals(_isOpen)) - return; - - _isOpen = value; - HandleOpen(); - NotifyOfPropertyChange(() => IsOpen); - } - } - - public Position Position - { - get { return _position; } - - set - { - if (value == _position) - return; - - _position = value; - NotifyOfPropertyChange(() => Position); - } - } - - protected abstract void HandleOpen(); - } +using Caliburn.Micro; +using MahApps.Metro.Controls; + +namespace Artemis.ViewModels +{ + public abstract class FlyoutBaseViewModel : PropertyChangedBase + { + private string _header; + private bool _isOpen; + private Position _position; + + public string Header + { + get { return _header; } + + set + { + if (value == _header) + return; + + _header = value; + NotifyOfPropertyChange(() => Header); + } + } + + public bool IsOpen + { + get { return _isOpen; } + + set + { + if (value.Equals(_isOpen)) + return; + + _isOpen = value; + HandleOpen(); + NotifyOfPropertyChange(() => IsOpen); + } + } + + public Position Position + { + get { return _position; } + + set + { + if (value == _position) + return; + + _position = value; + NotifyOfPropertyChange(() => Position); + } + } + + protected abstract void HandleOpen(); + } } \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs b/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs index 192b1f0a3..aedf2c01c 100644 --- a/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs +++ b/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs @@ -1,134 +1,133 @@ -using System.Diagnostics; -using System.Linq; -using Artemis.Events; -using Artemis.Managers; -using Artemis.Settings; -using Caliburn.Micro; -using MahApps.Metro.Controls; - -namespace Artemis.ViewModels.Flyouts -{ - public class FlyoutSettingsViewModel : FlyoutBaseViewModel, IHandle, IHandle - { - private string _activeEffectName; - private bool _enabled; - private GeneralSettings _generalSettings; - private string _selectedKeyboardProvider; - - public FlyoutSettingsViewModel(MainManager mainManager) - { - MainManager = mainManager; - Header = "Settings"; - Position = Position.Right; - GeneralSettings = new GeneralSettings(); - - MainManager.Events.Subscribe(this); - } - - public GeneralSettings GeneralSettings - { - get { return _generalSettings; } - set - { - if (Equals(value, _generalSettings)) return; - _generalSettings = value; - NotifyOfPropertyChange(() => GeneralSettings); - } - } - - public MainManager MainManager { get; set; } - - public BindableCollection KeyboardProviders - { - get - { - var collection = new BindableCollection(MainManager.KeyboardManager.KeyboardProviders - .Select(k => k.Name)); - collection.Insert(0, "None"); - return collection; - } - } - - public string SelectedKeyboardProvider - { - get { return _selectedKeyboardProvider; } - set - { - if (value == _selectedKeyboardProvider) return; - _selectedKeyboardProvider = value; - NotifyOfPropertyChange(() => SelectedKeyboardProvider); - if (value == null) - return; - - MainManager.KeyboardManager.ChangeKeyboard( - MainManager.KeyboardManager.KeyboardProviders.FirstOrDefault( - k => k.Name == _selectedKeyboardProvider)); - } - } - - public bool Enabled - { - get { return MainManager.ProgramEnabled; } - set - { - if (value) - MainManager.EnableProgram(); - else - MainManager.DisableProgram(); - } - } - - public string ActiveEffectName - { - get { return _activeEffectName; } - set - { - if (value == _activeEffectName) return; - _activeEffectName = value; - NotifyOfPropertyChange(() => ActiveEffectName); - } - } - - public void Handle(ActiveEffectChanged message) - { - var effectDisplay = message.ActiveEffect.Length > 0 ? message.ActiveEffect : "none"; - ActiveEffectName = $"Active effect: {effectDisplay}"; - } - - public void Handle(ToggleEnabled message) - { - NotifyOfPropertyChange(() => Enabled); - } - - public void ToggleEnabled() - { - if (Enabled) - MainManager.DisableProgram(); - else - MainManager.EnableProgram(); - } - - public void ResetSettings() - { - GeneralSettings.ResetSettings(); - NotifyOfPropertyChange(() => GeneralSettings); - } - - public void SaveSettings() - { - GeneralSettings.SaveSettings(); - } - - public void NavigateTo(string url) - { - Process.Start(new ProcessStartInfo(url)); - } - - protected override void HandleOpen() - { - SelectedKeyboardProvider = General.Default.LastKeyboard.Length > 0 - ? General.Default.LastKeyboard - : "None"; - } - } +using System.Diagnostics; +using System.Linq; +using Artemis.Events; +using Artemis.Managers; +using Artemis.Settings; +using Caliburn.Micro; +using MahApps.Metro.Controls; + +namespace Artemis.ViewModels.Flyouts +{ + public class FlyoutSettingsViewModel : FlyoutBaseViewModel, IHandle, IHandle + { + private string _activeEffectName; + private GeneralSettings _generalSettings; + private string _selectedKeyboardProvider; + + public FlyoutSettingsViewModel(MainManager mainManager) + { + MainManager = mainManager; + Header = "Settings"; + Position = Position.Right; + GeneralSettings = new GeneralSettings(); + + MainManager.Events.Subscribe(this); + } + + public GeneralSettings GeneralSettings + { + get { return _generalSettings; } + set + { + if (Equals(value, _generalSettings)) return; + _generalSettings = value; + NotifyOfPropertyChange(() => GeneralSettings); + } + } + + public MainManager MainManager { get; set; } + + public BindableCollection KeyboardProviders + { + get + { + var collection = new BindableCollection(MainManager.KeyboardManager.KeyboardProviders + .Select(k => k.Name)); + collection.Insert(0, "None"); + return collection; + } + } + + public string SelectedKeyboardProvider + { + get { return _selectedKeyboardProvider; } + set + { + if (value == _selectedKeyboardProvider) return; + _selectedKeyboardProvider = value; + NotifyOfPropertyChange(() => SelectedKeyboardProvider); + if (value == null) + return; + + MainManager.KeyboardManager.ChangeKeyboard( + MainManager.KeyboardManager.KeyboardProviders.FirstOrDefault( + k => k.Name == _selectedKeyboardProvider)); + } + } + + public bool Enabled + { + get { return MainManager.ProgramEnabled; } + set + { + if (value) + MainManager.EnableProgram(); + else + MainManager.DisableProgram(); + } + } + + public string ActiveEffectName + { + get { return _activeEffectName; } + set + { + if (value == _activeEffectName) return; + _activeEffectName = value; + NotifyOfPropertyChange(() => ActiveEffectName); + } + } + + public void Handle(ActiveEffectChanged message) + { + var effectDisplay = string.IsNullOrEmpty(message.ActiveEffect) ? message.ActiveEffect : "none"; + ActiveEffectName = $"Active effect: {effectDisplay}"; + } + + public void Handle(ToggleEnabled message) + { + NotifyOfPropertyChange(() => Enabled); + } + + public void ToggleEnabled() + { + if (Enabled) + MainManager.DisableProgram(); + else + MainManager.EnableProgram(); + } + + public void ResetSettings() + { + GeneralSettings.ResetSettings(); + NotifyOfPropertyChange(() => GeneralSettings); + } + + public void SaveSettings() + { + GeneralSettings.SaveSettings(); + } + + public void NavigateTo(string url) + { + Process.Start(new ProcessStartInfo(url)); + } + + protected override void HandleOpen() + { + SelectedKeyboardProvider = General.Default.LastKeyboard.Length > 0 + ? General.Default.LastKeyboard + : "None"; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/GamesViewModel.cs b/Artemis/Artemis/ViewModels/GamesViewModel.cs index 99d3a1b9b..e8621002c 100644 --- a/Artemis/Artemis/ViewModels/GamesViewModel.cs +++ b/Artemis/Artemis/ViewModels/GamesViewModel.cs @@ -1,39 +1,39 @@ -using Artemis.Managers; -using Artemis.Modules.Games.CounterStrike; -using Artemis.Modules.Games.Dota2; -using Artemis.Modules.Games.RocketLeague; -using Artemis.Modules.Games.TheDivision; -using Artemis.Modules.Games.Witcher3; -using Caliburn.Micro; - -namespace Artemis.ViewModels -{ - public class GamesViewModel : Conductor.Collection.OneActive - { - private readonly CounterStrikeViewModel _counterStrikeVm; - private readonly Dota2ViewModel _dota2Vm; - private readonly RocketLeagueViewModel _rocketLeagueVm; - private readonly Witcher3ViewModel _witcher3Vm; - private readonly TheDivisionViewModel _divisionVm; - - public GamesViewModel(MainManager mainManager) - { - _rocketLeagueVm = new RocketLeagueViewModel(mainManager) {DisplayName = "Rocket League"}; - _counterStrikeVm = new CounterStrikeViewModel(mainManager) {DisplayName = "CS:GO"}; - _dota2Vm = new Dota2ViewModel(mainManager) {DisplayName = "Dota 2"}; - _witcher3Vm = new Witcher3ViewModel(mainManager) {DisplayName = "The Witcher 3"}; - // _divisionVm = new TheDivisionViewModel(mainManager) {DisplayName = "The Division"}; - } - - protected override void OnActivate() - { - base.OnActivate(); - - ActivateItem(_rocketLeagueVm); - ActivateItem(_counterStrikeVm); - ActivateItem(_dota2Vm); - ActivateItem(_witcher3Vm); - // ActivateItem(_divisionVm); - } - } +using Artemis.Managers; +using Artemis.Modules.Games.CounterStrike; +using Artemis.Modules.Games.Dota2; +using Artemis.Modules.Games.RocketLeague; +using Artemis.Modules.Games.TheDivision; +using Artemis.Modules.Games.Witcher3; +using Caliburn.Micro; + +namespace Artemis.ViewModels +{ + public class GamesViewModel : Conductor.Collection.OneActive + { + private readonly CounterStrikeViewModel _counterStrikeVm; + private readonly Dota2ViewModel _dota2Vm; + private readonly RocketLeagueViewModel _rocketLeagueVm; + private readonly Witcher3ViewModel _witcher3Vm; + private readonly TheDivisionViewModel _divisionVm; + + public GamesViewModel(MainManager mainManager) + { + _rocketLeagueVm = new RocketLeagueViewModel(mainManager) {DisplayName = "Rocket League"}; + _counterStrikeVm = new CounterStrikeViewModel(mainManager) {DisplayName = "CS:GO"}; + _dota2Vm = new Dota2ViewModel(mainManager) {DisplayName = "Dota 2"}; + _witcher3Vm = new Witcher3ViewModel(mainManager) {DisplayName = "The Witcher 3"}; + _divisionVm = new TheDivisionViewModel(mainManager) {DisplayName = "The Division"}; + } + + protected override void OnActivate() + { + base.OnActivate(); + + ActivateItem(_rocketLeagueVm); + ActivateItem(_counterStrikeVm); + ActivateItem(_dota2Vm); + ActivateItem(_witcher3Vm); + ActivateItem(_divisionVm); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/LayerEditor/LayerConditionViewModel.cs b/Artemis/Artemis/ViewModels/LayerEditor/LayerConditionViewModel.cs new file mode 100644 index 000000000..82d8ebdcd --- /dev/null +++ b/Artemis/Artemis/ViewModels/LayerEditor/LayerConditionViewModel.cs @@ -0,0 +1,201 @@ +using System.ComponentModel; +using System.Linq; +using Artemis.Models.Profiles; +using Artemis.Utilities; +using Caliburn.Micro; + +namespace Artemis.ViewModels.LayerEditor +{ + public class LayerConditionViewModel : Screen + { + private readonly NamedOperator[] _boolOperators = + { + new NamedOperator("True", "== True"), + new NamedOperator("False", "== False") + }; + + private readonly LayerEditorViewModel _conditionModel; + + private readonly NamedOperator[] _int32Operators = + { + new NamedOperator("Lower than", "<"), + new NamedOperator("Lower or equal to", "<="), + new NamedOperator("Higher than", ">"), + new NamedOperator("Higher or equal to", ">="), + new NamedOperator("Equal to", "=="), + new NamedOperator("Not equal to", "!=") + }; + + private readonly NamedOperator[] _operators = + { + new NamedOperator("Equal to", "=="), + new NamedOperator("Not equal to", "!=") + }; + + private bool _preselecting; + + private GeneralHelpers.PropertyCollection _selectedDataModelProp; + private NamedOperator _selectedOperator; + private string _userValue; + private bool _userValueIsVisible; + + public LayerConditionViewModel(LayerEditorViewModel conditionModel, LayerConditionModel layerConditionModel, + BindableCollection dataModelProps) + { + _conditionModel = conditionModel; + _preselecting = false; + + LayerConditionModel = layerConditionModel; + DataModelProps = dataModelProps; + Operators = new BindableCollection(); + + PropertyChanged += UpdateModel; + PropertyChanged += UpdateForm; + + PreSelect(); + } + + public string UserValue + { + get { return _userValue; } + set + { + if (value == _userValue) return; + _userValue = value; + NotifyOfPropertyChange(() => UserValue); + } + } + + public LayerConditionModel LayerConditionModel { get; set; } + public BindableCollection DataModelProps { get; set; } + public BindableCollection Operators { get; set; } + + public GeneralHelpers.PropertyCollection SelectedDataModelProp + { + get { return _selectedDataModelProp; } + set + { + if (value.Equals(_selectedDataModelProp)) return; + _selectedDataModelProp = value; + NotifyOfPropertyChange(() => SelectedDataModelProp); + } + } + + + public bool UserValueIsVisible + { + get { return _userValueIsVisible; } + set + { + if (value == _userValueIsVisible) return; + _userValueIsVisible = value; + NotifyOfPropertyChange(() => UserValueIsVisible); + } + } + + public NamedOperator SelectedOperator + { + get { return _selectedOperator; } + set + { + if (value.Equals(_selectedOperator)) return; + _selectedOperator = value; + NotifyOfPropertyChange(() => SelectedOperator); + } + } + + /// + /// Handles updating the form to match the selected data model property + /// + /// + /// + private void UpdateForm(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName != "SelectedDataModelProp") + return; + + Operators.Clear(); + if (SelectedDataModelProp.EnumValues != null) + { + Operators.AddRange( + SelectedDataModelProp.EnumValues.Select(val => new NamedOperator(val.SplitCamelCase(), "== " + val))); + UserValueIsVisible = false; + } + else + switch (SelectedDataModelProp.Type) + { + case "Int32": + Operators.AddRange(_int32Operators); + UserValueIsVisible = true; + break; + case "Boolean": + Operators.AddRange(_boolOperators); + UserValueIsVisible = false; + break; + default: + Operators.AddRange(_operators); + UserValueIsVisible = true; + break; + } + + SelectedOperator = Operators.First(); + } + + /// + /// Handles saving user input to the model + /// TODO: Data validation? + /// + /// + /// + private void UpdateModel(object sender, PropertyChangedEventArgs e) + { + // Don't mess with model during preselect + if (_preselecting) + return; + + // Only care about these fields + if (e.PropertyName != "UserValue" && + e.PropertyName != "SelectedOperator" && + e.PropertyName != "SelectedDataModelProp") + return; + + LayerConditionModel.Field = SelectedDataModelProp.Path; + LayerConditionModel.Operator = SelectedOperator.Value; + LayerConditionModel.Value = UserValue; + LayerConditionModel.Type = SelectedDataModelProp.Type; + } + + /// + /// Setup the current UI elements to show the backing model + /// + private void PreSelect() + { + _preselecting = true; + SelectedDataModelProp = DataModelProps.FirstOrDefault(m => m.Path == LayerConditionModel.Field); + SelectedOperator = Operators.FirstOrDefault(o => o.Value == LayerConditionModel.Operator); + UserValue = LayerConditionModel.Value; + LayerConditionModel.Type = SelectedDataModelProp.Type; + _preselecting = false; + } + + /// + /// Delete the current model from the parent + /// + public void Delete() + { + _conditionModel.DeleteCondition(this, LayerConditionModel); + } + + public struct NamedOperator + { + public string Display { get; set; } + public string Value { get; set; } + + public NamedOperator(string display, string value) + { + Display = display; + Value = value; + } + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/LayerEditor/LayerDynamicPropertiesViewModel.cs b/Artemis/Artemis/ViewModels/LayerEditor/LayerDynamicPropertiesViewModel.cs new file mode 100644 index 000000000..18d5b8b6d --- /dev/null +++ b/Artemis/Artemis/ViewModels/LayerEditor/LayerDynamicPropertiesViewModel.cs @@ -0,0 +1,159 @@ +using System.ComponentModel; +using System.Linq; +using Artemis.Models.Profiles; +using Artemis.Utilities; +using Caliburn.Micro; + +namespace Artemis.ViewModels.LayerEditor +{ + public class LayerDynamicPropertiesViewModel : Screen + { + private readonly LayerModel _layer; + private readonly string _property; + private LayerDynamicPropertiesModel _layerDynamicPropertiesModelProposed; + private LayerPropertyType _layerPropertyType; + private string _name; + private GeneralHelpers.PropertyCollection _selectedSource; + private GeneralHelpers.PropertyCollection _selectedTarget; + private bool _sourcesIsVisible; + private bool _userSourceIsVisible; + + public LayerDynamicPropertiesViewModel(string property, + BindableCollection dataModelProps, LayerModel layer) + { + _property = property; + _layer = layer; + + // Look for the existing property model + LayerDynamicPropertiesModelProposed = new LayerDynamicPropertiesModel(); + var original = _layer.LayerProperties.FirstOrDefault(lp => lp.LayerProperty == _property); + if (original == null) + { + LayerDynamicPropertiesModelProposed.LayerProperty = property; + LayerDynamicPropertiesModelProposed.LayerPropertyType = LayerPropertyType.None; + } + else + { + GeneralHelpers.CopyProperties(LayerDynamicPropertiesModelProposed, original); + } + + Name = property + ":"; + Targets = new BindableCollection(); + Targets.AddRange(dataModelProps.Where(p => p.Type == "Int32")); + Sources = new BindableCollection(); + Sources.AddRange(dataModelProps.Where(p => p.Type == "Int32")); + + PropertyChanged += OnPropertyChanged; + + SelectedTarget = + dataModelProps.FirstOrDefault(p => p.Path == LayerDynamicPropertiesModelProposed.GameProperty); + SelectedSource = + dataModelProps.FirstOrDefault(p => p.Path == LayerDynamicPropertiesModelProposed.PercentageSource); + LayerPropertyType = LayerDynamicPropertiesModelProposed.LayerPropertyType; + } + + public LayerPropertyType LayerPropertyType + { + get { return _layerPropertyType; } + set + { + if (value == _layerPropertyType) return; + _layerPropertyType = value; + NotifyOfPropertyChange(() => LayerPropertyType); + } + } + + public string Name + { + get { return _name; } + set + { + if (value == _name) return; + _name = value; + NotifyOfPropertyChange(() => Name); + } + } + + public LayerDynamicPropertiesModel LayerDynamicPropertiesModelProposed + { + get { return _layerDynamicPropertiesModelProposed; } + set + { + if (Equals(value, _layerDynamicPropertiesModelProposed)) return; + _layerDynamicPropertiesModelProposed = value; + NotifyOfPropertyChange(() => LayerDynamicPropertiesModelProposed); + } + } + + public BindableCollection Targets { get; set; } + + public GeneralHelpers.PropertyCollection SelectedTarget + { + get { return _selectedTarget; } + set + { + if (value.Equals(_selectedTarget)) return; + _selectedTarget = value; + NotifyOfPropertyChange(() => SelectedTarget); + } + } + + public BindableCollection Sources { get; set; } + + public GeneralHelpers.PropertyCollection SelectedSource + { + get { return _selectedSource; } + set + { + if (value.Equals(_selectedSource)) return; + _selectedSource = value; + NotifyOfPropertyChange(() => SelectedSource); + } + } + + public bool SourcesIsVisible + { + get { return _sourcesIsVisible; } + set + { + if (value == _sourcesIsVisible) return; + _sourcesIsVisible = value; + NotifyOfPropertyChange(() => SourcesIsVisible); + } + } + + public bool UserSourceIsVisible + { + get { return _userSourceIsVisible; } + set + { + if (value == _userSourceIsVisible) return; + _userSourceIsVisible = value; + NotifyOfPropertyChange(() => UserSourceIsVisible); + } + } + + private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "SelectedTarget") + LayerDynamicPropertiesModelProposed.GameProperty = SelectedTarget.Path; + if (e.PropertyName == "SelectedSource") + LayerDynamicPropertiesModelProposed.PercentageSource = SelectedSource.Path; + if (e.PropertyName == "LayerPropertyType") + { + LayerDynamicPropertiesModelProposed.LayerPropertyType = LayerPropertyType; + UserSourceIsVisible = LayerPropertyType == LayerPropertyType.PercentageOf; + SourcesIsVisible = LayerPropertyType == LayerPropertyType.PercentageOfProperty; + } + } + + public void Apply() + { + var original = _layer.LayerProperties.FirstOrDefault(lp => lp.LayerProperty == _property); + if (original == null) + _layer.LayerProperties.Add(LayerDynamicPropertiesModelProposed); + else + GeneralHelpers.CopyProperties(original, LayerDynamicPropertiesModelProposed); + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/LayerEditor/LayerEditorViewModel.cs b/Artemis/Artemis/ViewModels/LayerEditor/LayerEditorViewModel.cs new file mode 100644 index 000000000..944322a1c --- /dev/null +++ b/Artemis/Artemis/ViewModels/LayerEditor/LayerEditorViewModel.cs @@ -0,0 +1,168 @@ +using System; +using System.ComponentModel; +using System.Linq; +using System.Threading; +using System.Windows.Media; +using Artemis.KeyboardProviders; +using Artemis.Models.Profiles; +using Artemis.Utilities; +using Caliburn.Micro; + +namespace Artemis.ViewModels.LayerEditor +{ + public class LayerEditorViewModel : Screen + { + private readonly KeyboardProvider _activeKeyboard; + private readonly BackgroundWorker _previewWorker; + private readonly bool _wasEnabled; + private LayerModel _layer; + private LayerModel _proposedLayer; + private LayerPropertiesModel _proposedProperties; + + public LayerEditorViewModel(KeyboardProvider activeKeyboard, LayerModel layer) + { + _activeKeyboard = activeKeyboard; + _wasEnabled = layer.Enabled; + + Layer = layer; + ProposedLayer = new LayerModel(); + GeneralHelpers.CopyProperties(ProposedLayer, Layer); + Layer.Enabled = false; + DataModelProps = new BindableCollection(); + ProposedProperties = new LayerPropertiesModel(); + DataModelProps.AddRange(GeneralHelpers.GenerateTypeMap()); + LayerConditionVms = + new BindableCollection>( + layer.LayerConditions.Select(c => new LayerConditionViewModel(this, c, DataModelProps))); + HeightProperties = new LayerDynamicPropertiesViewModel("Height", DataModelProps, layer); + WidthProperties = new LayerDynamicPropertiesViewModel("Width", DataModelProps, layer); + OpacityProperties = new LayerDynamicPropertiesViewModel("Opacity", DataModelProps, layer); + + _previewWorker = new BackgroundWorker {WorkerSupportsCancellation = true}; + _previewWorker.DoWork += PreviewWorkerOnDoWork; + _previewWorker.RunWorkerAsync(); + + PropertyChanged += AnimationUiHandler; + PreSelect(); + } + + public LayerDynamicPropertiesViewModel OpacityProperties { get; set; } + + public LayerDynamicPropertiesViewModel WidthProperties { get; set; } + + public LayerDynamicPropertiesViewModel HeightProperties { get; set; } + + public BindableCollection DataModelProps { get; set; } + + public BindableCollection LayerTypes => new BindableCollection(); + + public BindableCollection> LayerConditionVms { get; set; } + + public LayerModel Layer + { + get { return _layer; } + set + { + if (Equals(value, _layer)) return; + _layer = value; + NotifyOfPropertyChange(() => Layer); + } + } + + public LayerModel ProposedLayer + { + get { return _proposedLayer; } + set + { + if (Equals(value, _proposedLayer)) return; + _proposedLayer = value; + NotifyOfPropertyChange(() => ProposedLayer); + } + } + + public LayerPropertiesModel ProposedProperties + { + get { return _proposedProperties; } + set + { + if (Equals(value, _proposedProperties)) return; + _proposedProperties = value; + NotifyOfPropertyChange(() => ProposedProperties); + } + } + + public ImageSource LayerImage + { + get + { + var keyboardRect = _activeKeyboard.KeyboardRectangle(4); + + var visual = new DrawingVisual(); + using (var drawingContext = visual.RenderOpen()) + { + // Setup the DrawingVisual's size + drawingContext.PushClip(new RectangleGeometry(keyboardRect)); + drawingContext.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, keyboardRect); + + // Draw the layer + _layer.DrawPreview(drawingContext); + + // Remove the clip + drawingContext.Pop(); + } + var image = new DrawingImage(visual.Drawing); + + return image; + } + } + + private void PreviewWorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs) + { + while (!_previewWorker.CancellationPending) + { + NotifyOfPropertyChange(() => LayerImage); + Thread.Sleep(1000/25); + } + } + + public void PreSelect() + { + GeneralHelpers.CopyProperties(ProposedProperties, Layer.UserProps); + } + + private void AnimationUiHandler(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName != "_proposedProperties") + return; + } + + public void AddCondition() + { + var condition = new LayerConditionModel(); + Layer.LayerConditions.Add(condition); + LayerConditionVms.Add(new LayerConditionViewModel(this, condition, DataModelProps)); + } + + public void Apply() + { + GeneralHelpers.CopyProperties(Layer.UserProps, ProposedProperties); + HeightProperties.Apply(); + WidthProperties.Apply(); + OpacityProperties.Apply(); + } + + public void DeleteCondition(LayerConditionViewModel layerConditionViewModel, + LayerConditionModel layerConditionModel) + { + LayerConditionVms.Remove(layerConditionViewModel); + Layer.LayerConditions.Remove(layerConditionModel); + } + + public override void CanClose(Action callback) + { + _previewWorker.CancelAsync(); + _layer.Enabled = _wasEnabled; + base.CanClose(callback); + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/OverlaysViewModel.cs b/Artemis/Artemis/ViewModels/OverlaysViewModel.cs index c6290e7e1..22beca4ad 100644 --- a/Artemis/Artemis/ViewModels/OverlaysViewModel.cs +++ b/Artemis/Artemis/ViewModels/OverlaysViewModel.cs @@ -1,29 +1,29 @@ -using Artemis.Managers; -using Artemis.Modules.Overlays.VolumeDisplay; -using Caliburn.Micro; - -namespace Artemis.ViewModels -{ - public class OverlaysViewModel : Conductor.Collection.OneActive - { - private readonly MainManager _mainManager; - private VolumeDisplayViewModel _volumeDisplayVm; - - public OverlaysViewModel(MainManager mainManager) - { - _mainManager = mainManager; - } - - protected override void OnActivate() - { - base.OnActivate(); - - Items.Clear(); - - // This VM appears to be going out of scope, so recreating it every time just to be sure. - _volumeDisplayVm = new VolumeDisplayViewModel(_mainManager) {DisplayName = "Volume Display"}; - ActivateItem(_volumeDisplayVm); - ActiveItem = _volumeDisplayVm; - } - } +using Artemis.Managers; +using Artemis.Modules.Overlays.VolumeDisplay; +using Caliburn.Micro; + +namespace Artemis.ViewModels +{ + public class OverlaysViewModel : Conductor.Collection.OneActive + { + private readonly MainManager _mainManager; + private VolumeDisplayViewModel _volumeDisplayVm; + + public OverlaysViewModel(MainManager mainManager) + { + _mainManager = mainManager; + } + + protected override void OnActivate() + { + base.OnActivate(); + + Items.Clear(); + + // This VM appears to be going out of scope, so recreating it every time just to be sure. + _volumeDisplayVm = new VolumeDisplayViewModel(_mainManager) {DisplayName = "Volume Display"}; + ActivateItem(_volumeDisplayVm); + ActiveItem = _volumeDisplayVm; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs b/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs new file mode 100644 index 000000000..5bf104d05 --- /dev/null +++ b/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs @@ -0,0 +1,503 @@ +using System; +using System.ComponentModel; +using System.Drawing.Imaging; +using System.Dynamic; +using System.IO; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Xml.Serialization; +using Artemis.DAL; +using Artemis.Events; +using Artemis.KeyboardProviders; +using Artemis.Managers; +using Artemis.Models; +using Artemis.Models.Profiles; +using Artemis.Utilities; +using Artemis.ViewModels.LayerEditor; +using Caliburn.Micro; +using MahApps.Metro; + +namespace Artemis.ViewModels +{ + public class ProfileEditorViewModel : Screen, IHandle + { + private readonly GameModel _gameModel; + private readonly MainManager _mainManager; + private DateTime _downTime; + private LayerModel _draggingLayer; + private Point? _draggingLayerOffset; + private LayerEditorViewModel _editorVm; + private Cursor _keyboardPreviewCursor; + private BindableCollection _layers; + private BindableCollection _profiles; + private bool _resizing; + private LayerModel _selectedLayer; + private ProfileModel _selectedProfile; + + public ProfileEditorViewModel(MainManager mainManager, GameModel gameModel) + { + _mainManager = mainManager; + _gameModel = gameModel; + + Profiles = new BindableCollection(); + Layers = new BindableCollection(); + _mainManager.Events.Subscribe(this); + + PropertyChanged += PropertyChangeHandler; + LoadProfiles(); + } + + public BindableCollection Profiles + { + get { return _profiles; } + set + { + if (Equals(value, _profiles)) return; + _profiles = value; + NotifyOfPropertyChange(() => Profiles); + } + } + + public BindableCollection Layers + { + get { return _layers; } + set + { + if (Equals(value, _layers)) return; + _layers = value; + NotifyOfPropertyChange(() => Layers); + } + } + + public LayerModel SelectedLayer + { + get { return _selectedLayer; } + set + { + if (Equals(value, _selectedLayer)) return; + _selectedLayer = value; + NotifyOfPropertyChange(() => SelectedLayer); + NotifyOfPropertyChange(() => CanRemoveLayer); + } + } + + public Cursor KeyboardPreviewCursor + { + get { return _keyboardPreviewCursor; } + set + { + if (Equals(value, _keyboardPreviewCursor)) return; + _keyboardPreviewCursor = value; + NotifyOfPropertyChange(() => KeyboardPreviewCursor); + } + } + + public ProfileModel SelectedProfile + { + get { return _selectedProfile; } + set + { + if (Equals(value, _selectedProfile)) return; + _selectedProfile = value; + + Layers.Clear(); + Layers.AddRange(_selectedProfile?.Layers); + + NotifyOfPropertyChange(() => SelectedProfile); + NotifyOfPropertyChange(() => CanAddLayer); + NotifyOfPropertyChange(() => CanRemoveLayer); + } + } + + public ImageSource KeyboardPreview + { + get + { + if (_selectedProfile == null || ActiveKeyboard == null) + return null; + + var keyboardRect = ActiveKeyboard.KeyboardRectangle(4); + var visual = new DrawingVisual(); + using (var drawingContext = visual.RenderOpen()) + { + // Setup the DrawingVisual's size + drawingContext.PushClip(new RectangleGeometry(keyboardRect)); + drawingContext.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, keyboardRect); + + // Draw the layers + foreach (var layerModel in _selectedProfile.Layers.OrderByDescending(l => l.Order)) + layerModel.DrawPreview(drawingContext); + + // Get the selection color + var color = (Color) ThemeManager.DetectAppStyle(Application.Current).Item2.Resources["AccentColor"]; + var pen = new Pen(new SolidColorBrush(color), 0.4); + + // Draw the selection outline and resize indicator + if (SelectedLayer != null && SelectedLayer.Enabled) + { + var layerRect = SelectedLayer.UserProps.GetRect(); + // Deflate the rect so that the border is drawn on the inside + layerRect.Inflate(-0.2, -0.2); + + // Draw an outline around the selected layer + drawingContext.DrawRectangle(null, pen, layerRect); + // Draw a resize indicator in the bottom-right + drawingContext.DrawLine(pen, + new Point(layerRect.BottomRight.X - 1, layerRect.BottomRight.Y - 0.5), + new Point(layerRect.BottomRight.X - 1.2, layerRect.BottomRight.Y - 0.7)); + drawingContext.DrawLine(pen, + new Point(layerRect.BottomRight.X - 0.5, layerRect.BottomRight.Y - 1), + new Point(layerRect.BottomRight.X - 0.7, layerRect.BottomRight.Y - 1.2)); + drawingContext.DrawLine(pen, + new Point(layerRect.BottomRight.X - 0.5, layerRect.BottomRight.Y - 0.5), + new Point(layerRect.BottomRight.X - 0.7, layerRect.BottomRight.Y - 0.7)); + } + + // Remove the clip + drawingContext.Pop(); + } + var image = new DrawingImage(visual.Drawing); + + return image; + } + } + + public ImageSource KeyboardImage + { + get + { + using (var memory = new MemoryStream()) + { + if (ActiveKeyboard?.PreviewSettings.Image == null) + return null; + + ActiveKeyboard.PreviewSettings.Image.Save(memory, ImageFormat.Png); + memory.Position = 0; + + var bitmapImage = new BitmapImage(); + bitmapImage.BeginInit(); + bitmapImage.StreamSource = memory; + bitmapImage.CacheOption = BitmapCacheOption.OnLoad; + bitmapImage.EndInit(); + + return bitmapImage; + } + } + } + + public PreviewSettings? PreviewSettings => ActiveKeyboard?.PreviewSettings; + + public bool CanAddLayer => _selectedProfile != null; + public bool CanRemoveLayer => _selectedProfile != null && _selectedLayer != null; + + private KeyboardProvider ActiveKeyboard => _mainManager.KeyboardManager.ActiveKeyboard; + + /// + /// Handles chaning the active keyboard, updating the preview image and profiles collection + /// + /// + public void Handle(ActiveKeyboardChanged message) + { + NotifyOfPropertyChange(() => KeyboardImage); + NotifyOfPropertyChange(() => PreviewSettings); + LoadProfiles(); + } + + /// + /// Handles refreshing the layer preview + /// + /// + /// + private void PropertyChangeHandler(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "KeyboardPreview") + return; + + NotifyOfPropertyChange(() => KeyboardPreview); + + if (SelectedProfile != null) + ProfileProvider.AddOrUpdate(SelectedProfile); + } + + /// + /// Loads all profiles for the current game and keyboard + /// + private void LoadProfiles() + { + Profiles.Clear(); + Profiles.AddRange(ProfileProvider.GetAll(_gameModel)); + SelectedProfile = Profiles.FirstOrDefault(); + } + + /// + /// Adds a new profile to the current game and keyboard + /// + public async void AddProfile() + { + var name = await _mainManager.DialogService.ShowInputDialog("Add new profile", + "Please provide a profile name unique to this game and keyboard."); + if (name.Length < 1) + { + _mainManager.DialogService.ShowMessageBox("Invalid profile name", "Please provide a valid profile name"); + return; + } + + var profile = new ProfileModel + { + Name = name, + KeyboardName = ActiveKeyboard.Name, + GameName = _gameModel.Name + }; + + if (ProfileProvider.GetAll().Contains(profile)) + { + var overwrite = await _mainManager.DialogService.ShowQuestionMessageBox("Overwrite existing profile", + "A profile with this name already exists for this game. Would you like to overwrite it?"); + if (!overwrite.Value) + return; + } + + ProfileProvider.AddOrUpdate(profile); + + LoadProfiles(); + SelectedProfile = profile; + } + + public void ToggleEnabled(LayerModel layer) + { + NotifyOfPropertyChange(() => KeyboardPreview); + } + + /// + /// Opens a new LayerEditorView for the given layer + /// + /// The layer to open the view for + public void LayerEditor(LayerModel layer) + { + IWindowManager manager = new WindowManager(); + _editorVm = new LayerEditorViewModel(ActiveKeyboard, layer); + dynamic settings = new ExpandoObject(); + + settings.Title = "Artemis | Edit " + layer.Name; + manager.ShowDialog(_editorVm, null, settings); + + // Refresh the layer list and reselect the last layer + NotifyOfPropertyChange(() => Layers); + SelectedLayer = layer; + } + + /// + /// Adds a new layer to the profile and selects it + /// + public void AddLayer() + { + if (_selectedProfile == null) + return; + + var layer = SelectedProfile.AddLayer(); + Layers.Add(layer); + + SelectedLayer = layer; + } + + /// + /// Removes the currently selected layer from the profile + /// + public void RemoveLayer() + { + if (_selectedProfile == null || _selectedLayer == null) + return; + + SelectedProfile.Layers.Remove(_selectedLayer); + Layers.Remove(_selectedLayer); + + SelectedProfile.FixOrder(); + } + + /// + /// Removes the given layer from the profile + /// + /// + public void RemoveLayerFromMenu(LayerModel layer) + { + SelectedProfile.Layers.Remove(layer); + Layers.Remove(layer); + + SelectedProfile.FixOrder(); + } + + /// + /// Clones the given layer and adds it to the profile, on top of the original + /// + /// + public void CloneLayer(LayerModel layer) + { + var clone = GeneralHelpers.Clone(layer); + clone.Order = layer.Order - 1; + SelectedProfile.Layers.Add(clone); + Layers.Add(clone); + + SelectedProfile.FixOrder(); + } + + /// + /// Moves the currently selected layer up in the profile's layer tree + /// + public void LayerUp() + { + if (SelectedLayer == null) + return; + + var reorderLayer = SelectedLayer; + + if (SelectedLayer.ParentLayer != null) + SelectedLayer.ParentLayer.Reorder(SelectedLayer, true); + else + SelectedLayer.ParentProfile.Reorder(SelectedLayer, true); + + NotifyOfPropertyChange(() => Layers); + SelectedLayer = reorderLayer; + } + + /// + /// Moves the currently selected layer down in the profile's layer tree + /// + public void LayerDown() + { + if (SelectedLayer == null) + return; + + var reorderLayer = SelectedLayer; + + if (SelectedLayer.ParentLayer != null) + SelectedLayer.ParentLayer.Reorder(SelectedLayer, false); + else + SelectedLayer.ParentProfile.Reorder(SelectedLayer, false); + + NotifyOfPropertyChange(() => Layers); + SelectedLayer = reorderLayer; + } + + /// + /// Handler for clicking + /// + /// + public void MouseDownKeyboardPreview(MouseButtonEventArgs e) + { + if (e.LeftButton == MouseButtonState.Pressed) + _downTime = DateTime.Now; + } + + /// + /// Second handler for clicking, selects a the layer the user clicked on + /// if the used clicked on an empty spot, deselects the current layer + /// + /// + public void MouseUpKeyboardPreview(MouseButtonEventArgs e) + { + var timeSinceDown = DateTime.Now - _downTime; + if (!(timeSinceDown.TotalMilliseconds < 500)) + return; + + var pos = e.GetPosition((Image) e.OriginalSource); + var x = pos.X/((double) ActiveKeyboard.PreviewSettings.Width/ActiveKeyboard.Width); + var y = pos.Y/((double) ActiveKeyboard.PreviewSettings.Height/ActiveKeyboard.Height); + + var hoverLayer = SelectedProfile.Layers.OrderBy(l => l.Order).Where(l => l.Enabled) + .FirstOrDefault(l => l.UserProps.GetRect(1).Contains(x, y)); + SelectedLayer = hoverLayer; + } + + /// + /// Handler for resizing and moving the currently selected layer + /// + /// + public void MouseMoveKeyboardPreview(MouseEventArgs e) + { + var pos = e.GetPosition((Image) e.OriginalSource); + var x = pos.X/((double) ActiveKeyboard.PreviewSettings.Width/ActiveKeyboard.Width); + var y = pos.Y/((double) ActiveKeyboard.PreviewSettings.Height/ActiveKeyboard.Height); + var hoverLayer = SelectedProfile.Layers.OrderBy(l => l.Order).Where(l => l.Enabled) + .FirstOrDefault(l => l.UserProps.GetRect(1).Contains(x, y)); + + HandleDragging(e, x, y, hoverLayer); + + if (hoverLayer == null) + { + KeyboardPreviewCursor = Cursors.Arrow; + return; + } + + + // Turn the mouse pointer into a hand if hovering over an active layer + if (hoverLayer == SelectedLayer) + { + var rect = hoverLayer.UserProps.GetRect(1); + KeyboardPreviewCursor = + Math.Sqrt(Math.Pow(x - rect.BottomRight.X, 2) + Math.Pow(y - rect.BottomRight.Y, 2)) < 0.6 + ? Cursors.SizeNWSE + : Cursors.SizeAll; + } + else + KeyboardPreviewCursor = Cursors.Hand; + } + + /// + /// Handles dragging the given layer + /// + /// + /// + /// + /// + private void HandleDragging(MouseEventArgs e, double x, double y, LayerModel hoverLayer) + { + // Reset the dragging state on mouse release + if (e.LeftButton == MouseButtonState.Released || + (_draggingLayer != null && _selectedLayer != _draggingLayer)) + { + _draggingLayerOffset = null; + _draggingLayer = null; + return; + } + + if (SelectedLayer == null) + return; + + // Setup the dragging state on mouse press + if (_draggingLayerOffset == null && hoverLayer != null && e.LeftButton == MouseButtonState.Pressed) + { + var layerRect = hoverLayer.UserProps.GetRect(1); + _draggingLayerOffset = new Point(x - SelectedLayer.UserProps.X, y - SelectedLayer.UserProps.Y); + _draggingLayer = hoverLayer; + if (Math.Sqrt(Math.Pow(x - layerRect.BottomRight.X, 2) + Math.Pow(y - layerRect.BottomRight.Y, 2)) < 0.6) + _resizing = true; + else + _resizing = false; + } + + if (_draggingLayerOffset == null || _draggingLayer == null || (_draggingLayer != SelectedLayer)) + return; + + // If no setup or reset was done, handle the actual dragging action + if (_resizing) + { + _draggingLayer.UserProps.Width = (int) Math.Round(x - _draggingLayer.UserProps.X); + _draggingLayer.UserProps.Height = (int) Math.Round(y - _draggingLayer.UserProps.Y); + if (_draggingLayer.UserProps.Width < 1) + _draggingLayer.UserProps.Width = 1; + if (_draggingLayer.UserProps.Height < 1) + _draggingLayer.UserProps.Height = 1; + } + else + { + _draggingLayer.UserProps.X = (int) Math.Round(x - _draggingLayerOffset.Value.X); + _draggingLayer.UserProps.Y = (int) Math.Round(y - _draggingLayerOffset.Value.Y); + } + NotifyOfPropertyChange(() => KeyboardPreview); + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/ShellViewModel.cs b/Artemis/Artemis/ViewModels/ShellViewModel.cs index 37cb3bc0b..c3455df20 100644 --- a/Artemis/Artemis/ViewModels/ShellViewModel.cs +++ b/Artemis/Artemis/ViewModels/ShellViewModel.cs @@ -1,59 +1,59 @@ -using System.Linq; -using Artemis.Managers; -using Artemis.Services; -using Artemis.ViewModels.Flyouts; -using Caliburn.Micro; - -namespace Artemis.ViewModels -{ - public sealed class ShellViewModel : Conductor.Collection.OneActive - { - private readonly EffectsViewModel _effectsVm; - private readonly GamesViewModel _gamesVm; - private readonly OverlaysViewModel _overlaysVm; - private readonly WelcomeViewModel _welcomeVm; - - public ShellViewModel() - { - var dialogService = new MetroDialogService(this); - IEventAggregator events = new EventAggregator(); - - MainManager = new MainManager(events, dialogService); - DisplayName = "Artemis"; - - _welcomeVm = new WelcomeViewModel {DisplayName = "Welcome"}; - _effectsVm = new EffectsViewModel(MainManager) {DisplayName = "Effects"}; - _gamesVm = new GamesViewModel(MainManager) {DisplayName = "Games"}; - _overlaysVm = new OverlaysViewModel(MainManager) {DisplayName = "Overlays"}; - - Flyouts.Add(new FlyoutSettingsViewModel(MainManager)); - } - - public IObservableCollection Flyouts { get; set; } = - new BindableCollection(); - - public MainManager MainManager { get; set; } - - protected override void OnActivate() - { - base.OnActivate(); - - ActivateItem(_welcomeVm); - ActivateItem(_effectsVm); - ActivateItem(_gamesVm); - ActivateItem(_overlaysVm); - - ActiveItem = _welcomeVm; - } - - public void Settings() - { - Flyouts.First().IsOpen = !Flyouts.First().IsOpen; - } - - public void CloseSettings() - { - Flyouts.First().IsOpen = false; - } - } +using System.Linq; +using Artemis.Managers; +using Artemis.Services; +using Artemis.ViewModels.Flyouts; +using Caliburn.Micro; + +namespace Artemis.ViewModels +{ + public sealed class ShellViewModel : Conductor.Collection.OneActive + { + private readonly EffectsViewModel _effectsVm; + private readonly GamesViewModel _gamesVm; + private readonly OverlaysViewModel _overlaysVm; + private readonly WelcomeViewModel _welcomeVm; + + public ShellViewModel() + { + var dialogService = new MetroDialogService(this); + IEventAggregator events = new EventAggregator(); + + MainManager = new MainManager(events, dialogService); + DisplayName = "Artemis"; + + _welcomeVm = new WelcomeViewModel {DisplayName = "Welcome"}; + _effectsVm = new EffectsViewModel(MainManager) {DisplayName = "Effects"}; + _gamesVm = new GamesViewModel(MainManager) {DisplayName = "Games"}; + _overlaysVm = new OverlaysViewModel(MainManager) {DisplayName = "Overlays"}; + + Flyouts.Add(new FlyoutSettingsViewModel(MainManager)); + } + + public IObservableCollection Flyouts { get; set; } = + new BindableCollection(); + + public MainManager MainManager { get; set; } + + protected override void OnActivate() + { + base.OnActivate(); + + ActivateItem(_welcomeVm); + ActivateItem(_effectsVm); + ActivateItem(_gamesVm); + ActivateItem(_overlaysVm); + + ActiveItem = _welcomeVm; + } + + public void Settings() + { + Flyouts.First().IsOpen = !Flyouts.First().IsOpen; + } + + public void CloseSettings() + { + Flyouts.First().IsOpen = false; + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/SystemTrayViewModel.cs b/Artemis/Artemis/ViewModels/SystemTrayViewModel.cs index 1b9bc164d..bda3ecf4f 100644 --- a/Artemis/Artemis/ViewModels/SystemTrayViewModel.cs +++ b/Artemis/Artemis/ViewModels/SystemTrayViewModel.cs @@ -1,54 +1,53 @@ -using System; -using System.Windows; -using Artemis.Events; -using Artemis.Properties; -using Artemis.Settings; -using Artemis.Utilities; -using Caliburn.Micro; - -namespace Artemis.ViewModels -{ - public class SystemTrayViewModel : Screen, IHandle - { - private readonly ShellViewModel _shellViewModel; - - private readonly IWindowManager _windowManager; - private string _activeIcon; - private bool _checkedForUpdate; - private bool _enabled; - private string _toggleText; - - public SystemTrayViewModel(IWindowManager windowManager, ShellViewModel shellViewModel) - { - _windowManager = windowManager; - _shellViewModel = shellViewModel; - _shellViewModel.MainManager.Events.Subscribe(this); - _shellViewModel.MainManager.EnableProgram(); - _checkedForUpdate = false; - //ActiveIcon = "../logo.ico"; - - if (General.Default.ShowOnStartup) - ShowWindow(); - } - - public bool CanShowWindow => !_shellViewModel.IsActive; - - public bool CanHideWindow => _shellViewModel.IsActive; - - public bool Enabled - { - get { return _enabled; } - set - { - if (value == _enabled) return; - _enabled = value; - - ToggleText = _enabled ? "Disable Artemis" : "Enable Artemis"; - ActiveIcon = _enabled ? "../Resources/logo.ico" : "../Resources/logo-disabled.ico"; - NotifyOfPropertyChange(() => Enabled); - } - } - +using System; +using System.Windows; +using Artemis.Events; +using Artemis.Properties; +using Artemis.Settings; +using Artemis.Utilities; +using Caliburn.Micro; + +namespace Artemis.ViewModels +{ + public class SystemTrayViewModel : Screen, IHandle + { + private readonly ShellViewModel _shellViewModel; + + private readonly IWindowManager _windowManager; + private string _activeIcon; + private bool _checkedForUpdate; + private bool _enabled; + private string _toggleText; + + public SystemTrayViewModel(IWindowManager windowManager, ShellViewModel shellViewModel) + { + _windowManager = windowManager; + _shellViewModel = shellViewModel; + _shellViewModel.MainManager.Events.Subscribe(this); + _shellViewModel.MainManager.EnableProgram(); + _checkedForUpdate = false; + + if (General.Default.ShowOnStartup) + ShowWindow(); + } + + public bool CanShowWindow => !_shellViewModel.IsActive; + + public bool CanHideWindow => _shellViewModel.IsActive; + + public bool Enabled + { + get { return _enabled; } + set + { + if (value == _enabled) return; + _enabled = value; + + ToggleText = _enabled ? "Disable Artemis" : "Enable Artemis"; + ActiveIcon = _enabled ? "../Resources/logo.ico" : "../Resources/logo-disabled.ico"; + NotifyOfPropertyChange(() => Enabled); + } + } + public string ActiveIcon { get { return _activeIcon; } @@ -57,77 +56,77 @@ namespace Artemis.ViewModels _activeIcon = value; NotifyOfPropertyChange(); } - } - - public string ToggleText - { - get { return _toggleText; } - set - { - if (value == _toggleText) return; - _toggleText = value; - NotifyOfPropertyChange(() => ToggleText); - } - } - - public void Handle(ToggleEnabled message) - { - Enabled = message.Enabled; - } - - public void ToggleEnabled() - { - if (Enabled) - _shellViewModel.MainManager.DisableProgram(); - else - _shellViewModel.MainManager.EnableProgram(); - } - - protected override void OnActivate() - { - base.OnActivate(); - - NotifyOfPropertyChange(() => CanShowWindow); - NotifyOfPropertyChange(() => CanHideWindow); - } - - public void ShowWindow() - { - if (!CanShowWindow) - return; - - // manually show the next window view-model - _windowManager.ShowWindow(_shellViewModel); - - NotifyOfPropertyChange(() => CanShowWindow); - NotifyOfPropertyChange(() => CanHideWindow); - - if (_checkedForUpdate) - return; - - _checkedForUpdate = true; - Updater.CheckForUpdate(_shellViewModel.MainManager.DialogService); - } - - - public void HideWindow() - { - if (!CanHideWindow) - return; - - _shellViewModel.TryClose(); - - NotifyOfPropertyChange(() => CanShowWindow); - NotifyOfPropertyChange(() => CanHideWindow); - } - - public void ExitApplication() - { - _shellViewModel.MainManager.Shutdown(); - Application.Current.Shutdown(); - - // Sometimes you need to be rough. - Environment.Exit(0); - } - } + } + + public string ToggleText + { + get { return _toggleText; } + set + { + if (value == _toggleText) return; + _toggleText = value; + NotifyOfPropertyChange(() => ToggleText); + } + } + + public void Handle(ToggleEnabled message) + { + Enabled = message.Enabled; + } + + public void ToggleEnabled() + { + if (Enabled) + _shellViewModel.MainManager.DisableProgram(); + else + _shellViewModel.MainManager.EnableProgram(); + } + + protected override void OnActivate() + { + base.OnActivate(); + + NotifyOfPropertyChange(() => CanShowWindow); + NotifyOfPropertyChange(() => CanHideWindow); + } + + public void ShowWindow() + { + if (!CanShowWindow) + return; + + // manually show the next window view-model + _windowManager.ShowWindow(_shellViewModel); + + NotifyOfPropertyChange(() => CanShowWindow); + NotifyOfPropertyChange(() => CanHideWindow); + + if (_checkedForUpdate) + return; + + _checkedForUpdate = true; + Updater.CheckForUpdate(_shellViewModel.MainManager.DialogService); + } + + + public void HideWindow() + { + if (!CanHideWindow) + return; + + _shellViewModel.TryClose(); + + NotifyOfPropertyChange(() => CanShowWindow); + NotifyOfPropertyChange(() => CanHideWindow); + } + + public void ExitApplication() + { + _shellViewModel.MainManager.Shutdown(); + Application.Current.Shutdown(); + + // Sometimes you need to be rough. + Environment.Exit(0); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/WelcomeViewModel.cs b/Artemis/Artemis/ViewModels/WelcomeViewModel.cs index 8000adf27..522ccfbfe 100644 --- a/Artemis/Artemis/ViewModels/WelcomeViewModel.cs +++ b/Artemis/Artemis/ViewModels/WelcomeViewModel.cs @@ -1,13 +1,13 @@ -using System.Diagnostics; -using Caliburn.Micro; - -namespace Artemis.ViewModels -{ - public class WelcomeViewModel : Screen - { - public void NavigateTo(string url) - { - Process.Start(new ProcessStartInfo(url)); - } - } +using System.Diagnostics; +using Caliburn.Micro; + +namespace Artemis.ViewModels +{ + public class WelcomeViewModel : Screen + { + public void NavigateTo(string url) + { + Process.Start(new ProcessStartInfo(url)); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Views/EffectsView.xaml.cs b/Artemis/Artemis/Views/EffectsView.xaml.cs index bd60c9fcc..20c924d86 100644 --- a/Artemis/Artemis/Views/EffectsView.xaml.cs +++ b/Artemis/Artemis/Views/EffectsView.xaml.cs @@ -1,15 +1,15 @@ -using System.Windows.Controls; - -namespace Artemis.Views -{ - /// - /// Interaction logic for EffectsView.xaml - /// - public partial class EffectsView : UserControl - { - public EffectsView() - { - InitializeComponent(); - } - } +using System.Windows.Controls; + +namespace Artemis.Views +{ + /// + /// Interaction logic for EffectsView.xaml + /// + public partial class EffectsView : UserControl + { + public EffectsView() + { + InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml.cs b/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml.cs index f6e9b718f..03798beef 100644 --- a/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml.cs +++ b/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml.cs @@ -1,15 +1,15 @@ -using System.Windows.Controls; - -namespace Artemis.Views.Flyouts -{ - /// - /// Interaction logic for FlyoutSettingsView.xaml - /// - public partial class FlyoutSettingsView : UserControl - { - public FlyoutSettingsView() - { - InitializeComponent(); - } - } +using System.Windows.Controls; + +namespace Artemis.Views.Flyouts +{ + /// + /// Interaction logic for FlyoutSettingsView.xaml + /// + public partial class FlyoutSettingsView : UserControl + { + public FlyoutSettingsView() + { + InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Views/GamesView.xaml.cs b/Artemis/Artemis/Views/GamesView.xaml.cs index 7ecaf8b17..22c53f6bb 100644 --- a/Artemis/Artemis/Views/GamesView.xaml.cs +++ b/Artemis/Artemis/Views/GamesView.xaml.cs @@ -1,15 +1,15 @@ -using System.Windows.Controls; - -namespace Artemis.Views -{ - /// - /// Interaction logic for GamesView.xaml - /// - public partial class GamesView : UserControl - { - public GamesView() - { - InitializeComponent(); - } - } +using System.Windows.Controls; + +namespace Artemis.Views +{ + /// + /// Interaction logic for GamesView.xaml + /// + public partial class GamesView : UserControl + { + public GamesView() + { + InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml b/Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml new file mode 100644 index 000000000..f9031fae1 --- /dev/null +++ b/Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml.cs b/Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml.cs new file mode 100644 index 000000000..1dd225b05 --- /dev/null +++ b/Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Artemis.Views.LayerEditor +{ + /// + /// Interaction logic for LayerConditionView.xaml + /// + public partial class LayerConditionView : UserControl + { + public LayerConditionView() + { + InitializeComponent(); + } + } +} diff --git a/Artemis/Artemis/Views/LayerEditor/LayerDynamicPropertiesView.xaml b/Artemis/Artemis/Views/LayerEditor/LayerDynamicPropertiesView.xaml new file mode 100644 index 000000000..22c306ab2 --- /dev/null +++ b/Artemis/Artemis/Views/LayerEditor/LayerDynamicPropertiesView.xaml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Artemis/Artemis/Views/LayerEditor/LayerDynamicPropertiesView.xaml.cs b/Artemis/Artemis/Views/LayerEditor/LayerDynamicPropertiesView.xaml.cs new file mode 100644 index 000000000..bbb08551e --- /dev/null +++ b/Artemis/Artemis/Views/LayerEditor/LayerDynamicPropertiesView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Artemis.Views.LayerEditor +{ + /// + /// Interaction logic for LayerDynamicPropertiesView.xaml + /// + public partial class LayerDynamicPropertiesView : UserControl + { + public LayerDynamicPropertiesView() + { + InitializeComponent(); + } + } +} diff --git a/Artemis/Artemis/Views/LayerEditor/LayerEditorView.xaml b/Artemis/Artemis/Views/LayerEditor/LayerEditorView.xaml new file mode 100644 index 000000000..7676dc8a4 --- /dev/null +++ b/Artemis/Artemis/Views/LayerEditor/LayerEditorView.xaml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Artemis/Artemis/Views/ProfileEditorView.xaml.cs b/Artemis/Artemis/Views/ProfileEditorView.xaml.cs new file mode 100644 index 000000000..5cfcb4102 --- /dev/null +++ b/Artemis/Artemis/Views/ProfileEditorView.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Artemis.Views +{ + /// + /// Interaction logic for ProfileEditorView.xaml + /// + public partial class ProfileEditorView : UserControl + { + public ProfileEditorView() + { + InitializeComponent(); + } + } +} diff --git a/Artemis/Artemis/Views/ShellView.xaml b/Artemis/Artemis/Views/ShellView.xaml index 29ff90142..11c885d27 100644 --- a/Artemis/Artemis/Views/ShellView.xaml +++ b/Artemis/Artemis/Views/ShellView.xaml @@ -8,8 +8,8 @@ xmlns:dialogs="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro" dialogs:DialogParticipation.Register="{Binding RelativeSource={RelativeSource Self}, Path=DataContext}" mc:Ignorable="d" - Title="Artemis" Height="670" Width="690" - MinWidth="500" MinHeight="400" + Title="Artemis" Height="800" Width="1210" + MinHeight="800" MinWidth="1210" GlowBrush="{DynamicResource AccentColorBrush}" Icon="../logo.ico"> diff --git a/Artemis/Artemis/Views/ShellView.xaml.cs b/Artemis/Artemis/Views/ShellView.xaml.cs index 0d63f646c..569791a91 100644 --- a/Artemis/Artemis/Views/ShellView.xaml.cs +++ b/Artemis/Artemis/Views/ShellView.xaml.cs @@ -1,13 +1,13 @@ -namespace Artemis.Views -{ - /// - /// Interaction logic for ShellView.xaml - /// - public partial class ShellView - { - public ShellView() - { - InitializeComponent(); - } - } +namespace Artemis.Views +{ + /// + /// Interaction logic for ShellView.xaml + /// + public partial class ShellView + { + public ShellView() + { + InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Views/SystemTrayView.xaml.cs b/Artemis/Artemis/Views/SystemTrayView.xaml.cs index e0f1b093a..b99935b62 100644 --- a/Artemis/Artemis/Views/SystemTrayView.xaml.cs +++ b/Artemis/Artemis/Views/SystemTrayView.xaml.cs @@ -1,15 +1,15 @@ -using MahApps.Metro.Controls; - -namespace Artemis.Views -{ - /// - /// Interaction logic for SystemTrayView.xaml - /// - public partial class SystemTrayView : MetroWindow - { - public SystemTrayView() - { - InitializeComponent(); - } - } +using MahApps.Metro.Controls; + +namespace Artemis.Views +{ + /// + /// Interaction logic for SystemTrayView.xaml + /// + public partial class SystemTrayView : MetroWindow + { + public SystemTrayView() + { + InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Views/WelcomeView.xaml.cs b/Artemis/Artemis/Views/WelcomeView.xaml.cs index bcbd826e4..6aed8592c 100644 --- a/Artemis/Artemis/Views/WelcomeView.xaml.cs +++ b/Artemis/Artemis/Views/WelcomeView.xaml.cs @@ -1,22 +1,22 @@ -using System.Diagnostics; -using System.Windows.Controls; -using System.Windows.Navigation; - -namespace Artemis.Views -{ - /// - /// Interaction logic for WelcomeView.xaml - /// - public partial class WelcomeView : UserControl - { - public WelcomeView() - { - InitializeComponent(); - } - - private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e) - { - Process.Start("https://github.com/SpoinkyNL/Artemis/wiki/Frequently-Asked-Questions-(FAQ)"); - } - } +using System.Diagnostics; +using System.Windows.Controls; +using System.Windows.Navigation; + +namespace Artemis.Views +{ + /// + /// Interaction logic for WelcomeView.xaml + /// + public partial class WelcomeView : UserControl + { + public WelcomeView() + { + InitializeComponent(); + } + + private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e) + { + Process.Start("https://github.com/SpoinkyNL/Artemis/wiki/Frequently-Asked-Questions-(FAQ)"); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/lib/ColorBox.dll b/Artemis/Artemis/lib/ColorBox.dll new file mode 100644 index 000000000..176d3f50b Binary files /dev/null and b/Artemis/Artemis/lib/ColorBox.dll differ diff --git a/Artemis/Artemis/packages.config b/Artemis/Artemis/packages.config index 8cb94cea7..137cbc49a 100644 --- a/Artemis/Artemis/packages.config +++ b/Artemis/Artemis/packages.config @@ -6,18 +6,18 @@ - - + + - + - - + + \ No newline at end of file diff --git a/Artemis/LogiLed2Artemis/Logger.cpp b/Artemis/LogiLed2Artemis/Logger.cpp new file mode 100644 index 000000000..d255c8713 --- /dev/null +++ b/Artemis/LogiLed2Artemis/Logger.cpp @@ -0,0 +1,104 @@ +// Original work by VRocker https://github.com/VRocker/LogiLed2Corsair +// I'm mainly a C# developer, and these modification aren't a piece of art, but it suits our needs. + +// The MIT License (MIT) +// +// Copyright (c) 2015 VRocker +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "Logger.h" + +#include +#include +#include + + +// Ok this looks butt-ugleh but its just to force the default log level to debug if we compile in debug +#ifdef _DEBUG +LogLevel CLogger::m_eLogLevel = LogLevel::Debug; +#else +LogLevel CLogger::m_eLogLevel = LogLevel::All; +#endif +FILE* CLogger::m_pFile = 0; + +void CLogger::InitLogging(const char* szFile) +{ + if (!m_pFile) + { + m_pFile = fopen(szFile, "a+"); + if (!m_pFile) + { + // Hum, we couldn't open the file for writing + printf("ERROR: Unable to open log file %s.\n", szFile); + } + } +} + +void CLogger::EndLogging(void) +{ + if (m_pFile) + { + fclose(m_pFile); + m_pFile = 0; + } +} + +void CLogger::OutputLog_s(const char* sz, const LogLevel eLevel) +{ + // If the level of this log entry is less important than what we are told to log, just return + if (eLevel < m_eLogLevel) + return; + + // If we don't have a file to write to, bail. + if (!m_pFile) + return; + + char szOutput[512] = {0}; + + time_t rawtime; + struct tm* timeinfo; + + time(&rawtime); + timeinfo = localtime(&rawtime); + + // Timestamp the log entry + size_t uiLen = sprintf(szOutput, "<%.2d/%.2d/%.2d - %.2d:%.2d:%.2d> %s\n", timeinfo->tm_mday, timeinfo->tm_mon + 1, timeinfo->tm_year + 1900, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, sz); + + // Write the text to the file + fwrite(szOutput, 1, uiLen, m_pFile); + // Flush the log file to the disk. May move this to a seperate function + fflush(m_pFile); + + // Output the text to any console that may be attached + printf("%s", szOutput); +} + +void CLogger::OutputLog(const char* sz, const LogLevel eLevel, ...) +{ + char szText[1024] = {0}; + va_list marker; + va_start(marker, eLevel); + vsprintf(szText, sz, marker); + va_end(marker); + + // Since this function is pretty much the same as the safer function, we'll just redirect it there + OutputLog_s(szText, eLevel); +} + diff --git a/Artemis/LogiLed2Artemis/Logger.h b/Artemis/LogiLed2Artemis/Logger.h new file mode 100644 index 000000000..41cab02d2 --- /dev/null +++ b/Artemis/LogiLed2Artemis/Logger.h @@ -0,0 +1,82 @@ +// Original work by VRocker https://github.com/VRocker/LogiLed2Corsair +// I'm mainly a C# developer, and these modification aren't a piece of art, but it suits our needs. + +// The MIT License (MIT) +// +// Copyright (c) 2015 VRocker +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once +#ifndef _LOGGER_H +#define _LOGGER_H + +#include + +enum class LogLevel +{ + Debug, + All, + Critical, + Warning, + Information, + User, + Internal, + None, + + // Just to force the compiler to treat the enum options as an int + FORCE_32BIT = 0x7fffffff +}; + +class CLogger +{ +public: + static LogLevel GetLogLevel(void) + { + return m_eLogLevel; + } + + static void SetLogLevel(const LogLevel e) + { +#ifndef _DEBUG + if ( e == LogLevel::Debug ) return; +#endif + m_eLogLevel = e; + } + + static void InitLogging(const char* szFile); + // Always remember to end logging when you are finished otherwise you will have file handles floating around + static void EndLogging(void); + + // Output the text to a log file. + static void OutputLog_s(const char* sz, const LogLevel eLevel); + static void OutputLog(const char* sz, const LogLevel eLevel, ...); + + static FILE* GetFile() + { + return m_pFile; + } + +private: + static LogLevel m_eLogLevel; + static FILE* m_pFile; +}; + +#endif + diff --git a/Artemis/LogiLed2Artemis/LogiLed2Artemis.def b/Artemis/LogiLed2Artemis/LogiLed2Artemis.def new file mode 100644 index 000000000..ef38be3f1 --- /dev/null +++ b/Artemis/LogiLed2Artemis/LogiLed2Artemis.def @@ -0,0 +1,49 @@ +// Original work by VRocker https://github.com/VRocker/LogiLed2Corsair +// I'm mainly a C# developer, and these modification aren't a piece of art, but it suits our needs. + +// The MIT License (MIT) +// +// Copyright (c) 2015 VRocker +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +LIBRARY LogiLed2Artemis.dll + +EXPORTS + + LogiLedInit + LogiLedGetSdkVersion + LogiLedSetTargetDevice + LogiLedSaveCurrentLighting + LogiLedSetLighting + LogiLedRestoreLighting + LogiLedFlashLighting + LogiLedPulseLighting + LogiLedStopEffects + LogiLedSetLightingFromBitmap + LogiLedSetLightingForKeyWithScanCode + LogiLedSetLightingForKeyWithHidCode + LogiLedSetLightingForKeyWithQuartzCode + LogiLedSetLightingForKeyWithKeyName + LogiLedSaveLightingForKey + LogiLedRestoreLightingForKey + LogiLedFlashSingleKey + LogiLedPulseSingleKey + LogiLedStopEffectsOnKey + LogiLedShutdown diff --git a/Artemis/LogiLed2Artemis/LogiLed2Artemis.vcxproj b/Artemis/LogiLed2Artemis/LogiLed2Artemis.vcxproj new file mode 100644 index 000000000..670478206 --- /dev/null +++ b/Artemis/LogiLed2Artemis/LogiLed2Artemis.vcxproj @@ -0,0 +1,168 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {D2EDB8F3-F0CB-4670-B472-0B46D5800D2C} + Win32Proj + LogiLed2Artemis + LogiLed2Artemis + + + + DynamicLibrary + true + v140 + Unicode + + + DynamicLibrary + true + v140 + Unicode + + + DynamicLibrary + false + v140 + true + Unicode + + + DynamicLibrary + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + true + + + true + $(LibraryPath) + + + false + + + false + $(ProjectName) + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;LOGILEDCORSAIR_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + LogiLed2Artemis.def + ../CUESDK/lib/i386/CUESDK_2013.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;LOGILEDCORSAIR_EXPORTS;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + + + Windows + true + LogiLed2Artemis.def + %(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;LOGILEDCORSAIR_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + true + true + LogiLed2Artemis.def + ../CUESDK/lib/i386/CUESDK_2013.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;LOGILEDCORSAIR_EXPORTS;%(PreprocessorDefinitions) + + + Windows + true + true + true + LogiLed2Artemis.def + %(AdditionalDependencies) + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Artemis/LogiLed2Artemis/LogiLed2Artemis.vcxproj.filters b/Artemis/LogiLed2Artemis/LogiLed2Artemis.vcxproj.filters new file mode 100644 index 000000000..34a553926 --- /dev/null +++ b/Artemis/LogiLed2Artemis/LogiLed2Artemis.vcxproj.filters @@ -0,0 +1,41 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/Artemis/LogiLed2Artemis/LogiLedDefs.h b/Artemis/LogiLed2Artemis/LogiLedDefs.h new file mode 100644 index 000000000..e1d2a4f24 --- /dev/null +++ b/Artemis/LogiLed2Artemis/LogiLedDefs.h @@ -0,0 +1,135 @@ +#pragma once + +const int LOGITECH_LED_MOUSE = 0x0001; +const int LOGITECH_LED_KEYBOARD = 0x0002; +const int LOGITECH_LED_ALL = LOGITECH_LED_MOUSE | LOGITECH_LED_KEYBOARD; + +#define LOGI_LED_BITMAP_WIDTH 21 +#define LOGI_LED_BITMAP_HEIGHT 6 +#define LOGI_LED_BITMAP_BYTES_PER_KEY 4 + +#define LOGI_LED_BITMAP_SIZE LOGI_LED_BITMAP_WIDTH*LOGI_LED_BITMAP_HEIGHT*LOGI_LED_BITMAP_BYTES_PER_KEY + +#define LOGI_LED_DURATION_INFINITE 0 + +#define LOGI_DEVICETYPE_MONOCHROME_ORD 0 +#define LOGI_DEVICETYPE_RGB_ORD 1 +#define LOGI_DEVICETYPE_PERKEY_RGB_ORD 2 + +#define LOGI_DEVICETYPE_MONOCHROME (1 << LOGI_DEVICETYPE_MONOCHROME_ORD) +#define LOGI_DEVICETYPE_RGB (1 << LOGI_DEVICETYPE_RGB_ORD) +#define LOGI_DEVICETYPE_PERKEY_RGB (1 << LOGI_DEVICETYPE_PERKEY_RGB_ORD) + +#define LOGI_DEVICETYPE_ALL (LOGI_DEVICETYPE_MONOCHROME | LOGI_DEVICETYPE_RGB | LOGI_DEVICETYPE_PERKEY_RGB) + +namespace LogiLed +{ + typedef enum + { + 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 = 0x145, + 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 = 0x45, + 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, + } KeyName; +} + diff --git a/Artemis/LogiLed2Artemis/main.cpp b/Artemis/LogiLed2Artemis/main.cpp new file mode 100644 index 000000000..c224e7daf --- /dev/null +++ b/Artemis/LogiLed2Artemis/main.cpp @@ -0,0 +1,254 @@ +// Original work by VRocker https://github.com/VRocker/LogiLed2Corsair +// I'm mainly a C# developer, and these modification aren't a piece of art, but it suits our needs. + +// The MIT License (MIT) +// +// Copyright (c) 2015 VRocker +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "main.h" +#include +#include +#include +#include "LogiLedDefs.h" +#define WIN32_LEAN_AND_MEAN +#include +#include "Logger.h" + +#include +#include + + +static bool g_hasInitialised = false; +const char* game = ""; + +void cleanup() +{ + CLogger::EndLogging(); +} + +BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + { + atexit(cleanup); + + CLogger::InitLogging("Log.txt"); + CLogger::SetLogLevel(LogLevel::None); + + // Get the process that loaded the DLL + TCHAR divisionFind[] = _T("Division"); + TCHAR gtaFind[] = _T("GTA"); + TCHAR szPath[MAX_PATH]; + GetModuleFileName(NULL, szPath, MAX_PATH); + + if (_tcscmp(szPath, divisionFind) != 0) + game = "division"; + else if (_tcscmp(szPath, gtaFind) != 0) + game = "gta"; + + CLogger::OutputLog("Attached to process.", LogLevel::Debug); + } + break; + + case DLL_PROCESS_DETACH: + { + cleanup(); + + CLogger::OutputLog_s("Detached from process.", LogLevel::Debug); + } + break; + } + + return true; +} + +bool LogiLedInit() +{ + CLogger::OutputLog_s("Logitech LED init called.", LogLevel::Debug); + g_hasInitialised = true; + return true; +} + +bool LogiLedGetSdkVersion(int* majorNum, int* minorNum, int* buildNum) +{ + CLogger::OutputLog("LogiLedGetSdkVersion called.", LogLevel::Debug); + + // Mimic the SDK version + *majorNum = 8; + *minorNum = 81; + *buildNum = 15; + + return true; +} + +bool LogiLedSetTargetDevice(int targetDevice) +{ + CLogger::OutputLog("LogiLedSetTargetDevice called (%i)", LogLevel::Debug, targetDevice); + + // Logitech SDK says this function returns false if LogiLedInit hasn't been called + return g_hasInitialised; +} + +bool LogiLedSaveCurrentLighting() +{ + CLogger::OutputLog("LogiLedSaveCurrentLighting called (%i)", LogLevel::Debug); + return true; +} + +void Transmit(const char* msg) +{ + //Pipe Init Data + HANDLE hPipe1; + char buf[100]; + LPTSTR lpszPipename1 = TEXT("\\\\.\\pipe\\artemis"); + + hPipe1 = CreateFile(lpszPipename1, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (hPipe1 == NULL || hPipe1 == INVALID_HANDLE_VALUE) + { + CLogger::OutputLog("Could not open the pipe - (error %i)", LogLevel::Debug, GetLastError()); + return; + } + + DWORD cbWritten; + WriteFile(hPipe1, msg, strlen(msg), &cbWritten, NULL); + CLogger::OutputLog_s("Transmitted to pipe", LogLevel::Debug); +} + +bool LogiLedSetLighting(int redPercentage, int greenPercentage, int bluePercentage) +{ + CLogger::OutputLog("LogiLedSetLighting called (%i %i %i)", LogLevel::Debug, redPercentage, greenPercentage, bluePercentage); + + std::ostringstream os; + os << "0 0 " << redPercentage << " " << greenPercentage << " " << bluePercentage; + Transmit(os.str().c_str()); + + return true; +} + +bool LogiLedRestoreLighting() +{ + CLogger::OutputLog("LogiLedRestoreLighting called", LogLevel::Debug); + return true; +} + +bool LogiLedFlashLighting(int redPercentage, int greenPercentage, int bluePercentage, int milliSecondsDuration, int milliSecondsInterval) +{ + CLogger::OutputLog("LogiLedFlashLighting called (%i %i %i %i %i)", LogLevel::Debug, redPercentage, greenPercentage, bluePercentage, milliSecondsDuration, milliSecondsInterval); + return true; +} + +bool LogiLedPulseLighting(int redPercentage, int greenPercentage, int bluePercentage, int milliSecondsDuration, int milliSecondsInterval) +{ + CLogger::OutputLog("LogiLedPulseLighting called (%i %i %i %i %i)", LogLevel::Debug, redPercentage, greenPercentage, bluePercentage, milliSecondsDuration, milliSecondsInterval); + return true; +} + +bool LogiLedStopEffects() +{ + CLogger::OutputLog_s("LogiLedStopEffects called", LogLevel::Debug); + return true; +} + +bool LogiLedSetLightingFromBitmap(unsigned char bitmap[]) +{ + CLogger::OutputLog_s("LogiLedSetLightingFromBitmap called", LogLevel::Debug); + return true; +} + +bool LogiLedSetLightingForKeyWithScanCode(int keyCode, int redPercentage, int greenPercentage, int bluePercentage) +{ + CLogger::OutputLog("LogiLedSetLightingForKeyWithScanCode called [Key: %i] (%i %i %i)", LogLevel::Debug, keyCode, redPercentage, greenPercentage, bluePercentage); + return true; +} + +bool LogiLedSetLightingForKeyWithHidCode(int keyCode, int redPercentage, int greenPercentage, int bluePercentage) +{ + CLogger::OutputLog("LogiLedSetLightingForKeyWithHidCode called [Key: %i] (%i %i %i)", LogLevel::Debug, keyCode, redPercentage, greenPercentage, bluePercentage); + return true; +} + +bool LogiLedSetLightingForKeyWithQuartzCode(int keyCode, int redPercentage, int greenPercentage, int bluePercentage) +{ + CLogger::OutputLog("LogiLedSetLightingForKeyWithQuartzCode called [Key: %i] (%i %i %i)", LogLevel::Debug, keyCode, redPercentage, greenPercentage, bluePercentage); + return true; +} + +bool LogiLedSetLightingForKeyWithKeyName(LogiLed::KeyName keyName, int redPercentage, int greenPercentage, int bluePercentage) +{ + CLogger::OutputLog("LogiLedSetLightingForKeyWithKeyName called [Key: %i] (%i %i %i)", LogLevel::Debug, keyName, redPercentage, greenPercentage, bluePercentage); + + // Only transmit interesting keys. This can most likely be done prettier, but I'm no C++ dev. + if (game == "division" && + (keyName == LogiLed::F1 || + keyName == LogiLed::F2 || + keyName == LogiLed::F3 || + keyName == LogiLed::F4 || + keyName == LogiLed::R || + keyName == LogiLed::G || + keyName == LogiLed::V) + ) + { + std::ostringstream os; + os << "1 " << keyName << " " << redPercentage << " " << greenPercentage << " " << bluePercentage; + std::string s = os.str(); + Transmit(os.str().c_str()); + } + return true; +} + +bool LogiLedSaveLightingForKey(LogiLed::KeyName keyName) +{ + CLogger::OutputLog("LogiLedSaveLightingForKey called [Key: %i]", LogLevel::Debug, keyName); + return true; +} + +bool LogiLedRestoreLightingForKey(LogiLed::KeyName keyName) +{ + CLogger::OutputLog("LogiLedRestoreLightingForKey called [Key: %i]", LogLevel::Debug, keyName); + return true; +} + +bool LogiLedFlashSingleKey(LogiLed::KeyName keyName, int redPercentage, int greenPercentage, int bluePercentage, int msDuration, int msInterval) +{ + CLogger::OutputLog("LogiLedFlashSingleKey called [Key: %i] (%i %i %i %i %i)", LogLevel::Debug, keyName, redPercentage, greenPercentage, bluePercentage, msDuration, msInterval); + return true; +} + +bool LogiLedPulseSingleKey(LogiLed::KeyName keyName, int startRedPercentage, int startGreenPercentage, int startBluePercentage, int finishRedPercentage, int finishGreenPercentage, int finishBluePercentage, int msDuration, bool isInfinite) +{ + CLogger::OutputLog("LogiLedPulseSingleKey called [Key: %i] (%i %i %i %i %i %i %i %i)", LogLevel::Debug, keyName, startRedPercentage, startGreenPercentage, startBluePercentage, finishRedPercentage, finishGreenPercentage, finishBluePercentage, msDuration, isInfinite); + return true; +} + +bool LogiLedStopEffectsOnKey(LogiLed::KeyName keyName) +{ + CLogger::OutputLog("LogiLedStopEffectsOnKey called [Key: %i]", LogLevel::Debug, keyName); + return true; +} + +void LogiLedShutdown() +{ + CLogger::OutputLog_s("LogiLedShutdown called.", LogLevel::Debug); + g_hasInitialised = false; +} + diff --git a/Artemis/LogiLed2Artemis/main.h b/Artemis/LogiLed2Artemis/main.h new file mode 100644 index 000000000..3f59c932d --- /dev/null +++ b/Artemis/LogiLed2Artemis/main.h @@ -0,0 +1,2 @@ +#pragma once + diff --git a/pointers.json b/pointers.json index 83e812568..66fb6af27 100644 --- a/pointers.json +++ b/pointers.json @@ -2,17 +2,17 @@ [ { "Game":"RocketLeague", - "GameVersion":"1.16", + "GameVersion":"1.15", "GameAddresses":[ { "Description":"Boost", "BasePointer":{ - "value":22411984 + "value":22555396 }, "Offsets":[ - 1632, - 64, - 1636, + 180, + 260, + 800, 1800, 540 ]