diff --git a/Artemis/Artemis.sln b/Artemis/Artemis.sln index d48581c3b..6c8abbab3 100644 --- a/Artemis/Artemis.sln +++ b/Artemis/Artemis.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis", "Artemis\Artemis.csproj", "{ED9997A2-E54C-4E9F-9350-62BE672C3ABE}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Razer2Artemis", "Razer2Artemis\Razer2Artemis.vcxproj", "{39711909-C1D5-46CE-A9EA-2D561692EA47}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution CD_ROM|Any CPU = CD_ROM|Any CPU @@ -54,6 +56,34 @@ Global {ED9997A2-E54C-4E9F-9350-62BE672C3ABE}.SingleImage|x64.Build.0 = Release|x64 {ED9997A2-E54C-4E9F-9350-62BE672C3ABE}.SingleImage|x86.ActiveCfg = Release|x86 {ED9997A2-E54C-4E9F-9350-62BE672C3ABE}.SingleImage|x86.Build.0 = Release|x86 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.CD_ROM|Any CPU.ActiveCfg = Release|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.CD_ROM|Any CPU.Build.0 = Release|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.CD_ROM|x64.ActiveCfg = Release|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.CD_ROM|x64.Build.0 = Release|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.CD_ROM|x86.ActiveCfg = Release|Win32 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.CD_ROM|x86.Build.0 = Release|Win32 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.Debug|x64.ActiveCfg = Debug|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.Debug|x64.Build.0 = Debug|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.Debug|x86.ActiveCfg = Debug|Win32 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.Debug|x86.Build.0 = Debug|Win32 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.DVD-5|Any CPU.ActiveCfg = Release|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.DVD-5|Any CPU.Build.0 = Release|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.DVD-5|x64.ActiveCfg = Debug|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.DVD-5|x64.Build.0 = Debug|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.DVD-5|x86.ActiveCfg = Debug|Win32 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.DVD-5|x86.Build.0 = Debug|Win32 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.Release|Any CPU.ActiveCfg = Release|Win32 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.Release|x64.ActiveCfg = Release|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.Release|x64.Build.0 = Release|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.Release|x86.ActiveCfg = Release|Win32 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.Release|x86.Build.0 = Release|Win32 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.SingleImage|Any CPU.ActiveCfg = Release|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.SingleImage|Any CPU.Build.0 = Release|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.SingleImage|x64.ActiveCfg = Release|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.SingleImage|x64.Build.0 = Release|x64 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.SingleImage|x86.ActiveCfg = Release|Win32 + {39711909-C1D5-46CE-A9EA-2D561692EA47}.SingleImage|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Artemis/Artemis/App.xaml.cs b/Artemis/Artemis/App.xaml.cs index 5379a5cf8..e2b94fb9c 100644 --- a/Artemis/Artemis/App.xaml.cs +++ b/Artemis/Artemis/App.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Security.Principal; using System.Windows; using System.Windows.Threading; using Artemis.Utilities; @@ -14,12 +15,20 @@ namespace Artemis { public App() { - if (!GeneralHelpers.IsRunAsAdministrator()) + if (!IsRunAsAdministrator()) GeneralHelpers.RunAsAdministrator(); InitializeComponent(); } + private static bool IsRunAsAdministrator() + { + var wi = WindowsIdentity.GetCurrent(); + var wp = new WindowsPrincipal(wi); + + return wp.IsInRole(WindowsBuiltInRole.Administrator); + } + public bool DoHandle { get; set; } private void Application_Startup(object sender, StartupEventArgs e) diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index 542b424c5..955cc87d2 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -464,17 +464,18 @@ - - - - - - - - + + + + + + + + + - + @@ -508,25 +509,25 @@ Witcher3View.xaml - + FolderPropertiesView.xaml - + HeadsetPropertiesView.xaml - + KeyboardPropertiesView.xaml - + LayerConditionView.xaml - + LayerDynamicPropertiesView.xaml - + LayerEditorView.xaml - + MousePropertiesView.xaml @@ -535,7 +536,7 @@ VolumeDisplayView.xaml - + ProfileEditorView.xaml @@ -696,31 +697,31 @@ Designer MSBuild:Compile - + Designer MSBuild:Compile - + Designer MSBuild:Compile - + Designer MSBuild:Compile - + Designer MSBuild:Compile - + Designer MSBuild:Compile - + MSBuild:Compile Designer - + Designer MSBuild:Compile @@ -732,7 +733,7 @@ Designer MSBuild:Compile - + Designer MSBuild:Compile diff --git a/Artemis/Artemis/InjectionFactories/IProfileEditorViewModelFactory.cs b/Artemis/Artemis/InjectionFactories/IProfileEditorViewModelFactory.cs index 1ed1c17aa..31eb5138c 100644 --- a/Artemis/Artemis/InjectionFactories/IProfileEditorViewModelFactory.cs +++ b/Artemis/Artemis/InjectionFactories/IProfileEditorViewModelFactory.cs @@ -1,6 +1,7 @@ using Artemis.Managers; using Artemis.Models; using Artemis.ViewModels; +using Artemis.ViewModels.Profiles; using Caliburn.Micro; namespace Artemis.InjectionFactories diff --git a/Artemis/Artemis/InjectionModules/ArtemisModules.cs b/Artemis/Artemis/InjectionModules/ArtemisModules.cs index 5b5ae02a9..4f013698d 100644 --- a/Artemis/Artemis/InjectionModules/ArtemisModules.cs +++ b/Artemis/Artemis/InjectionModules/ArtemisModules.cs @@ -20,6 +20,8 @@ namespace Artemis.InjectionModules { public override void Load() { + #region Modules + // Effects Bind().To().InSingletonScope(); Bind().To().InSingletonScope(); @@ -36,7 +38,10 @@ namespace Artemis.InjectionModules // Overlays Bind().To().InSingletonScope(); - // Device Providers + #endregion + + #region Devices + // Keyboards Bind().To().InSingletonScope(); Bind().To().InSingletonScope(); @@ -45,6 +50,8 @@ namespace Artemis.InjectionModules Bind().To().InSingletonScope(); // Headsets Bind().To().InSingletonScope(); + + #endregion } } } \ No newline at end of file diff --git a/Artemis/Artemis/InjectionModules/BaseModules.cs b/Artemis/Artemis/InjectionModules/BaseModules.cs index 46c2fcd2a..dcbcc440b 100644 --- a/Artemis/Artemis/InjectionModules/BaseModules.cs +++ b/Artemis/Artemis/InjectionModules/BaseModules.cs @@ -3,6 +3,7 @@ using Artemis.Modules.Effects.ProfilePreview; using Artemis.Services; using Artemis.ViewModels; using Artemis.ViewModels.Abstract; +using Artemis.ViewModels.Profiles; using Caliburn.Micro; using Ninject.Extensions.Factory; using Ninject.Modules; @@ -16,6 +17,7 @@ namespace Artemis.InjectionModules // ViewModels Bind().To().InSingletonScope(); Bind().ToFactory(); + Bind().ToSelf(); Bind().To().InSingletonScope(); Bind().To().InSingletonScope(); diff --git a/Artemis/Artemis/Managers/ProfileManager.cs b/Artemis/Artemis/Managers/ProfileManager.cs index f998913bc..0bdf27565 100644 --- a/Artemis/Artemis/Managers/ProfileManager.cs +++ b/Artemis/Artemis/Managers/ProfileManager.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Timers; using Artemis.Models; using Artemis.Modules.Effects.ProfilePreview; +using Artemis.Settings; using Artemis.ViewModels.Abstract; using Ninject.Extensions.Logging; @@ -10,13 +11,14 @@ namespace Artemis.Managers { public class ProfileManager { - private readonly EffectManager _effectManager; private readonly DeviceManager _deviceManager; - private readonly LoopManager _loopManager; + private readonly EffectManager _effectManager; private readonly ILogger _logger; + private readonly LoopManager _loopManager; private EffectModel _prePreviewEffect; - public ProfileManager(ILogger logger, EffectManager effectManager, DeviceManager deviceManager, LoopManager loopManager) + public ProfileManager(ILogger logger, EffectManager effectManager, DeviceManager deviceManager, + LoopManager loopManager) { _logger = logger; _effectManager = effectManager; @@ -41,7 +43,8 @@ namespace Artemis.Managers /// private void SetupProfilePreview(object sender, ElapsedEventArgs e) { - if (_deviceManager.ActiveKeyboard == null ||_deviceManager.ChangingKeyboard || ProfilePreviewModel == null) + if (string.IsNullOrEmpty(General.Default.LastKeyboard) || _deviceManager.ChangingKeyboard || + ProfilePreviewModel == null) return; var activePreview = GameViewModels.FirstOrDefault(vm => vm.IsActive); @@ -73,7 +76,7 @@ namespace Artemis.Managers // LoopManager might be running, this method won't do any harm in that case. _loopManager.Start(); - + if (!ReferenceEquals(ProfilePreviewModel.SelectedProfile, activePreview.ProfileEditor.SelectedProfile)) ProfilePreviewModel.SelectedProfile = activePreview.ProfileEditor.SelectedProfile; } diff --git a/Artemis/Artemis/Models/Profiles/LayerModel.cs b/Artemis/Artemis/Models/Profiles/LayerModel.cs index f6e6b1ad6..16a8afa72 100644 --- a/Artemis/Artemis/Models/Profiles/LayerModel.cs +++ b/Artemis/Artemis/Models/Profiles/LayerModel.cs @@ -101,7 +101,7 @@ namespace Artemis.Models.Profiles else appliedProperties = Properties.Brush.Dispatcher.Invoke(() => GeneralHelpers.Clone(Properties)); - // TODO: Animations + // TODO: Mouse/headset animations // Update animations on layer types that support them //if (LayerType != LayerType.Folder && updateAnimations) //{ diff --git a/Artemis/Artemis/Models/Profiles/ProfileModel.cs b/Artemis/Artemis/Models/Profiles/ProfileModel.cs index 43de4b4e9..83e237b8f 100644 --- a/Artemis/Artemis/Models/Profiles/ProfileModel.cs +++ b/Artemis/Artemis/Models/Profiles/ProfileModel.cs @@ -154,6 +154,10 @@ namespace Artemis.Models.Profiles return layers; } + /// + /// Looks at all the layers wthin the profile and makes sure they are within boundaries of the given rectangle + /// + /// public void FixBoundaries(Rect keyboardRectangle) { foreach (var layer in GetLayers(false)) diff --git a/Artemis/Artemis/Modules/Effects/ProfilePreview/ProfilePreviewModel.cs b/Artemis/Artemis/Modules/Effects/ProfilePreview/ProfilePreviewModel.cs index 1bb6a0fe7..3e9f97177 100644 --- a/Artemis/Artemis/Modules/Effects/ProfilePreview/ProfilePreviewModel.cs +++ b/Artemis/Artemis/Modules/Effects/ProfilePreview/ProfilePreviewModel.cs @@ -36,6 +36,8 @@ namespace Artemis.Modules.Effects.ProfilePreview public override Bitmap GenerateBitmap() { + if (MainManager.DeviceManager.ActiveKeyboard == null) + return null; var bitmap = MainManager.DeviceManager.ActiveKeyboard.KeyboardBitmap(4); if (SelectedProfile == null) diff --git a/Artemis/Artemis/Utilities/GeneralHelpers.cs b/Artemis/Artemis/Utilities/GeneralHelpers.cs index 5003a40c1..3fc206095 100644 --- a/Artemis/Artemis/Utilities/GeneralHelpers.cs +++ b/Artemis/Artemis/Utilities/GeneralHelpers.cs @@ -38,22 +38,6 @@ 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 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. /// @@ -87,7 +71,6 @@ namespace Artemis.Utilities } 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 = "") diff --git a/Artemis/Artemis/Utilities/ImageUtilities.cs b/Artemis/Artemis/Utilities/ImageUtilities.cs index 3e395ee62..a83f22e67 100644 --- a/Artemis/Artemis/Utilities/ImageUtilities.cs +++ b/Artemis/Artemis/Utilities/ImageUtilities.cs @@ -37,30 +37,6 @@ namespace Artemis.Utilities 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 BitmapImage BitmapToBitmapImage(Bitmap b) { if (b == null) diff --git a/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs b/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs index 5c1040255..dc98fae7b 100644 --- a/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs +++ b/Artemis/Artemis/ViewModels/Abstract/GameViewModel.cs @@ -6,6 +6,7 @@ using Artemis.Managers; using Artemis.Models; using Artemis.Modules.Effects.ProfilePreview; using Artemis.Services; +using Artemis.ViewModels.Profiles; using Caliburn.Micro; using Ninject; using Ninject.Extensions.Logging; @@ -103,13 +104,13 @@ namespace Artemis.ViewModels.Abstract protected override void OnActivate() { base.OnActivate(); - ProfileEditor.PreviewTimer.Start(); + ProfileEditor.ProfileViewModel.Activate(); } protected override void OnDeactivate(bool close) { base.OnDeactivate(close); - ProfileEditor.PreviewTimer.Stop(); + ProfileEditor.ProfileViewModel.Deactivate(); } } diff --git a/Artemis/Artemis/ViewModels/LayerEditor/LayerConditionViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/LayerConditionViewModel.cs similarity index 96% rename from Artemis/Artemis/ViewModels/LayerEditor/LayerConditionViewModel.cs rename to Artemis/Artemis/ViewModels/Profiles/LayerConditionViewModel.cs index edc26b714..b3af86ea1 100644 --- a/Artemis/Artemis/ViewModels/LayerEditor/LayerConditionViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/LayerConditionViewModel.cs @@ -1,236 +1,236 @@ -using System.ComponentModel; -using System.Linq; -using Artemis.Models.Profiles; -using Artemis.Utilities; -using Caliburn.Micro; - -namespace Artemis.ViewModels.LayerEditor -{ - public sealed 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 _enumValueIsVisible; - private bool _preselecting; - private GeneralHelpers.PropertyCollection _selectedDataModelProp; - private string _selectedEnum; - 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(); - Enums = new BindableCollection(); - - PropertyChanged += UpdateModel; - PropertyChanged += UpdateForm; - - PreSelect(); - } - - public LayerConditionModel LayerConditionModel { get; set; } - - public BindableCollection DataModelProps { get; set; } - - public BindableCollection Operators { get; set; } - public BindableCollection Enums { get; set; } - - public string UserValue - { - get { return _userValue; } - set - { - if (value == _userValue) return; - _userValue = value; - NotifyOfPropertyChange(() => UserValue); - } - } - - 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 bool EnumValueIsVisible - { - get { return _enumValueIsVisible; } - set - { - if (value == _enumValueIsVisible) return; - _enumValueIsVisible = value; - NotifyOfPropertyChange(() => EnumValueIsVisible); - } - } - - public NamedOperator SelectedOperator - { - get { return _selectedOperator; } - set - { - if (value.Equals(_selectedOperator)) return; - _selectedOperator = value; - NotifyOfPropertyChange(() => SelectedOperator); - } - } - - public string SelectedEnum - { - get { return _selectedEnum; } - set - { - if (value == _selectedEnum) return; - _selectedEnum = value; - NotifyOfPropertyChange(() => SelectedEnum); - } - } - - /// - /// 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(); - UserValueIsVisible = false; - EnumValueIsVisible = false; - - switch (SelectedDataModelProp.Type) - { - case "Int32": - Operators.AddRange(_int32Operators); - UserValueIsVisible = true; - break; - case "Boolean": - Operators.AddRange(_boolOperators); - break; - default: - Operators.AddRange(_operators); - UserValueIsVisible = true; - break; - } - - // Setup Enum selection if needed - if (SelectedDataModelProp.EnumValues != null) - { - Enums.AddRange(SelectedDataModelProp.EnumValues); - EnumValueIsVisible = true; - } - - 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" && - e.PropertyName != "SelectedEnum") - return; - - LayerConditionModel.Field = SelectedDataModelProp.Path; - LayerConditionModel.Operator = SelectedOperator.Value; - LayerConditionModel.Type = SelectedDataModelProp.Type; - LayerConditionModel.Value = SelectedDataModelProp.Type == "Enum" ? SelectedEnum : UserValue; - } - - /// - /// 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); - LayerConditionModel.Type = SelectedDataModelProp.Type; - if (LayerConditionModel.Type =="Enum") - SelectedEnum = LayerConditionModel.Value; - else - UserValue = LayerConditionModel.Value; - - _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; - } - } - } +using System.ComponentModel; +using System.Linq; +using Artemis.Models.Profiles; +using Artemis.Utilities; +using Caliburn.Micro; + +namespace Artemis.ViewModels.Profiles +{ + public sealed 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 _enumValueIsVisible; + private bool _preselecting; + private GeneralHelpers.PropertyCollection _selectedDataModelProp; + private string _selectedEnum; + 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(); + Enums = new BindableCollection(); + + PropertyChanged += UpdateModel; + PropertyChanged += UpdateForm; + + PreSelect(); + } + + public LayerConditionModel LayerConditionModel { get; set; } + + public BindableCollection DataModelProps { get; set; } + + public BindableCollection Operators { get; set; } + public BindableCollection Enums { get; set; } + + public string UserValue + { + get { return _userValue; } + set + { + if (value == _userValue) return; + _userValue = value; + NotifyOfPropertyChange(() => UserValue); + } + } + + 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 bool EnumValueIsVisible + { + get { return _enumValueIsVisible; } + set + { + if (value == _enumValueIsVisible) return; + _enumValueIsVisible = value; + NotifyOfPropertyChange(() => EnumValueIsVisible); + } + } + + public NamedOperator SelectedOperator + { + get { return _selectedOperator; } + set + { + if (value.Equals(_selectedOperator)) return; + _selectedOperator = value; + NotifyOfPropertyChange(() => SelectedOperator); + } + } + + public string SelectedEnum + { + get { return _selectedEnum; } + set + { + if (value == _selectedEnum) return; + _selectedEnum = value; + NotifyOfPropertyChange(() => SelectedEnum); + } + } + + /// + /// 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(); + UserValueIsVisible = false; + EnumValueIsVisible = false; + + switch (SelectedDataModelProp.Type) + { + case "Int32": + Operators.AddRange(_int32Operators); + UserValueIsVisible = true; + break; + case "Boolean": + Operators.AddRange(_boolOperators); + break; + default: + Operators.AddRange(_operators); + UserValueIsVisible = true; + break; + } + + // Setup Enum selection if needed + if (SelectedDataModelProp.EnumValues != null) + { + Enums.AddRange(SelectedDataModelProp.EnumValues); + EnumValueIsVisible = true; + } + + 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" && + e.PropertyName != "SelectedEnum") + return; + + LayerConditionModel.Field = SelectedDataModelProp.Path; + LayerConditionModel.Operator = SelectedOperator.Value; + LayerConditionModel.Type = SelectedDataModelProp.Type; + LayerConditionModel.Value = SelectedDataModelProp.Type == "Enum" ? SelectedEnum : UserValue; + } + + /// + /// 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); + LayerConditionModel.Type = SelectedDataModelProp.Type; + if (LayerConditionModel.Type =="Enum") + SelectedEnum = LayerConditionModel.Value; + else + UserValue = LayerConditionModel.Value; + + _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/Profiles/LayerDynamicPropertiesViewModel.cs similarity index 98% rename from Artemis/Artemis/ViewModels/LayerEditor/LayerDynamicPropertiesViewModel.cs rename to Artemis/Artemis/ViewModels/Profiles/LayerDynamicPropertiesViewModel.cs index 150d23e29..dcdb69303 100644 --- a/Artemis/Artemis/ViewModels/LayerEditor/LayerDynamicPropertiesViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/LayerDynamicPropertiesViewModel.cs @@ -4,7 +4,7 @@ using Artemis.Models.Profiles.Properties; using Artemis.Utilities; using Caliburn.Micro; -namespace Artemis.ViewModels.LayerEditor +namespace Artemis.ViewModels.Profiles { public sealed class LayerDynamicPropertiesViewModel : PropertyChangedBase { @@ -33,7 +33,7 @@ namespace Artemis.ViewModels.LayerEditor Proposed.LayerPropertyType = LayerPropertyType.PercentageOf; } else - GeneralHelpers.CopyProperties(Proposed, original); + Proposed = GeneralHelpers.Clone(original); PropertyChanged += OnPropertyChanged; SetupControls(dataModelProps); diff --git a/Artemis/Artemis/ViewModels/LayerEditor/LayerEditorViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs similarity index 98% rename from Artemis/Artemis/ViewModels/LayerEditor/LayerEditorViewModel.cs rename to Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs index 6b151b23c..28257dcc9 100644 --- a/Artemis/Artemis/ViewModels/LayerEditor/LayerEditorViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs @@ -6,11 +6,11 @@ using Artemis.Models.Profiles; using Artemis.Models.Profiles.Properties; using Artemis.Services; using Artemis.Utilities; -using Artemis.ViewModels.LayerEditor.Properties; +using Artemis.ViewModels.Profiles.Properties; using Caliburn.Micro; using Ninject; -namespace Artemis.ViewModels.LayerEditor +namespace Artemis.ViewModels.Profiles { public sealed class LayerEditorViewModel : Screen { diff --git a/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs similarity index 60% rename from Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs rename to Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs index a7d9c2920..94de681dd 100644 --- a/Artemis/Artemis/ViewModels/ProfileEditorViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs @@ -1,760 +1,548 @@ -using System; -using System.ComponentModel; -using System.Dynamic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Timers; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Forms; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Threading; -using Artemis.DAL; -using Artemis.DeviceProviders; -using Artemis.Events; -using Artemis.Managers; -using Artemis.Models; -using Artemis.Models.Profiles; -using Artemis.Models.Profiles.Properties; -using Artemis.Services; -using Artemis.Styles.DropTargetAdorners; -using Artemis.Utilities; -using Artemis.ViewModels.LayerEditor; -using Caliburn.Micro; -using GongSolutions.Wpf.DragDrop; -using MahApps.Metro; -using Ninject; -using Application = System.Windows.Application; -using Cursor = System.Windows.Input.Cursor; -using Cursors = System.Windows.Input.Cursors; -using DragDropEffects = System.Windows.DragDropEffects; -using IDropTarget = GongSolutions.Wpf.DragDrop.IDropTarget; -using MouseEventArgs = System.Windows.Input.MouseEventArgs; -using Screen = Caliburn.Micro.Screen; -using Timer = System.Timers.Timer; - -namespace Artemis.ViewModels -{ - public sealed class ProfileEditorViewModel : Screen, IHandle, IDropTarget - { - private readonly GameModel _gameModel; - private readonly MainManager _mainManager; - private DateTime _downTime; - private LayerModel _draggingLayer; - private Point? _draggingLayerOffset; - private LayerEditorViewModel _editorVm; - private ImageSource _keyboardPreview; - private Cursor _keyboardPreviewCursor; - private BindableCollection _layers; - private BindableCollection _profiles; - private bool _resizing; - private LayerModel _selectedLayer; - private ProfileModel _selectedProfile; - - public ProfileEditorViewModel(IEventAggregator events, MainManager mainManager, GameModel gameModel, - MetroDialogService dialogService) - { - _mainManager = mainManager; - _gameModel = gameModel; - - Profiles = new BindableCollection(); - Layers = new BindableCollection(); - ActiveKeyboard = _mainManager.DeviceManager.ActiveKeyboard; - DialogService = dialogService; - - events.Subscribe(this); - - PreviewTimer = new Timer(40); - PreviewTimer.Elapsed += InvokeUpdateKeyboardPreview; - - PropertyChanged += PropertyChangeHandler; - LoadProfiles(); - } - - [Inject] - public MetroDialogService DialogService { get; set; } - - public Timer PreviewTimer { get; set; } - - 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(() => LayerSelected); - } - } - - 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(); - if (_selectedProfile != null) - Layers.AddRange(SelectedProfile.Layers); - - NotifyOfPropertyChange(() => SelectedProfile); - NotifyOfPropertyChange(() => ProfileSelected); - NotifyOfPropertyChange(() => LayerSelected); - } - } - - public ImageSource KeyboardPreview - { - get { return _keyboardPreview; } - set - { - if (Equals(value, _keyboardPreview)) return; - _keyboardPreview = value; - NotifyOfPropertyChange(() => KeyboardPreview); - } - } - - public ImageSource KeyboardImage => ImageUtilities.BitmapToBitmapImage(ActiveKeyboard?.PreviewSettings.Image); - - public PreviewSettings? PreviewSettings => ActiveKeyboard?.PreviewSettings; - - public bool ProfileSelected => SelectedProfile != null; - public bool LayerSelected => SelectedProfile != null && _selectedLayer != null; - - private KeyboardProvider ActiveKeyboard { get; set; } - - public void DragOver(IDropInfo dropInfo) - { - var source = dropInfo.Data as LayerModel; - var target = dropInfo.TargetItem as LayerModel; - if (source == null || target == null || source == target) - return; - - if (dropInfo.InsertPosition == RelativeInsertPosition.TargetItemCenter && - target.LayerType == LayerType.Folder) - { - dropInfo.DropTargetAdorner = typeof(DropTargetMetroHighlightAdorner); - dropInfo.Effects = DragDropEffects.Copy; - } - else - { - dropInfo.DropTargetAdorner = typeof(DropTargetMetroInsertionAdorner); - dropInfo.Effects = DragDropEffects.Move; - } - } - - public void Drop(IDropInfo dropInfo) - { - var source = dropInfo.Data as LayerModel; - var target = dropInfo.TargetItem as LayerModel; - if (source == null || target == null || source == target) - return; - - // Don't allow a folder to become it's own child, that's just weird - if (target.Parent == source) - return; - - // Remove the source from it's old profile/parent - if (source.Parent == null) - source.Profile.Layers.Remove(source); - else - source.Parent.Children.Remove(source); - - if (dropInfo.InsertPosition == RelativeInsertPosition.TargetItemCenter && - target.LayerType == LayerType.Folder) - { - // Insert into folder - source.Order = -1; - target.Children.Add(source); - target.FixOrder(); - } - else - { - // Insert the source into it's new profile/parent and update the order - if (dropInfo.InsertPosition == RelativeInsertPosition.AfterTargetItem) - source.Order = target.Order + 1; - else - source.Order = target.Order - 1; - if (target.Parent == null) - target.Profile.Layers.Add(source); - else - target.Parent.Children.Add(source); - } - - target.Profile?.FixOrder(); - target.Parent?.FixOrder(); - UpdateLayerList(source); - } - - /// - /// Handles chaning the active keyboard, updating the preview image and profiles collection - /// - /// - public void Handle(ActiveKeyboardChanged message) - { - ActiveKeyboard = _mainManager.DeviceManager.ActiveKeyboard; - NotifyOfPropertyChange(() => KeyboardImage); - NotifyOfPropertyChange(() => PreviewSettings); - LoadProfiles(); - } - - /// - /// Handles refreshing the layer preview - /// - /// - /// - private void PropertyChangeHandler(object sender, PropertyChangedEventArgs e) - { - if (e.PropertyName == "KeyboardPreview") - return; - - if (SelectedProfile != null) - ProfileProvider.AddOrUpdate(SelectedProfile); - } - - /// - /// Loads all profiles for the current game and keyboard - /// - private void LoadProfiles() - { - Profiles.Clear(); - if (_gameModel == null || ActiveKeyboard == null) - return; - - Profiles.AddRange(ProfileProvider.GetAll(_gameModel, ActiveKeyboard)); - SelectedProfile = Profiles.FirstOrDefault(); - } - - public void EditLayer() - { - if (SelectedLayer == null) - return; - - LayerEditor(SelectedLayer); - } - - /// - /// 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(_gameModel.GameDataModel, layer); - dynamic settings = new ExpandoObject(); - - settings.Title = "Artemis | Edit " + layer.Name; - manager.ShowDialog(_editorVm, null, settings); - - // If the layer was a folder, but isn't anymore, assign it's children to it's parent. - if (layer.LayerType != LayerType.Folder && layer.Children.Any()) - { - while (layer.Children.Any()) - { - var child = layer.Children[0]; - layer.Children.Remove(child); - if (layer.Parent != null) - { - layer.Parent.Children.Add(child); - layer.Parent.FixOrder(); - } - else - { - layer.Profile.Layers.Add(child); - layer.Profile.FixOrder(); - } - } - } - - UpdateLayerList(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(); - } - - public void CloneLayer() - { - if (SelectedLayer == null) - return; - - CloneLayer(SelectedLayer); - } - - /// - /// 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(); - } - - private void UpdateLayerList(LayerModel selectModel) - { - // Update the UI - Layers.Clear(); - if (SelectedProfile != null) - Layers.AddRange(SelectedProfile.Layers); - - // A small delay to allow the profile list to rebuild - Task.Factory.StartNew(() => - { - Thread.Sleep(20); - SelectedLayer = selectModel; - }); - } - - /// - /// 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) - { - if (SelectedProfile == null) - return; - - 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.GetLayers() - .Where(l => l.MustDraw()) - .FirstOrDefault(l => ((KeyboardPropertiesModel) l.Properties) - .GetRect(1) - .Contains(x, y)); - - SelectedLayer = hoverLayer; - } - - /// - /// Handler for resizing and moving the currently selected layer - /// - /// - public void MouseMoveKeyboardPreview(MouseEventArgs e) - { - if (SelectedProfile == null) - 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.GetLayers() - .Where(l => l.MustDraw()) - .FirstOrDefault(l => ((KeyboardPropertiesModel) l.Properties) - .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 = ((KeyboardPropertiesModel) hoverLayer.Properties).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; - } - - private void InvokeUpdateKeyboardPreview(object sender, ElapsedEventArgs e) - { - Application.Current.Dispatcher.InvokeAsync(UpdateKeyboardPreview, DispatcherPriority.ContextIdle); - } - - /// - /// Generates a new image for the keyboard preview - /// - public void UpdateKeyboardPreview() - { - if (SelectedProfile == null || ActiveKeyboard == null) - { - KeyboardPreview = new DrawingImage(); - return; - } - - 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 - var drawLayers = SelectedProfile.Layers - .OrderByDescending(l => l.Order) - .Where(l => l.Enabled && - (l.LayerType == LayerType.Keyboard || - l.LayerType == LayerType.KeyboardGif || - l.LayerType == LayerType.Folder)); - foreach (var layer in drawLayers) - layer.Draw(null, drawingContext, true, false); - - // 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.MustDraw()) - { - var layerRect = ((KeyboardPropertiesModel) SelectedLayer.Properties).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(); - } - KeyboardPreview = new DrawingImage(visual.Drawing); - } - - /// - /// 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 = ((KeyboardPropertiesModel) hoverLayer.Properties).GetRect(1); - var selectedProps = (KeyboardPropertiesModel) SelectedLayer.Properties; - - _draggingLayerOffset = new Point(x - selectedProps.X, y - selectedProps.Y); - _draggingLayer = hoverLayer; - // Detect dragging if cursor is in the bottom right - _resizing = Math.Sqrt(Math.Pow(x - layerRect.BottomRight.X, 2) + - Math.Pow(y - layerRect.BottomRight.Y, 2)) < 0.6; - } - - if (_draggingLayerOffset == null || _draggingLayer == null || (_draggingLayer != SelectedLayer)) - return; - - var draggingProps = (KeyboardPropertiesModel) _draggingLayer?.Properties; - - // If no setup or reset was done, handle the actual dragging action - if (_resizing) - { - draggingProps.Width = (int) Math.Round(x - draggingProps.X); - draggingProps.Height = (int) Math.Round(y - draggingProps.Y); - if (draggingProps.Width < 1) - draggingProps.Width = 1; - if (draggingProps.Height < 1) - draggingProps.Height = 1; - } - else - { - draggingProps.X = (int) Math.Round(x - _draggingLayerOffset.Value.X); - draggingProps.Y = (int) Math.Round(y - _draggingLayerOffset.Value.Y); - } - } - - /// - /// Adds a new profile to the current game and keyboard - /// - public async void AddProfile() - { - var name = await DialogService.ShowInputDialog("Add new profile", - "Please provide a profile name unique to this game and keyboard."); - - // Null when the user cancelled - if (name == null) - return; - - if (name.Length < 1) - { - 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 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 async void RenameProfile() - { - if (SelectedProfile == null) - return; - - var oldName = SelectedProfile.Name; - SelectedProfile.Name = - await DialogService.ShowInputDialog("Rename profile", "Please enter a unique new profile name"); - // Verify the name - while (ProfileProvider.GetAll().Contains(SelectedProfile)) - { - SelectedProfile.Name = - await DialogService.ShowInputDialog("Name already in use", "Please enter a unique new profile name"); - - // Null when the user cancelled - if (string.IsNullOrEmpty(SelectedProfile.Name)) - { - SelectedProfile.Name = oldName; - return; - } - } - - var newName = SelectedProfile.Name; - SelectedProfile.Name = oldName; - ProfileProvider.RenameProfile(SelectedProfile, newName); - - LoadProfiles(); - SelectedProfile = Profiles.FirstOrDefault(p => p.Name == newName); - } - - public async void DuplicateProfile() - { - if (SelectedProfile == null) - return; - - var newProfile = GeneralHelpers.Clone(SelectedProfile); - newProfile.Name = - await DialogService.ShowInputDialog("Duplicate profile", "Please enter a unique profile name"); - // Verify the name - while (ProfileProvider.GetAll().Contains(newProfile)) - { - newProfile.Name = - await DialogService.ShowInputDialog("Name already in use", "Please enter a unique profile name"); - - // Null when the user cancelled - if (string.IsNullOrEmpty(SelectedProfile.Name)) - return; - } - - ProfileProvider.AddOrUpdate(newProfile); - LoadProfiles(); - SelectedProfile = Profiles.FirstOrDefault(p => p.Name == newProfile.Name); - } - - public async void DeleteProfile() - { - if (SelectedProfile == null) - return; - - var confirm = await - DialogService.ShowQuestionMessageBox("Delete profile", - $"Are you sure you want to delete the profile named: {SelectedProfile.Name}?\n\n" + - "This cannot be undone."); - if (!confirm.Value) - return; - - ProfileProvider.DeleteProfile(SelectedProfile); - LoadProfiles(); - } - - public async void ImportProfile() - { - var dialog = new OpenFileDialog {Filter = "Artemis profile (*.xml)|*.xml"}; - var result = dialog.ShowDialog(); - if (result != DialogResult.OK) - return; - - var profile = ProfileProvider.LoadProfileIfValid(dialog.FileName); - if (profile == null) - { - DialogService.ShowErrorMessageBox("Oh noes, the profile you provided is invalid. " + - "If this keeps happening, please make an issue on GitHub and provide the profile."); - return; - } - - // Verify the game - if (profile.GameName != _gameModel.Name) - { - DialogService.ShowErrorMessageBox( - $"Oh oops! This profile is ment for {profile.GameName}, not {_gameModel.Name} :c"); - return; - } - - // Verify the keyboard - if (profile.KeyboardName != _mainManager.DeviceManager.ActiveKeyboard.Name) - { - var adjustKeyboard = await DialogService.ShowQuestionMessageBox("Profile not inteded for this keyboard", - $"Watch out, this profile wasn't ment for this keyboard, but for the {profile.KeyboardName}. " + - "You can still import it but you'll probably have to do some adjusting\n\n" + - "Continue?"); - if (!adjustKeyboard.Value) - return; - - profile.KeyboardName = _mainManager.DeviceManager.ActiveKeyboard.Name; - profile.FixBoundaries(_mainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(1)); - } - - // Verify the name - while (ProfileProvider.GetAll().Contains(profile)) - { - profile.Name = await DialogService.ShowInputDialog("Rename imported profile", - "A profile with this name already exists for this game. Please enter a new name"); - - // Null when the user cancelled - if (string.IsNullOrEmpty(profile.Name)) - return; - } - - ProfileProvider.AddOrUpdate(profile); - LoadProfiles(); - - SelectedProfile = Profiles.FirstOrDefault(p => p.Name == profile.Name); - } - - public void ExportProfile() - { - if (SelectedProfile == null) - return; - - var dialog = new SaveFileDialog {Filter = "Artemis profile (*.xml)|*.xml"}; - var result = dialog.ShowDialog(); - if (result != DialogResult.OK) - return; - - ProfileProvider.ExportProfile(SelectedProfile, dialog.FileName); - } - } +using System.ComponentModel; +using System.Dynamic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Windows.Input; +using System.Windows.Media; +using Artemis.DAL; +using Artemis.DeviceProviders; +using Artemis.Events; +using Artemis.Managers; +using Artemis.Models; +using Artemis.Models.Profiles; +using Artemis.Services; +using Artemis.Styles.DropTargetAdorners; +using Artemis.Utilities; +using Caliburn.Micro; +using GongSolutions.Wpf.DragDrop; +using Ninject; +using DragDropEffects = System.Windows.DragDropEffects; +using IDropTarget = GongSolutions.Wpf.DragDrop.IDropTarget; +using MouseEventArgs = System.Windows.Input.MouseEventArgs; +using Screen = Caliburn.Micro.Screen; + +namespace Artemis.ViewModels.Profiles +{ + public sealed class ProfileEditorViewModel : Screen, IHandle, IDropTarget + { + private readonly GameModel _gameModel; + private readonly MainManager _mainManager; + private LayerEditorViewModel _editorVm; + private ImageSource _keyboardPreview; + private BindableCollection _layers; + private BindableCollection _profiles; + private ProfileModel _selectedProfile; + + public ProfileEditorViewModel(IEventAggregator events, MainManager mainManager, GameModel gameModel, + ProfileViewModel profileViewModel, MetroDialogService dialogService) + { + _mainManager = mainManager; + _gameModel = gameModel; + + Profiles = new BindableCollection(); + Layers = new BindableCollection(); + ProfileViewModel = profileViewModel; + DialogService = dialogService; + + events.Subscribe(this); + + PropertyChanged += PropertyChangeHandler; + LoadProfiles(); + } + + [Inject] + public MetroDialogService DialogService { get; set; } + + public ProfileViewModel ProfileViewModel { get; set; } + + 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 ProfileModel SelectedProfile + { + get { return _selectedProfile; } + set + { + if (Equals(value, _selectedProfile)) return; + _selectedProfile = value; + NotifyOfPropertyChange(() => SelectedProfile); + } + } + + public ImageSource KeyboardPreview + { + get { return _keyboardPreview; } + set + { + if (Equals(value, _keyboardPreview)) return; + _keyboardPreview = value; + NotifyOfPropertyChange(() => KeyboardPreview); + } + } + + public PreviewSettings? PreviewSettings => _mainManager.DeviceManager.ActiveKeyboard?.PreviewSettings; + + public bool ProfileSelected => SelectedProfile != null; + public bool LayerSelected => SelectedProfile != null && ProfileViewModel.SelectedLayer != null; + + public void DragOver(IDropInfo dropInfo) + { + var source = dropInfo.Data as LayerModel; + var target = dropInfo.TargetItem as LayerModel; + if (source == null || target == null || source == target) + return; + + if (dropInfo.InsertPosition == RelativeInsertPosition.TargetItemCenter && + target.LayerType == LayerType.Folder) + { + dropInfo.DropTargetAdorner = typeof(DropTargetMetroHighlightAdorner); + dropInfo.Effects = DragDropEffects.Copy; + } + else + { + dropInfo.DropTargetAdorner = typeof(DropTargetMetroInsertionAdorner); + dropInfo.Effects = DragDropEffects.Move; + } + } + + public void Drop(IDropInfo dropInfo) + { + var source = dropInfo.Data as LayerModel; + var target = dropInfo.TargetItem as LayerModel; + if (source == null || target == null || source == target) + return; + + // Don't allow a folder to become it's own child, that's just weird + if (target.Parent == source) + return; + + // Remove the source from it's old profile/parent + if (source.Parent == null) + source.Profile.Layers.Remove(source); + else + source.Parent.Children.Remove(source); + + if (dropInfo.InsertPosition == RelativeInsertPosition.TargetItemCenter && + target.LayerType == LayerType.Folder) + { + // Insert into folder + source.Order = -1; + target.Children.Add(source); + target.FixOrder(); + } + else + { + // Insert the source into it's new profile/parent and update the order + if (dropInfo.InsertPosition == RelativeInsertPosition.AfterTargetItem) + source.Order = target.Order + 1; + else + source.Order = target.Order - 1; + if (target.Parent == null) + target.Profile.Layers.Add(source); + else + target.Parent.Children.Add(source); + } + + target.Profile?.FixOrder(); + target.Parent?.FixOrder(); + UpdateLayerList(source); + } + + + /// + /// Handles chaning the active keyboard, updating the preview image and profiles collection + /// + /// + public void Handle(ActiveKeyboardChanged message) + { + NotifyOfPropertyChange(() => PreviewSettings); + LoadProfiles(); + } + + /// + /// Handles refreshing the layer preview + /// + /// + /// + private void PropertyChangeHandler(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "KeyboardPreview") + return; + + if (SelectedProfile != null) + ProfileProvider.AddOrUpdate(SelectedProfile); + + if (e.PropertyName != "SelectedProfile") + return; + + // Update ProfileViewModel + ProfileViewModel.SelectedProfile = SelectedProfile; + // Update interface + Layers.Clear(); + if (SelectedProfile != null) + Layers.AddRange(SelectedProfile.Layers); + // Update booleans + NotifyOfPropertyChange(() => ProfileSelected); + NotifyOfPropertyChange(() => LayerSelected); + } + + /// + /// Loads all profiles for the current game and keyboard + /// + private void LoadProfiles() + { + Profiles.Clear(); + if (_gameModel == null || _mainManager.DeviceManager.ActiveKeyboard == null) + return; + + Profiles.AddRange(ProfileProvider.GetAll(_gameModel, _mainManager.DeviceManager.ActiveKeyboard)); + SelectedProfile = Profiles.FirstOrDefault(); + } + + public void EditLayer() + { + if (ProfileViewModel.SelectedLayer == null) + return; + + LayerEditor(ProfileViewModel.SelectedLayer); + } + + /// + /// 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(_gameModel.GameDataModel, layer); + dynamic settings = new ExpandoObject(); + + settings.Title = "Artemis | Edit " + layer.Name; + manager.ShowDialog(_editorVm, null, settings); + + // If the layer was a folder, but isn't anymore, assign it's children to it's parent. + if (layer.LayerType != LayerType.Folder && layer.Children.Any()) + { + while (layer.Children.Any()) + { + var child = layer.Children[0]; + layer.Children.Remove(child); + if (layer.Parent != null) + { + layer.Parent.Children.Add(child); + layer.Parent.FixOrder(); + } + else + { + layer.Profile.Layers.Add(child); + layer.Profile.FixOrder(); + } + } + } + + UpdateLayerList(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); + + ProfileViewModel.SelectedLayer = layer; + } + + /// + /// Removes the currently selected layer from the profile + /// + public void RemoveLayer() + { + if (SelectedProfile == null || ProfileViewModel.SelectedLayer == null) + return; + + SelectedProfile.Layers.Remove(ProfileViewModel.SelectedLayer); + Layers.Remove(ProfileViewModel.SelectedLayer); + + SelectedProfile.FixOrder(); + } + + /// + /// Removes the given layer from the profile + /// + /// + public void RemoveLayerFromMenu(LayerModel layer) + { + SelectedProfile.Layers.Remove(layer); + Layers.Remove(layer); + + SelectedProfile.FixOrder(); + } + + public void CloneLayer() + { + if (ProfileViewModel.SelectedLayer == null) + return; + + CloneLayer(ProfileViewModel.SelectedLayer); + } + + /// + /// 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(); + } + + private void UpdateLayerList(LayerModel selectModel) + { + // Update the UI + Layers.Clear(); + if (SelectedProfile != null) + Layers.AddRange(SelectedProfile.Layers); + + // A small delay to allow the profile list to rebuild + Task.Factory.StartNew(() => + { + Thread.Sleep(20); + ProfileViewModel.SelectedLayer = selectModel; + }); + } + + /// + /// Handler for clicking + /// + /// + public void MouseDownKeyboardPreview(MouseButtonEventArgs e) + { + ProfileViewModel.MouseDownKeyboardPreview(e); + } + + /// + /// 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) + { + ProfileViewModel.MouseUpKeyboardPreview(e); + } + + /// + /// Handler for resizing and moving the currently selected layer + /// + /// + public void MouseMoveKeyboardPreview(MouseEventArgs e) + { + ProfileViewModel.MouseMoveKeyboardPreview(e); + } + + /// + /// Adds a new profile to the current game and keyboard + /// + public async void AddProfile() + { + var name = await DialogService.ShowInputDialog("Add new profile", + "Please provide a profile name unique to this game and keyboard."); + + // Null when the user cancelled + if (name == null) + return; + + if (name.Length < 1) + { + DialogService.ShowMessageBox("Invalid profile name", "Please provide a valid profile name"); + return; + } + + var profile = new ProfileModel + { + Name = name, + KeyboardName = _mainManager.DeviceManager.ActiveKeyboard.Name, + GameName = _gameModel.Name + }; + + if (ProfileProvider.GetAll().Contains(profile)) + { + var overwrite = await 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 async void RenameProfile() + { + if (SelectedProfile == null) + return; + + var oldName = SelectedProfile.Name; + SelectedProfile.Name = + await DialogService.ShowInputDialog("Rename profile", "Please enter a unique new profile name"); + // Verify the name + while (ProfileProvider.GetAll().Contains(SelectedProfile)) + { + SelectedProfile.Name = + await DialogService.ShowInputDialog("Name already in use", "Please enter a unique new profile name"); + + // Null when the user cancelled + if (string.IsNullOrEmpty(SelectedProfile.Name)) + { + SelectedProfile.Name = oldName; + return; + } + } + + var newName = SelectedProfile.Name; + SelectedProfile.Name = oldName; + ProfileProvider.RenameProfile(SelectedProfile, newName); + + LoadProfiles(); + SelectedProfile = Profiles.FirstOrDefault(p => p.Name == newName); + } + + public async void DuplicateProfile() + { + if (SelectedProfile == null) + return; + + var newProfile = GeneralHelpers.Clone(SelectedProfile); + newProfile.Name = + await DialogService.ShowInputDialog("Duplicate profile", "Please enter a unique profile name"); + // Verify the name + while (ProfileProvider.GetAll().Contains(newProfile)) + { + newProfile.Name = + await DialogService.ShowInputDialog("Name already in use", "Please enter a unique profile name"); + + // Null when the user cancelled + if (string.IsNullOrEmpty(SelectedProfile.Name)) + return; + } + + ProfileProvider.AddOrUpdate(newProfile); + LoadProfiles(); + SelectedProfile = Profiles.FirstOrDefault(p => p.Name == newProfile.Name); + } + + public async void DeleteProfile() + { + if (SelectedProfile == null) + return; + + var confirm = await + DialogService.ShowQuestionMessageBox("Delete profile", + $"Are you sure you want to delete the profile named: {SelectedProfile.Name}?\n\n" + + "This cannot be undone."); + if (!confirm.Value) + return; + + ProfileProvider.DeleteProfile(SelectedProfile); + LoadProfiles(); + } + + public async void ImportProfile() + { + var dialog = new OpenFileDialog {Filter = "Artemis profile (*.xml)|*.xml"}; + var result = dialog.ShowDialog(); + if (result != DialogResult.OK) + return; + + var profile = ProfileProvider.LoadProfileIfValid(dialog.FileName); + if (profile == null) + { + DialogService.ShowErrorMessageBox("Oh noes, the profile you provided is invalid. " + + "If this keeps happening, please make an issue on GitHub and provide the profile."); + return; + } + + // Verify the game + if (profile.GameName != _gameModel.Name) + { + DialogService.ShowErrorMessageBox( + $"Oh oops! This profile is ment for {profile.GameName}, not {_gameModel.Name} :c"); + return; + } + + // Verify the keyboard + if (profile.KeyboardName != _mainManager.DeviceManager.ActiveKeyboard.Name) + { + var adjustKeyboard = await DialogService.ShowQuestionMessageBox("Profile not inteded for this keyboard", + $"Watch out, this profile wasn't ment for this keyboard, but for the {profile.KeyboardName}. " + + "You can still import it but you'll probably have to do some adjusting\n\n" + + "Continue?"); + if (!adjustKeyboard.Value) + return; + + profile.KeyboardName = _mainManager.DeviceManager.ActiveKeyboard.Name; + profile.FixBoundaries(_mainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(1)); + } + + // Verify the name + while (ProfileProvider.GetAll().Contains(profile)) + { + profile.Name = await DialogService.ShowInputDialog("Rename imported profile", + "A profile with this name already exists for this game. Please enter a new name"); + + // Null when the user cancelled + if (string.IsNullOrEmpty(profile.Name)) + return; + } + + ProfileProvider.AddOrUpdate(profile); + LoadProfiles(); + + SelectedProfile = Profiles.FirstOrDefault(p => p.Name == profile.Name); + } + + public void ExportProfile() + { + if (SelectedProfile == null) + return; + + var dialog = new SaveFileDialog {Filter = "Artemis profile (*.xml)|*.xml"}; + var result = dialog.ShowDialog(); + if (result != DialogResult.OK) + return; + + ProfileProvider.ExportProfile(SelectedProfile, dialog.FileName); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/Profiles/ProfileViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/ProfileViewModel.cs new file mode 100644 index 000000000..e8cf9598b --- /dev/null +++ b/Artemis/Artemis/ViewModels/Profiles/ProfileViewModel.cs @@ -0,0 +1,306 @@ +using System; +using System.Linq; +using System.Timers; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Threading; +using Artemis.Events; +using Artemis.Managers; +using Artemis.Models.Profiles; +using Artemis.Models.Profiles.Properties; +using Artemis.Utilities; +using Caliburn.Micro; +using MahApps.Metro; + +namespace Artemis.ViewModels.Profiles +{ + public class ProfileViewModel : PropertyChangedBase, IHandle + { + private readonly DeviceManager _deviceManager; + private DateTime _downTime; + private LayerModel _draggingLayer; + private Point? _draggingLayerOffset; + private DrawingImage _keyboardPreview; + private Cursor _keyboardPreviewCursor; + private bool _resizing; + private LayerModel _selectedLayer; + + public ProfileViewModel(IEventAggregator events, DeviceManager deviceManager) + { + events.Subscribe(this); + _deviceManager = deviceManager; + + PreviewTimer = new Timer(40); + PreviewTimer.Elapsed += InvokeUpdateKeyboardPreview; + } + + public ProfileModel SelectedProfile { get; set; } + public Timer PreviewTimer { get; set; } + + public LayerModel SelectedLayer + { + get { return _selectedLayer; } + set + { + if (Equals(value, _selectedLayer)) return; + _selectedLayer = value; + NotifyOfPropertyChange(() => SelectedLayer); + } + } + + public DrawingImage KeyboardPreview + { + get { return _keyboardPreview; } + set + { + if (Equals(value, _keyboardPreview)) return; + _keyboardPreview = value; + NotifyOfPropertyChange(() => KeyboardPreview); + } + } + + + public ImageSource KeyboardImage + { + get + { + return ImageUtilities.BitmapToBitmapImage(_deviceManager.ActiveKeyboard?.PreviewSettings.Image); + } + } + + private void InvokeUpdateKeyboardPreview(object sender, ElapsedEventArgs e) + { + Application.Current.Dispatcher.InvokeAsync(UpdateKeyboardPreview, DispatcherPriority.ContextIdle); + } + + public void Activate() + { + PreviewTimer.Start(); + } + + public void Deactivate() + { + PreviewTimer.Stop(); + } + + #region Drawing + + /// + /// Generates a new image for the keyboard preview + /// + public void UpdateKeyboardPreview() + { + if (SelectedProfile == null || _deviceManager.ActiveKeyboard == null) + { + KeyboardPreview = new DrawingImage(); + return; + } + + var keyboardRect = _deviceManager.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 + var drawLayers = SelectedProfile.Layers + .OrderByDescending(l => l.Order) + .Where(l => l.Enabled && + (l.LayerType == LayerType.Keyboard || + l.LayerType == LayerType.KeyboardGif || + l.LayerType == LayerType.Folder)); + foreach (var layer in drawLayers) + layer.Draw(null, drawingContext, true, false); + + // 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.MustDraw()) + { + var layerRect = ((KeyboardPropertiesModel) SelectedLayer.Properties).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(); + } + KeyboardPreview = new DrawingImage(visual.Drawing); + } + + #endregion + + #region Processing + + /// + /// 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) + { + if (SelectedProfile == null) + return; + + var timeSinceDown = DateTime.Now - _downTime; + if (!(timeSinceDown.TotalMilliseconds < 500)) + return; + + var keyboard = _deviceManager.ActiveKeyboard; + var pos = e.GetPosition((Image) e.OriginalSource); + var x = pos.X/((double) keyboard.PreviewSettings.Width/keyboard.Width); + var y = pos.Y/((double) keyboard.PreviewSettings.Height/keyboard.Height); + + var hoverLayer = SelectedProfile.GetLayers() + .Where(l => l.MustDraw()) + .FirstOrDefault(l => ((KeyboardPropertiesModel) l.Properties) + .GetRect(1) + .Contains(x, y)); + + SelectedLayer = hoverLayer; + } + + /// + /// Handler for resizing and moving the currently selected layer + /// + /// + public void MouseMoveKeyboardPreview(MouseEventArgs e) + { + if (SelectedProfile == null) + return; + + var pos = e.GetPosition((Image) e.OriginalSource); + var keyboard = _deviceManager.ActiveKeyboard; + var x = pos.X/((double) keyboard.PreviewSettings.Width/keyboard.Width); + var y = pos.Y/((double) keyboard.PreviewSettings.Height/keyboard.Height); + var hoverLayer = SelectedProfile.GetLayers() + .Where(l => l.MustDraw()) + .FirstOrDefault(l => ((KeyboardPropertiesModel) l.Properties) + .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 = ((KeyboardPropertiesModel) hoverLayer.Properties).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; + } + + public Cursor KeyboardPreviewCursor + { + get { return _keyboardPreviewCursor; } + set + { + if (Equals(value, _keyboardPreviewCursor)) return; + _keyboardPreviewCursor = value; + NotifyOfPropertyChange(() => KeyboardPreviewCursor); + } + } + + /// + /// 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 = ((KeyboardPropertiesModel) hoverLayer.Properties).GetRect(1); + var selectedProps = (KeyboardPropertiesModel) SelectedLayer.Properties; + + _draggingLayerOffset = new Point(x - selectedProps.X, y - selectedProps.Y); + _draggingLayer = hoverLayer; + // Detect dragging if cursor is in the bottom right + _resizing = Math.Sqrt(Math.Pow(x - layerRect.BottomRight.X, 2) + + Math.Pow(y - layerRect.BottomRight.Y, 2)) < 0.6; + } + + if (_draggingLayerOffset == null || _draggingLayer == null || (_draggingLayer != SelectedLayer)) + return; + + var draggingProps = (KeyboardPropertiesModel) _draggingLayer?.Properties; + + // If no setup or reset was done, handle the actual dragging action + if (_resizing) + { + draggingProps.Width = (int) Math.Round(x - draggingProps.X); + draggingProps.Height = (int) Math.Round(y - draggingProps.Y); + if (draggingProps.Width < 1) + draggingProps.Width = 1; + if (draggingProps.Height < 1) + draggingProps.Height = 1; + } + else + { + draggingProps.X = (int) Math.Round(x - _draggingLayerOffset.Value.X); + draggingProps.Y = (int) Math.Round(y - _draggingLayerOffset.Value.Y); + } + } + + #endregion + + public void Handle(ActiveKeyboardChanged message) + { + NotifyOfPropertyChange(() => KeyboardImage); + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/LayerEditor/Properties/FolderPropertiesViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/Properties/FolderPropertiesViewModel.cs similarity index 94% rename from Artemis/Artemis/ViewModels/LayerEditor/Properties/FolderPropertiesViewModel.cs rename to Artemis/Artemis/ViewModels/Profiles/Properties/FolderPropertiesViewModel.cs index 0603ee33c..94bdf9673 100644 --- a/Artemis/Artemis/ViewModels/LayerEditor/Properties/FolderPropertiesViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/Properties/FolderPropertiesViewModel.cs @@ -2,7 +2,7 @@ using Artemis.Models.Profiles.Properties; using Artemis.Utilities; -namespace Artemis.ViewModels.LayerEditor.Properties +namespace Artemis.ViewModels.Profiles.Properties { public class FolderPropertiesViewModel : LayerPropertiesViewModel { diff --git a/Artemis/Artemis/ViewModels/LayerEditor/Properties/HeadsetPropertiesViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/Properties/HeadsetPropertiesViewModel.cs similarity index 94% rename from Artemis/Artemis/ViewModels/LayerEditor/Properties/HeadsetPropertiesViewModel.cs rename to Artemis/Artemis/ViewModels/Profiles/Properties/HeadsetPropertiesViewModel.cs index 5e5ec5b93..9937b0e42 100644 --- a/Artemis/Artemis/ViewModels/LayerEditor/Properties/HeadsetPropertiesViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/Properties/HeadsetPropertiesViewModel.cs @@ -2,7 +2,7 @@ using Artemis.Models.Profiles.Properties; using Artemis.Utilities; -namespace Artemis.ViewModels.LayerEditor.Properties +namespace Artemis.ViewModels.Profiles.Properties { public class HeadsetPropertiesViewModel : LayerPropertiesViewModel { diff --git a/Artemis/Artemis/ViewModels/LayerEditor/Properties/KeyboardPropertiesViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/Properties/KeyboardPropertiesViewModel.cs similarity index 98% rename from Artemis/Artemis/ViewModels/LayerEditor/Properties/KeyboardPropertiesViewModel.cs rename to Artemis/Artemis/ViewModels/Profiles/Properties/KeyboardPropertiesViewModel.cs index 026ca8b79..bb24df861 100644 --- a/Artemis/Artemis/ViewModels/LayerEditor/Properties/KeyboardPropertiesViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/Properties/KeyboardPropertiesViewModel.cs @@ -4,7 +4,7 @@ using Artemis.Models.Profiles.Properties; using Artemis.Utilities; using Caliburn.Micro; -namespace Artemis.ViewModels.LayerEditor.Properties +namespace Artemis.ViewModels.Profiles.Properties { public class KeyboardPropertiesViewModel : LayerPropertiesViewModel { diff --git a/Artemis/Artemis/ViewModels/LayerEditor/Properties/LayerPropertiesViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/Properties/LayerPropertiesViewModel.cs similarity index 89% rename from Artemis/Artemis/ViewModels/LayerEditor/Properties/LayerPropertiesViewModel.cs rename to Artemis/Artemis/ViewModels/Profiles/Properties/LayerPropertiesViewModel.cs index 441490ea9..daf8fd465 100644 --- a/Artemis/Artemis/ViewModels/LayerEditor/Properties/LayerPropertiesViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/Properties/LayerPropertiesViewModel.cs @@ -2,7 +2,7 @@ using Artemis.Models.Profiles.Properties; using Caliburn.Micro; -namespace Artemis.ViewModels.LayerEditor.Properties +namespace Artemis.ViewModels.Profiles.Properties { public abstract class LayerPropertiesViewModel : PropertyChangedBase { diff --git a/Artemis/Artemis/ViewModels/LayerEditor/Properties/MousePropertiesViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/Properties/MousePropertiesViewModel.cs similarity index 94% rename from Artemis/Artemis/ViewModels/LayerEditor/Properties/MousePropertiesViewModel.cs rename to Artemis/Artemis/ViewModels/Profiles/Properties/MousePropertiesViewModel.cs index 0869b28e4..b31e59b37 100644 --- a/Artemis/Artemis/ViewModels/LayerEditor/Properties/MousePropertiesViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/Properties/MousePropertiesViewModel.cs @@ -2,7 +2,7 @@ using Artemis.Models.Profiles.Properties; using Artemis.Utilities; -namespace Artemis.ViewModels.LayerEditor.Properties +namespace Artemis.ViewModels.Profiles.Properties { public class MousePropertiesViewModel : LayerPropertiesViewModel { diff --git a/Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml b/Artemis/Artemis/Views/Profiles/LayerConditionView.xaml similarity index 94% rename from Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml rename to Artemis/Artemis/Views/Profiles/LayerConditionView.xaml index d0a68fdaf..2bef30de4 100644 --- a/Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml +++ b/Artemis/Artemis/Views/Profiles/LayerConditionView.xaml @@ -1,76 +1,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml.cs b/Artemis/Artemis/Views/Profiles/LayerConditionView.xaml.cs similarity index 85% rename from Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml.cs rename to Artemis/Artemis/Views/Profiles/LayerConditionView.xaml.cs index ef50d2c49..61fb53029 100644 --- a/Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml.cs +++ b/Artemis/Artemis/Views/Profiles/LayerConditionView.xaml.cs @@ -1,15 +1,15 @@ -using System.Windows.Controls; - -namespace Artemis.Views.LayerEditor -{ - /// - /// Interaction logic for LayerConditionView.xaml - /// - public partial class LayerConditionView : UserControl - { - public LayerConditionView() - { - InitializeComponent(); - } - } +using System.Windows.Controls; + +namespace Artemis.Views.Profiles +{ + /// + /// Interaction logic for LayerConditionView.xaml + /// + public partial class LayerConditionView : UserControl + { + public LayerConditionView() + { + InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Views/LayerEditor/LayerDynamicPropertiesView.xaml b/Artemis/Artemis/Views/Profiles/LayerDynamicPropertiesView.xaml similarity index 98% rename from Artemis/Artemis/Views/LayerEditor/LayerDynamicPropertiesView.xaml rename to Artemis/Artemis/Views/Profiles/LayerDynamicPropertiesView.xaml index cb68eb80d..500c6ae18 100644 --- a/Artemis/Artemis/Views/LayerEditor/LayerDynamicPropertiesView.xaml +++ b/Artemis/Artemis/Views/Profiles/LayerDynamicPropertiesView.xaml @@ -1,4 +1,4 @@ - /// Interaction logic for LayerDynamicPropertiesView.xaml diff --git a/Artemis/Artemis/Views/LayerEditor/LayerEditorView.xaml b/Artemis/Artemis/Views/Profiles/LayerEditorView.xaml similarity index 98% rename from Artemis/Artemis/Views/LayerEditor/LayerEditorView.xaml rename to Artemis/Artemis/Views/Profiles/LayerEditorView.xaml index 20ee71098..a695107ea 100644 --- a/Artemis/Artemis/Views/LayerEditor/LayerEditorView.xaml +++ b/Artemis/Artemis/Views/Profiles/LayerEditorView.xaml @@ -1,4 +1,4 @@ - /// Interaction logic for LayerEditorView.xaml diff --git a/Artemis/Artemis/Views/ProfileEditorView.xaml b/Artemis/Artemis/Views/Profiles/ProfileEditorView.xaml similarity index 96% rename from Artemis/Artemis/Views/ProfileEditorView.xaml rename to Artemis/Artemis/Views/Profiles/ProfileEditorView.xaml index e25765afa..9b893fdf3 100644 --- a/Artemis/Artemis/Views/ProfileEditorView.xaml +++ b/Artemis/Artemis/Views/Profiles/ProfileEditorView.xaml @@ -1,235 +1,235 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Artemis/Artemis/Views/ProfileEditorView.xaml.cs b/Artemis/Artemis/Views/Profiles/ProfileEditorView.xaml.cs similarity index 88% rename from Artemis/Artemis/Views/ProfileEditorView.xaml.cs rename to Artemis/Artemis/Views/Profiles/ProfileEditorView.xaml.cs index 1770824c7..b2abd5ee2 100644 --- a/Artemis/Artemis/Views/ProfileEditorView.xaml.cs +++ b/Artemis/Artemis/Views/Profiles/ProfileEditorView.xaml.cs @@ -1,15 +1,15 @@ -using System.Windows.Controls; - -namespace Artemis.Views -{ - /// - /// Interaction logic for ProfileEditorView.xaml - /// - public partial class ProfileEditorView : UserControl - { - public ProfileEditorView() - { - InitializeComponent(); - } - } +using System.Windows.Controls; + +namespace Artemis.Views.Profiles +{ + /// + /// Interaction logic for ProfileEditorView.xaml + /// + public partial class ProfileEditorView : UserControl + { + public ProfileEditorView() + { + InitializeComponent(); + } + } } \ No newline at end of file diff --git a/Artemis/Artemis/Views/LayerEditor/Properties/FolderPropertiesView.xaml b/Artemis/Artemis/Views/Profiles/Properties/FolderPropertiesView.xaml similarity index 90% rename from Artemis/Artemis/Views/LayerEditor/Properties/FolderPropertiesView.xaml rename to Artemis/Artemis/Views/Profiles/Properties/FolderPropertiesView.xaml index e1d82bec0..4d59545bd 100644 --- a/Artemis/Artemis/Views/LayerEditor/Properties/FolderPropertiesView.xaml +++ b/Artemis/Artemis/Views/Profiles/Properties/FolderPropertiesView.xaml @@ -1,4 +1,4 @@ - /// Interaction logic for FolderPropertiesView.xaml diff --git a/Artemis/Artemis/Views/LayerEditor/Properties/HeadsetPropertiesView.xaml b/Artemis/Artemis/Views/Profiles/Properties/HeadsetPropertiesView.xaml similarity index 95% rename from Artemis/Artemis/Views/LayerEditor/Properties/HeadsetPropertiesView.xaml rename to Artemis/Artemis/Views/Profiles/Properties/HeadsetPropertiesView.xaml index 79c149643..a345a23a5 100644 --- a/Artemis/Artemis/Views/LayerEditor/Properties/HeadsetPropertiesView.xaml +++ b/Artemis/Artemis/Views/Profiles/Properties/HeadsetPropertiesView.xaml @@ -1,4 +1,4 @@ - /// Interaction logic for HeadsetPropertiesView.xaml diff --git a/Artemis/Artemis/Views/LayerEditor/Properties/KeyboardPropertiesView.xaml b/Artemis/Artemis/Views/Profiles/Properties/KeyboardPropertiesView.xaml similarity index 98% rename from Artemis/Artemis/Views/LayerEditor/Properties/KeyboardPropertiesView.xaml rename to Artemis/Artemis/Views/Profiles/Properties/KeyboardPropertiesView.xaml index 2b18451f7..8ada893c9 100644 --- a/Artemis/Artemis/Views/LayerEditor/Properties/KeyboardPropertiesView.xaml +++ b/Artemis/Artemis/Views/Profiles/Properties/KeyboardPropertiesView.xaml @@ -1,4 +1,4 @@ - /// Interaction logic for KeyboardPropertiesView.xaml diff --git a/Artemis/Artemis/Views/LayerEditor/Properties/MousePropertiesView.xaml b/Artemis/Artemis/Views/Profiles/Properties/MousePropertiesView.xaml similarity index 95% rename from Artemis/Artemis/Views/LayerEditor/Properties/MousePropertiesView.xaml rename to Artemis/Artemis/Views/Profiles/Properties/MousePropertiesView.xaml index 68225c70b..ad2724bbb 100644 --- a/Artemis/Artemis/Views/LayerEditor/Properties/MousePropertiesView.xaml +++ b/Artemis/Artemis/Views/Profiles/Properties/MousePropertiesView.xaml @@ -1,4 +1,4 @@ - /// Interaction logic for MousePropertiesView.xaml diff --git a/Artemis/Razer2Artemis/Logger.cpp b/Artemis/Razer2Artemis/Logger.cpp new file mode 100644 index 000000000..121fbcaae --- /dev/null +++ b/Artemis/Razer2Artemis/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/Razer2Artemis/Logger.h b/Artemis/Razer2Artemis/Logger.h new file mode 100644 index 000000000..0b8295fe6 --- /dev/null +++ b/Artemis/Razer2Artemis/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/Razer2Artemis/Razer2Artemis.def b/Artemis/Razer2Artemis/Razer2Artemis.def new file mode 100644 index 000000000..c04d11712 --- /dev/null +++ b/Artemis/Razer2Artemis/Razer2Artemis.def @@ -0,0 +1,17 @@ +LIBRARY Razer2Artemis.dll + +EXPORTS + + CreateEffect + CreateHeadsetEffect + CreateKeyboardEffect + CreateKeypadEffect + CreateMouseEffect + CreateMousepadEffect + DeleteEffect + Init + QueryDevice + RegisterEventNotification + SetEffect + UnInit + UnregisterEventNotification diff --git a/Artemis/Razer2Artemis/Razer2Artemis.vcxproj b/Artemis/Razer2Artemis/Razer2Artemis.vcxproj new file mode 100644 index 000000000..a1fb26458 --- /dev/null +++ b/Artemis/Razer2Artemis/Razer2Artemis.vcxproj @@ -0,0 +1,142 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {39711909-C1D5-46CE-A9EA-2D561692EA47} + Razer2Artemis + 8.1 + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + DynamicLibrary + true + v140 + MultiByte + + + DynamicLibrary + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + .dll + + + .dll + + + + Level3 + Disabled + true + + + + + Level3 + Disabled + + + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Razer2Artemis.def + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + Level3 + MaxSpeed + true + true + + + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + true + true + Razer2Artemis.def + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Artemis/Razer2Artemis/Razer2Artemis.vcxproj.filters b/Artemis/Razer2Artemis/Razer2Artemis.vcxproj.filters new file mode 100644 index 000000000..82c9ba469 --- /dev/null +++ b/Artemis/Razer2Artemis/Razer2Artemis.vcxproj.filters @@ -0,0 +1,47 @@ + + + + + {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 + + + + + Source Files + + + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/Artemis/Razer2Artemis/RzChromaSDKDefines.h b/Artemis/Razer2Artemis/RzChromaSDKDefines.h new file mode 100644 index 000000000..0f09bf023 --- /dev/null +++ b/Artemis/Razer2Artemis/RzChromaSDKDefines.h @@ -0,0 +1,148 @@ +//! \file RzChromaSDKDefines.h +//! \brief Definitions of global and static variables. + +#ifndef _RZSCHROMADKDEFINES_H_ +#define _RZSCHROMADKDEFINES_H_ + +#pragma once + +#ifndef GUID_DEFINED +#include +#endif + +namespace ChromaSDK +{ + // Keyboards + //! Razer Blackwidow Chroma device. + // {2EA1BB63-CA28-428D-9F06-196B88330BBB} + static const GUID BLACKWIDOW_CHROMA = + { 0x2ea1bb63, 0xca28, 0x428d,{ 0x9f, 0x06, 0x19, 0x6b, 0x88, 0x33, 0x0b, 0xbb } }; + + //! Razer Blackwidow Chroma Tournament Edition device. + // {ED1C1B82-BFBE-418F-B49D-D03F05B149DF} + static const GUID BLACKWIDOW_CHROMA_TE = + { 0xed1c1b82, 0xbfbe, 0x418f,{ 0xb4, 0x9d, 0xd0, 0x3f, 0x5, 0xb1, 0x49, 0xdf } }; + + //! Razer Deathstalker device. + // {18C5AD9B-4326-4828-92C4-2669A66D2283} + static const GUID DEATHSTALKER_CHROMA = + { 0x18c5ad9b, 0x4326, 0x4828,{ 0x92, 0xc4, 0x26, 0x69, 0xa6, 0x6d, 0x22, 0x83 } }; + + //! Overwatch Keyboard. + // {872AB2A9-7959-4478-9FED-15F6186E72E4} + static const GUID OVERWATCH_KEYBOARD = + { 0x872ab2a9, 0x7959, 0x4478,{ 0x9f, 0xed, 0x15, 0xf6, 0x18, 0x6e, 0x72, 0xe4 } }; + + //! Razer Blackwidow X Chroma device. + // {5AF60076-ADE9-43D4-B574-52599293B554} + static const GUID BLACKWIDOW_X_CHROMA = + { 0x5af60076, 0xade9, 0x43d4,{ 0xb5, 0x74, 0x52, 0x59, 0x92, 0x93, 0xb5, 0x54 } }; + + //! Razer Blackwidow X TE Chroma device. + // {2D84DD51-3290-4AAC-9A89-D8AFDE38B57C} + static const GUID BLACKWIDOW_X_TE_CHROMA = + { 0x2d84dd51, 0x3290, 0x4aac,{ 0x9a, 0x89, 0xd8, 0xaf, 0xde, 0x38, 0xb5, 0x7c } }; + + //! Razer Blade Stealth. + // {C83BDFE8-E7FC-40E0-99DB-872E23F19891} + static const GUID BLADE_STEALTH = + { 0xc83bdfe8, 0xe7fc, 0x40e0,{ 0x99, 0xdb, 0x87, 0x2e, 0x23, 0xf1, 0x98, 0x91 } }; + + //! Razer Blade + // {F2BEDFAF-A0FE-4651-9D41-B6CE603A3DDD} + static const GUID BLADE = + { 0xf2bedfaf, 0xa0fe, 0x4651,{ 0x9d, 0x41, 0xb6, 0xce, 0x60, 0x3a, 0x3d, 0xdd } }; + + + // Mice + //! Razer Deathadder Chroma device. + // {AEC50D91-B1F1-452F-8E16-7B73F376FDF3} + static const GUID DEATHADDER_CHROMA = + { 0xaec50d91, 0xb1f1, 0x452f,{ 0x8e, 0x16, 0x7b, 0x73, 0xf3, 0x76, 0xfd, 0xf3 } }; + + //! Razer Mamba Chroma Tournament Edition device. + // {7EC00450-E0EE-4289-89D5-0D879C19061A} + static const GUID MAMBA_CHROMA_TE = + { 0x7ec00450, 0xe0ee, 0x4289,{ 0x89, 0xd5, 0xd, 0x87, 0x9c, 0x19, 0x6, 0x1a } }; + + //! Razer Diamondback device. + // {FF8A5929-4512-4257-8D59-C647BF9935D0} + static const GUID DIAMONDBACK_CHROMA = + { 0xff8a5929, 0x4512, 0x4257,{ 0x8d, 0x59, 0xc6, 0x47, 0xbf, 0x99, 0x35, 0xd0 } }; + + //! Razer Mamba device. + // {D527CBDC-EB0A-483A-9E89-66D50463EC6C} + static const GUID MAMBA_CHROMA = + { 0xd527cbdc, 0xeb0a, 0x483a,{ 0x9e, 0x89, 0x66, 0xd5, 0x4, 0x63, 0xec, 0x6c } }; + + //! Razer Naga Epic device. + // {D714C50B-7158-4368-B99C-601ACB985E98} + static const GUID NAGA_EPIC_CHROMA = + { 0xd714c50b, 0x7158, 0x4368,{ 0xb9, 0x9c, 0x60, 0x1a, 0xcb, 0x98, 0x5e, 0x98 } }; + + //! Razer Naga device. + // {F1876328-6CA4-46AE-BE04-BE812B414433} + static const GUID NAGA_CHROMA = + { 0xf1876328, 0x6ca4, 0x46ae,{ 0xbe, 0x4, 0xbe, 0x81, 0x2b, 0x41, 0x44, 0x33 } }; + + //! Razer Orochi Chroma device. + // {52C15681-4ECE-4DD9-8A52-A1418459EB34} + static const GUID OROCHI_CHROMA = + { 0x52c15681, 0x4ece, 0x4dd9,{ 0x8a, 0x52, 0xa1, 0x41, 0x84, 0x59, 0xeb, 0x34 } }; + + //! Razer Naga Hex Chroma device. + // {195D70F5-F285-4CFF-99F2-B8C0E9658DB4} + static const GUID NAGA_HEX_CHROMA = + { 0x195d70f5, 0xf285, 0x4cff,{ 0x99, 0xf2, 0xb8, 0xc0, 0xe9, 0x65, 0x8d, 0xb4 } }; + + + // Headsets + //! Razer Kraken 7.1 Chroma device. + // {CD1E09A5-D5E6-4A6C-A93B-E6D9BF1D2092} + static const GUID KRAKEN71_CHROMA = + { 0xcd1e09a5, 0xd5e6, 0x4a6c,{ 0xa9, 0x3b, 0xe6, 0xd9, 0xbf, 0x1d, 0x20, 0x92 } }; + + //! Razer ManO'War device. + // {DF3164D7-5408-4A0E-8A7F-A7412F26BEBF} + static const GUID MANOWAR_HEADSET = + { 0xdf3164d7, 0x5408, 0x4a0e,{ 0x8a, 0x7f, 0xa7, 0x41, 0x2f, 0x26, 0xbe, 0xbf } }; + + + // Mouse mat + //! Razer Firefly device. + // {80F95A94-73D2-48CA-AE9A-0986789A9AF2} + static const GUID FIREFLY_CHROMA = + { 0x80f95a94, 0x73d2, 0x48ca,{ 0xae, 0x9a, 0x9, 0x86, 0x78, 0x9a, 0x9a, 0xf2 } }; + + + // Keypads + //! Razer Tartarus device. + // {00F0545C-E180-4AD1-8E8A-419061CE505E} + static const GUID TARTARUS_CHROMA = + { 0xf0545c, 0xe180, 0x4ad1,{ 0x8e, 0x8a, 0x41, 0x90, 0x61, 0xce, 0x50, 0x5e } }; + + //! Razer Orbweaver device. + // {9D24B0AB-0162-466C-9640-7A924AA4D9FD} + static const GUID ORBWEAVER_CHROMA = + { 0x9d24b0ab, 0x162, 0x466c,{ 0x96, 0x40, 0x7a, 0x92, 0x4a, 0xa4, 0xd9, 0xfd } }; + + + // Systems + // {35F6F18D-1AE5-436C-A575-AB44A127903A} + static const GUID LENOVO_Y900 = + { 0x35f6f18d, 0x1ae5, 0x436c,{ 0xa5, 0x75, 0xab, 0x44, 0xa1, 0x27, 0x90, 0x3a } }; + + // {47DB1FA7-6B9B-4EE6-B6F4-4071A3B2053B} + static const GUID LENOVO_Y27 = + { 0x47db1fa7, 0x6b9b, 0x4ee6,{ 0xb6, 0xf4, 0x40, 0x71, 0xa3, 0xb2, 0x5, 0x3b } }; + + + // Accessories + // {0201203B-62F3-4C50-83DD-598BABD208E0} + static const GUID CORE_CHROMA = + { 0x201203b, 0x62f3, 0x4c50,{ 0x83, 0xdd, 0x59, 0x8b, 0xab, 0xd2, 0x8, 0xe0 } }; + + +} + +#endif diff --git a/Artemis/Razer2Artemis/RzChromaSDKTypes.h b/Artemis/Razer2Artemis/RzChromaSDKTypes.h new file mode 100644 index 000000000..ca8c60e99 --- /dev/null +++ b/Artemis/Razer2Artemis/RzChromaSDKTypes.h @@ -0,0 +1,787 @@ +#include + +//! \file RzChromaSDKTypes.h +//! \brief Data types. + +#ifndef _RZCHROMASDKTYPES_H_ +#define _RZCHROMASDKTYPES_H_ + +#pragma once + +typedef LONG RZRESULT; //!< Return result. +typedef GUID RZEFFECTID; //!< Effect Id. +typedef GUID RZDEVICEID; //!< Device Id. +typedef unsigned int RZDURATION; //!< Milliseconds. +typedef size_t RZSIZE; //!< Size. +typedef void* PRZPARAM; //!< Context sensitive pointer. +typedef DWORD RZID; //!< Generic data type for Identifier. +typedef DWORD RZCOLOR; //!< Color data. 1st byte = Red; 2nd byte = Green; 3rd byte = Blue; 4th byte = Alpha (if applicable) + +namespace ChromaSDK +{ + //! Event notification Window message + const UINT WM_CHROMA_EVENT = WM_APP + 0x2000; + + //! Chroma generic effects. Note: Not all devices supported the listed effects. + typedef enum EFFECT_TYPE + { + CHROMA_NONE = 0, //!< No effect. + CHROMA_WAVE, //!< Wave effect. + CHROMA_SPECTRUMCYCLING, //!< Spectrum cycling effect. + CHROMA_BREATHING, //!< Breathing effect. + CHROMA_BLINKING, //!< Blinking effect. + CHROMA_REACTIVE, //!< Reactive effect. + CHROMA_STATIC, //!< Static effect. + CHROMA_CUSTOM, //!< Custom effect. For mice, please see Mouse::CHROMA_CUSTOM2. + CHROMA_STARLIGHT, //!< TODO + CHROMA_INVALID //!< Invalid effect. + } EFFECT_TYPE; + + //! Device info. + typedef struct DEVICE_INFO_TYPE + { + //! Device types. + enum DeviceType + { + DEVICE_KEYBOARD = 1, //!< Keyboard device. + DEVICE_MOUSE = 2, //!< Mouse device. + DEVICE_HEADSET = 3, //!< Headset device. + DEVICE_MOUSEPAD = 4, //!< Mousepad device. + DEVICE_KEYPAD = 5, //!< Keypad device. + DEVICE_SYSTEM = 6, //!< System device. + DEVICE_INVALID //!< Invalid device. + } DeviceType; + + DWORD Connected; //!< Number of devices connected. + } DEVICE_INFO_TYPE; + + const RZSIZE MAX_ROW = 30; //!< Maximum rows for custom effects. + const RZSIZE MAX_COLUMN = 30; //!< Maximum columns for custom effects. + + //! Blinking effect. + typedef struct BLINKING_EFFECT_TYPE + { + RZSIZE Size; //!< Size of the structure. Size = sizeof(BLINKING_EFFECT_TYPE) + DWORD Param; //!< Extra parameters. + + COLORREF Color; //!< Blinking color + } BLINKING_EFFECT_TYPE; + + //! Breathing effect. + typedef struct BREATHING_EFFECT_TYPE + { + RZSIZE Size; //!< Size of ths structure. Size = sizeof(BREATHING_EFFECT_TYPE) + DWORD Param; //!< Extra parameters. + + //! Breathing effect types. + enum _Type + { + ONE_COLOR = 1, //!< 1 color (Only fill Color1). + TWO_COLORS, //!< 2 colors. + RANDOM_COLORS //!< Random colors + } Type; + + COLORREF Color1; //!< First color. + COLORREF Color2; //!< Second color. + } BREATHING_EFFECT_TYPE; + + //! Custom effect. + typedef struct CUSTOM_EFFECT_TYPE + { + RZSIZE Size; //!< Size of the structure. Size = sizeof(CUSTOM_EFFECT_TYPE) + DWORD Param; //!< Extra parameters. + + RZCOLOR Color[MAX_ROW][MAX_COLUMN]; + } CUSTOM_EFFECT_TYPE; + + //! No effect. + typedef struct NO_EFFECT_TYPE + { + RZSIZE Size; //!< Size of the structure. Size = sizeof(NO_EFFECT_TYPE) + DWORD Param; //!< Extra parameters. + } NO_EFFECT_TYPE; + + //! Reactive effect. + typedef struct REACTIVE_EFFECT_TYPE + { + RZSIZE Size; //!< Size of the structure. Size = sizeof(REACTIVE_EFFECT_TYPE) + DWORD Param; //!< Extra parameters. + + //! Duration of the effect. + enum _Duration + { + DURATION_SHORT = 1, //!< Short duration. + DURATION_MEDIUM, //!< Medium duration. + DURATION_LONG //!< Long duration. + } Duration; //!< The time taken for the effect to fade away. + + COLORREF Color; //!< Color of the effect. + } REACTIVE_EFFECT_TYPE; + + //! Spectrum cycling effect. + typedef struct SPECTRUMCYCLING_EFFECT_TYPE + { + RZSIZE Size; //!< Size of the structure. Size = sizeof(SPECTRUMCYCLING_EFFECT_TYPE) + DWORD Param; //!< Extra parameters. + } SPECTRUMCYCLING_EFFECT_TYPE; + + //! Starlight effect. + typedef struct STARLIGHT_EFFECT_TYPE + { + RZSIZE Size; //!< Size of the structure. Size = sizeof(SPECTRUMCYCLING_EFFECT_TYPE) + DWORD Param; //!< Extra parameters. + + //! Starlight effect types. + enum _Type + { + TWO_COLORS = 1, //!< 2 colors. + RANDOM_COLORS //!< Random colors + } Type; + + COLORREF Color1; //!< First color. + COLORREF Color2; //!< Second color. + + //! Duration of the effect. + enum _Duration + { + DURATION_SHORT = 1, //!< Short duration. + DURATION_MEDIUM, //!< Medium duration. + DURATION_LONG //!< Long duration. + } Duration; //!< The time taken for the effect to fade away. + + } STARLIGHT_EFFECT_TYPE; + + //! Static effect. + typedef struct STATIC_EFFECT_TYPE + { + RZSIZE Size; //!< Size of the structure. Size = sizeof(STATIC_EFFECT_TYPE) + DWORD Param; //!< Extra parameters. + + COLORREF Color; //!< Color of the effect. + } STATIC_EFFECT_TYPE; + + //! Wave effect. + typedef struct WAVE_EFFECT_TYPE + { + RZSIZE Size; //!< Size of the structure. Size = sizeof(WAVE_EFFECT_TYPE) + DWORD Param; //!< Extra parameters. + + //! Direction of effect. + enum _Direction + { + DIRECTION_LEFT_TO_RIGHT = 1, //!< Left to right. + DIRECTION_RIGHT_TO_LEFT, //!< Right to left. + DIRECTION_FRONT_TO_BACK, //!< Front to back + DIRECTION_BACK_TO_FRONT //!< Back top front + } Direction; + } WAVE_EFFECT_TYPE; + + //! Keyboards + namespace Keyboard + { + //! Definitions of keys. + typedef enum RZKEY + { + RZKEY_ESC = 0x0001, /*!< Esc (VK_ESCAPE) */ + RZKEY_F1 = 0x0003, /*!< F1 (VK_F1) */ + RZKEY_F2 = 0x0004, /*!< F2 (VK_F2) */ + RZKEY_F3 = 0x0005, /*!< F3 (VK_F3) */ + RZKEY_F4 = 0x0006, /*!< F4 (VK_F4) */ + RZKEY_F5 = 0x0007, /*!< F5 (VK_F5) */ + RZKEY_F6 = 0x0008, /*!< F6 (VK_F6) */ + RZKEY_F7 = 0x0009, /*!< F7 (VK_F7) */ + RZKEY_F8 = 0x000A, /*!< F8 (VK_F8) */ + RZKEY_F9 = 0x000B, /*!< F9 (VK_F9) */ + RZKEY_F10 = 0x000C, /*!< F10 (VK_F10) */ + RZKEY_F11 = 0x000D, /*!< F11 (VK_F11) */ + RZKEY_F12 = 0x000E, /*!< F12 (VK_F12) */ + RZKEY_1 = 0x0102, /*!< 1 (VK_1) */ + RZKEY_2 = 0x0103, /*!< 2 (VK_2) */ + RZKEY_3 = 0x0104, /*!< 3 (VK_3) */ + RZKEY_4 = 0x0105, /*!< 4 (VK_4) */ + RZKEY_5 = 0x0106, /*!< 5 (VK_5) */ + RZKEY_6 = 0x0107, /*!< 6 (VK_6) */ + RZKEY_7 = 0x0108, /*!< 7 (VK_7) */ + RZKEY_8 = 0x0109, /*!< 8 (VK_8) */ + RZKEY_9 = 0x010A, /*!< 9 (VK_9) */ + RZKEY_0 = 0x010B, /*!< 0 (VK_0) */ + RZKEY_A = 0x0302, /*!< A (VK_A) */ + RZKEY_B = 0x0407, /*!< B (VK_B) */ + RZKEY_C = 0x0405, /*!< C (VK_C) */ + RZKEY_D = 0x0304, /*!< D (VK_D) */ + RZKEY_E = 0x0204, /*!< E (VK_E) */ + RZKEY_F = 0x0305, /*!< F (VK_F) */ + RZKEY_G = 0x0306, /*!< G (VK_G) */ + RZKEY_H = 0x0307, /*!< H (VK_H) */ + RZKEY_I = 0x0209, /*!< I (VK_I) */ + RZKEY_J = 0x0308, /*!< J (VK_J) */ + RZKEY_K = 0x0309, /*!< K (VK_K) */ + RZKEY_L = 0x030A, /*!< L (VK_L) */ + RZKEY_M = 0x0409, /*!< M (VK_M) */ + RZKEY_N = 0x0408, /*!< N (VK_N) */ + RZKEY_O = 0x020A, /*!< O (VK_O) */ + RZKEY_P = 0x020B, /*!< P (VK_P) */ + RZKEY_Q = 0x0202, /*!< Q (VK_Q) */ + RZKEY_R = 0x0205, /*!< R (VK_R) */ + RZKEY_S = 0x0303, /*!< S (VK_S) */ + RZKEY_T = 0x0206, /*!< T (VK_T) */ + RZKEY_U = 0x0208, /*!< U (VK_U) */ + RZKEY_V = 0x0406, /*!< V (VK_V) */ + RZKEY_W = 0x0203, /*!< W (VK_W) */ + RZKEY_X = 0x0404, /*!< X (VK_X) */ + RZKEY_Y = 0x0207, /*!< Y (VK_Y) */ + RZKEY_Z = 0x0403, /*!< Z (VK_Z) */ + RZKEY_NUMLOCK = 0x0112, /*!< Numlock (VK_NUMLOCK) */ + RZKEY_NUMPAD0 = 0x0513, /*!< Numpad 0 (VK_NUMPAD0) */ + RZKEY_NUMPAD1 = 0x0412, /*!< Numpad 1 (VK_NUMPAD1) */ + RZKEY_NUMPAD2 = 0x0413, /*!< Numpad 2 (VK_NUMPAD2) */ + RZKEY_NUMPAD3 = 0x0414, /*!< Numpad 3 (VK_NUMPAD3) */ + RZKEY_NUMPAD4 = 0x0312, /*!< Numpad 4 (VK_NUMPAD4) */ + RZKEY_NUMPAD5 = 0x0313, /*!< Numpad 5 (VK_NUMPAD5) */ + RZKEY_NUMPAD6 = 0x0314, /*!< Numpad 6 (VK_NUMPAD6) */ + RZKEY_NUMPAD7 = 0x0212, /*!< Numpad 7 (VK_NUMPAD7) */ + RZKEY_NUMPAD8 = 0x0213, /*!< Numpad 8 (VK_NUMPAD8) */ + RZKEY_NUMPAD9 = 0x0214, /*!< Numpad 9 (VK_ NUMPAD9*/ + RZKEY_NUMPAD_DIVIDE = 0x0113, /*!< Divide (VK_DIVIDE) */ + RZKEY_NUMPAD_MULTIPLY = 0x0114, /*!< Multiply (VK_MULTIPLY) */ + RZKEY_NUMPAD_SUBTRACT = 0x0115, /*!< Subtract (VK_SUBTRACT) */ + RZKEY_NUMPAD_ADD = 0x0215, /*!< Add (VK_ADD) */ + RZKEY_NUMPAD_ENTER = 0x0415, /*!< Enter (VK_RETURN - Extended) */ + RZKEY_NUMPAD_DECIMAL = 0x0514, /*!< Decimal (VK_DECIMAL) */ + RZKEY_PRINTSCREEN = 0x000F, /*!< Print Screen (VK_PRINT) */ + RZKEY_SCROLL = 0x0010, /*!< Scroll Lock (VK_SCROLL) */ + RZKEY_PAUSE = 0x0011, /*!< Pause (VK_PAUSE) */ + RZKEY_INSERT = 0x010F, /*!< Insert (VK_INSERT) */ + RZKEY_HOME = 0x0110, /*!< Home (VK_HOME) */ + RZKEY_PAGEUP = 0x0111, /*!< Page Up (VK_PRIOR) */ + RZKEY_DELETE = 0x020f, /*!< Delete (VK_DELETE) */ + RZKEY_END = 0x0210, /*!< End (VK_END) */ + RZKEY_PAGEDOWN = 0x0211, /*!< Page Down (VK_NEXT) */ + RZKEY_UP = 0x0410, /*!< Up (VK_UP) */ + RZKEY_LEFT = 0x050F, /*!< Left (VK_LEFT) */ + RZKEY_DOWN = 0x0510, /*!< Down (VK_DOWN) */ + RZKEY_RIGHT = 0x0511, /*!< Right (VK_RIGHT) */ + RZKEY_TAB = 0x0201, /*!< Tab (VK_TAB) */ + RZKEY_CAPSLOCK = 0x0301, /*!< Caps Lock(VK_CAPITAL) */ + RZKEY_BACKSPACE = 0x010E, /*!< Backspace (VK_BACK) */ + RZKEY_ENTER = 0x030E, /*!< Enter (VK_RETURN) */ + RZKEY_LCTRL = 0x0501, /*!< Left Control(VK_LCONTROL) */ + RZKEY_LWIN = 0x0502, /*!< Left Window (VK_LWIN) */ + RZKEY_LALT = 0x0503, /*!< Left Alt (VK_LMENU) */ + RZKEY_SPACE = 0x0507, /*!< Spacebar (VK_SPACE) */ + RZKEY_RALT = 0x050B, /*!< Right Alt (VK_RMENU) */ + RZKEY_FN = 0x050C, /*!< Function key. */ + RZKEY_RMENU = 0x050D, /*!< Right Menu (VK_APPS) */ + RZKEY_RCTRL = 0x050E, /*!< Right Control (VK_RCONTROL) */ + RZKEY_LSHIFT = 0x0401, /*!< Left Shift (VK_LSHIFT) */ + RZKEY_RSHIFT = 0x040E, /*!< Right Shift (VK_RSHIFT) */ + RZKEY_MACRO1 = 0x0100, /*!< Macro Key 1 */ + RZKEY_MACRO2 = 0x0200, /*!< Macro Key 2 */ + RZKEY_MACRO3 = 0x0300, /*!< Macro Key 3 */ + RZKEY_MACRO4 = 0x0400, /*!< Macro Key 4 */ + RZKEY_MACRO5 = 0x0500, /*!< Macro Key 5 */ + RZKEY_OEM_1 = 0x0101, /*!< ~ (tilde/半角/全角) (VK_OEM_3) */ + RZKEY_OEM_2 = 0x010C, /*!< -- (minus) (VK_OEM_MINUS) */ + RZKEY_OEM_3 = 0x010D, /*!< = (equal) (VK_OEM_PLUS) */ + RZKEY_OEM_4 = 0x020C, /*!< [ (left sqaure bracket) (VK_OEM_4) */ + RZKEY_OEM_5 = 0x020D, /*!< ] (right square bracket) (VK_OEM_6) */ + RZKEY_OEM_6 = 0x020E, /*!< \ (backslash) (VK_OEM_5) */ + RZKEY_OEM_7 = 0x030B, /*!< ; (semi-colon) (VK_OEM_1) */ + RZKEY_OEM_8 = 0x030C, /*!< ' (apostrophe) (VK_OEM_7) */ + RZKEY_OEM_9 = 0x040A, /*!< , (comma) (VK_OEM_COMMA) */ + RZKEY_OEM_10 = 0x040B, /*!< . (period) (VK_OEM_PERIOD) */ + RZKEY_OEM_11 = 0x040C, /*!< / (forward slash) (VK_OEM_2) */ + RZKEY_EUR_1 = 0x030D, /*!< "#" (VK_OEM_5) */ + RZKEY_EUR_2 = 0x0402, /*!< \ (VK_OEM_102) */ + RZKEY_JPN_1 = 0x0015, /*!< ¥ (0xFF) */ + RZKEY_JPN_2 = 0x040D, /*!< \ (0xC1) */ + RZKEY_JPN_3 = 0x0504, /*!< 無変換 (VK_OEM_PA1) */ + RZKEY_JPN_4 = 0x0509, /*!< 変換 (0xFF) */ + RZKEY_JPN_5 = 0x050A, /*!< ひらがな/カタカナ (0xFF) */ + RZKEY_KOR_1 = 0x0015, /*!< | (0xFF) */ + RZKEY_KOR_2 = 0x030D, /*!< (VK_OEM_5) */ + RZKEY_KOR_3 = 0x0402, /*!< (VK_OEM_102) */ + RZKEY_KOR_4 = 0x040D, /*!< (0xC1) */ + RZKEY_KOR_5 = 0x0504, /*!< (VK_OEM_PA1) */ + RZKEY_KOR_6 = 0x0509, /*!< 한/영 (0xFF) */ + RZKEY_KOR_7 = 0x050A, /*!< (0xFF) */ + RZKEY_INVALID = 0xFFFF /*!< Invalid keys. */ + } RZKEY; + + //! Definition of LEDs. + typedef enum RZLED + { + RZLED_LOGO = 0x0014 /*!< Razer logo */ + } RZLED; + + //! Maximum number of rows in a keyboard. + const RZSIZE MAX_ROW = 6; + + //! Maximum number of columns in a keyboard. + const RZSIZE MAX_COLUMN = 22; + + //! Maximum number of keys. + const RZSIZE MAX_KEYS = MAX_ROW * MAX_COLUMN; + + //! Maximum number of custom effects. + const RZSIZE MAX_CUSTOM_EFFECTS = MAX_KEYS; + + //! Keyboard LED layout. + const COLORREF RZKEY_LAYOUT[MAX_ROW][MAX_COLUMN] = {}; + + //! Chroma keyboard effect types + typedef enum EFFECT_TYPE + { + CHROMA_NONE = 0, //!< No effect. + CHROMA_BREATHING, //!< Breathing effect. + CHROMA_CUSTOM, //!< Custom effect. + CHROMA_REACTIVE, //!< Reactive effect. + CHROMA_STATIC, //!< Static effect. + CHROMA_SPECTRUMCYCLING, //!< Spectrum cycling effect. + CHROMA_WAVE, //!< Wave effect. + CHROMA_STARLIGHT, //!< Starlight effect. + CHROMA_CUSTOM_KEY, //!< Custom effects with keys. + CHROMA_INVALID //!< Invalid effect. + } EFFECT_TYPE; + + // Chroma keyboard effects + //! Breathing effect type + typedef struct BREATHING_EFFECT_TYPE + { + //! Breathing effects. + enum Type + { + TWO_COLORS = 1, //!< 2 colors + RANDOM_COLORS, //!< Random colors + INVALID //!< Invalid type + } Type; + COLORREF Color1; //!< First color. + COLORREF Color2; //!< Second color. + } BREATHING_EFFECT_TYPE; + + //! Custom effect using a matrix type. + typedef struct CUSTOM_EFFECT_TYPE + { + COLORREF Color[MAX_ROW][MAX_COLUMN]; //!< Grid layout. 6 rows by 22 columns. + } CUSTOM_EFFECT_TYPE; + + //! Custom effect with keys. + typedef struct CUSTOM_KEY_EFFECT_TYPE + { + COLORREF Color[MAX_ROW][MAX_COLUMN]; //!< Grid layout. 6 rows by 22 columns. + COLORREF Key[MAX_ROW][MAX_COLUMN]; //!< Keys information. 6 rows by 22 columns. To indidate there is a key effect, OR with 0x01000000. i.e. Key[0][1] = 0x01000000 | Color; + } CUSTOM_KEY_EFFECT_TYPE; + + //! Reactive effect type + typedef struct REACTIVE_EFFECT_TYPE + { + //! Duration of the effect. + enum Duration + { + DURATION_NONE = 0, //!< No duration. + DURATION_SHORT, //!< Short duration. + DURATION_MEDIUM, //!< Medium duration. + DURATION_LONG, //!< Long duration. + DURATION_INVALID //!< Invalid duration. + } Duration; //!< The time taken for the effect to fade away. + + COLORREF Color; //!< Color of the effect + } REACTIVE_EFFECT_TYPE; + + //! Starlight effect. + typedef struct STARLIGHT_EFFECT_TYPE + { + //! Starlight effect types. + enum _Type + { + TWO_COLORS = 1, //!< 2 colors. + RANDOM_COLORS //!< Random colors + } Type; + + COLORREF Color1; //!< First color. + COLORREF Color2; //!< Second color. + + //! Duration of the effect. + enum _Duration + { + DURATION_SHORT = 1, //!< Short duration. + DURATION_MEDIUM, //!< Medium duration. + DURATION_LONG //!< Long duration. + } Duration; //!< The time taken for the effect to fade away. + + } STARLIGHT_EFFECT_TYPE; + + //! Static effect type + typedef struct STATIC_EFFECT_TYPE + { + COLORREF Color; //!< Color of the effect + } STATIC_EFFECT_TYPE; + + //! Wave effect type + typedef struct WAVE_EFFECT_TYPE + { + //! Direction of the wave effect. + enum Direction + { + DIRECTION_NONE = 0, //!< No direction. + DIRECTION_LEFT_TO_RIGHT, //!< Left to right. + DIRECTION_RIGHT_TO_LEFT, //!< Right to left. + DIRECTION_INVALID //!< Invalid direction. + } Direction; //!< Direction of the wave. + } WAVE_EFFECT_TYPE; + } + + //! Mice + namespace Mouse + { + //! Maximum number of custom LEDs (old definition to maintain backward compatibility). + const RZSIZE MAX_LEDS = 30; + + //! Mice LED layout (old definition to maintain backward compatibility). + const RZCOLOR RZLED_LAYOUT[MAX_LEDS] = {}; + + //! Maximum number of rows of the virtual grid. + const RZSIZE MAX_ROW = 9; + + //! Maximum number of columns of the virtual grid. + const RZSIZE MAX_COLUMN = 7; + + //! Maximum number of LEDs of the virtual grid. + const RZSIZE MAX_LEDS2 = MAX_ROW * MAX_COLUMN; + + //! Mice LED virtual grid layout. + const RZCOLOR RZLED_LAYOUT2[MAX_ROW][MAX_COLUMN] = {}; + + //! Mouse LED Id defintion (old definition to maintain backward compatibility). + typedef enum RZLED + { + RZLED_NONE = 0, //!< No LED. + RZLED_SCROLLWHEEL = 1, //!< Scroll Wheel LED. + RZLED_LOGO = 2, //!< Logo LED. + RZLED_BACKLIGHT = 3, //!< Backlight or numpad. + RZLED_SIDE_STRIP1 = 4, //!< Side strip LED 1. (For Mamba TE, starts from top left hand) + RZLED_SIDE_STRIP2 = 5, //!< Side strip LED 2. (For Mamba TE) + RZLED_SIDE_STRIP3 = 6, //!< Side strip LED 3. (For Mamba TE) + RZLED_SIDE_STRIP4 = 7, //!< Side strip LED 4. (For Mamba TE) + RZLED_SIDE_STRIP5 = 8, //!< Side strip LED 5. (For Mamba TE) + RZLED_SIDE_STRIP6 = 9, //!< Side strip LED 6. (For Mamba TE) + RZLED_SIDE_STRIP7 = 10, //!< Side strip LED 7. (For Mamba TE) + RZLED_SIDE_STRIP8 = 11, //!< Side strip LED 8. (For Mamba TE) + RZLED_SIDE_STRIP9 = 12, //!< Side strip LED 9. (For Mamba TE) + RZLED_SIDE_STRIP10 = 13, //!< Side strip LED 10. (For Mamba TE) + RZLED_SIDE_STRIP11 = 14, //!< Side strip LED 11. (For Mamba TE) + RZLED_SIDE_STRIP12 = 15, //!< Side strip LED 12. (For Mamba TE) + RZLED_SIDE_STRIP13 = 16, //!< Side strip LED 13. (For Mamba TE) + RZLED_SIDE_STRIP14 = 17, //!< Side strip LED 14. (For Mamba TE) + RZLED_ALL = 0xFFFF + } RZLED; + + //! Mouse LED Id defintion for the virtual grid. + typedef enum RZLED2 + { + RZLED2_SCROLLWHEEL = 0x0203, //!< Scroll Wheel LED. + RZLED2_LOGO = 0x0703, //!< Logo LED. + RZLED2_BACKLIGHT = 0x0403, //!< Backlight LED. + RZLED2_LEFT_SIDE1 = 0x0100, //!< Left LED 1. + RZLED2_LEFT_SIDE2 = 0x0200, //!< Left LED 2. + RZLED2_LEFT_SIDE3 = 0x0300, //!< Left LED 3. + RZLED2_LEFT_SIDE4 = 0x0400, //!< Left LED 4. + RZLED2_LEFT_SIDE5 = 0x0500, //!< Left LED 5. + RZLED2_LEFT_SIDE6 = 0x0600, //!< Left LED 6. + RZLED2_LEFT_SIDE7 = 0x0700, //!< Left LED 7. + RZLED2_BOTTOM1 = 0x0801, //!< Bottom LED 1. + RZLED2_BOTTOM2 = 0x0802, //!< Bottom LED 2. + RZLED2_BOTTOM3 = 0x0803, //!< Bottom LED 3. + RZLED2_BOTTOM4 = 0x0804, //!< Bottom LED 4. + RZLED2_BOTTOM5 = 0x0805, //!< Bottom LED 5. + RZLED2_RIGHT_SIDE1 = 0x0106, //!< Right LED 1. + RZLED2_RIGHT_SIDE2 = 0x0206, //!< Right LED 2. + RZLED2_RIGHT_SIDE3 = 0x0306, //!< Right LED 3. + RZLED2_RIGHT_SIDE4 = 0x0406, //!< Right LED 4. + RZLED2_RIGHT_SIDE5 = 0x0506, //!< Right LED 5. + RZLED2_RIGHT_SIDE6 = 0x0606, //!< Right LED 6. + RZLED2_RIGHT_SIDE7 = 0x0706 //!< Right LED 7. + } RZLED2; + + //! Chroma mouse effect types + typedef enum EFFECT_TYPE + { + CHROMA_NONE = 0, //!< No effect. + CHROMA_BLINKING, //!< Blinking effect. + CHROMA_BREATHING, //!< Breathing effect. + CHROMA_CUSTOM, //!< Custom effect (old definition to maintain backward compatibility). + CHROMA_REACTIVE, //!< Reactive effect. + CHROMA_SPECTRUMCYCLING, //!< Spectrum cycling effect. + CHROMA_STATIC, //!< Static effect. + CHROMA_WAVE, //!< Wave effect. + CHROMA_CUSTOM2, //!< Custom effects using a virtual grid. + CHROMA_INVALID //!< Invalid effect. + } EFFECT_TYPE; + + //! Static effect type + typedef struct STATIC_EFFECT_TYPE + { + RZLED LEDId; //!< LED Id + COLORREF Color; //!< Color of the effect. + } STATIC_EFFECT_TYPE; + + //! Blinking effect type. + typedef struct BLINKING_EFFECT_TYPE + { + RZLED LEDId; //!< LED Id + COLORREF Color; //!< Color. + } BLINKING_EFFECT_TYPE; + + //! Breathing effect. + typedef struct BREATHING_EFFECT_TYPE + { + RZLED LEDId; //!< LED Id + + //! Breathing type. + enum Type + { + ONE_COLOR = 1, //!< 1 color (Only fill Color1). + TWO_COLORS, //!< 2 colors. + RANDOM_COLORS, //!< Random colors + INVALID //!< Invalid type + } Type; + + COLORREF Color1; //!< First color. + COLORREF Color2; //!< Second color. + } BREATHING_EFFECT_TYPE; + + //! Custom effect. + typedef struct CUSTOM_EFFECT_TYPE + { + RZCOLOR Color[MAX_LEDS]; //!< Array of colors. + } CUSTOM_EFFECT_TYPE; + + //! Custom effect using virtual grid. + //! Indexes of the LED are defined in RZLED2.i.e. Row = HIBYTE(RZLED2_SCROLLWHEEL), Column = LOBYTE(RZLED2_SCROLLWHEEL) + typedef struct CUSTOM_EFFECT_TYPE2 + { + RZCOLOR Color[MAX_ROW][MAX_COLUMN]; //!< Array of colors. + } CUSTOM_EFFECT_TYPE2; + + //! Reactive effect. + typedef struct REACTIVE_EFFECT_TYPE + { + RZLED LEDId; //!< LED Id + + //! Duration of the effect. + enum Duration + { + DURATION_NONE = 0, //!< No duration. + DURATION_SHORT, //!< Short duration. + DURATION_MEDIUM, //!< Medium duration. + DURATION_LONG //!< Long duration. + } Duration; + + RZCOLOR Color; //!< Color of the effect. + } REACTIVE_EFFECT_TYPE; + + //! No effect. + typedef struct NO_EFFECT_TYPE + { + RZLED LEDId; //!< LED Id + } NO_EFFECT_TYPE; + + //! Spectrum cycling. + typedef struct SPECTRUMCYCLING_EFFECT_TYPE + { + RZLED LEDId; //!< LED id. + } SPECTRUMCYCLING_EFFECT_TYPE; + + //! Wave effect. + typedef struct WAVE_EFFECT_TYPE + { + //! Direction of the wave effect. + enum Direction + { + FRONT_TO_BACK, //!< Front to back + BACK_TO_FRONT //!< Back to front + } Direction; + } WAVE_EFFECT_TYPE; + } + + //! Headsets + namespace Headset + { + //! Maximum number of LEDs + const RZSIZE MAX_LEDS = 5; + + //! Chroma headset effect types + typedef enum EFFECT_TYPE + { + CHROMA_NONE = 0, //!< No effect. + CHROMA_STATIC, //!< Static effect. + CHROMA_BREATHING, //!< Breathing effect. + CHROMA_SPECTRUMCYCLING, //!< Spectrum cycling effect. + CHROMA_CUSTOM, //!< Custom effects. + CHROMA_INVALID //!< Invalid effect. + } EFFECT_TYPE; + + //! Static effect type + typedef struct STATIC_EFFECT_TYPE + { + COLORREF Color; //!< Color of the effect. + } STATIC_EFFECT_TYPE; + + //! Breathing effect type. + typedef struct BREATHING_EFFECT_TYPE + { + COLORREF Color; //!< Color. + } BREATHING_EFFECT_TYPE; + + //! Custom effect type. + typedef struct CUSTOM_EFFECT_TYPE + { + RZCOLOR Color[MAX_LEDS]; //!< Array of colors. + } CUSTOM_EFFECT_TYPE; + } + + //! Mousepads + namespace Mousepad + { + //! Maximum number of LEDs + const RZSIZE MAX_LEDS = 15; + + //! Chroma mousepad effect types + typedef enum EFFECT_TYPE + { + CHROMA_NONE = 0, //!< No effect. + CHROMA_BREATHING, //!< Breathing effect. + CHROMA_CUSTOM, //!< Custom effect. + CHROMA_SPECTRUMCYCLING, //!< Spectrum cycling effect. + CHROMA_STATIC, //!< Static effect. + CHROMA_WAVE, //!< Wave effect. + CHROMA_INVALID //!< Invalid effect. + } EFFECT_TYPE; + + // Chroma mousepad effects + //! Breathing effect type. + typedef struct BREATHING_EFFECT_TYPE + { + //! Breathing effects. + enum Type + { + TWO_COLORS = 1, //!< 2 colors + RANDOM_COLORS, //!< Random colors + INVALID + } Type; + COLORREF Color1; //!< First color. + COLORREF Color2; //!< Second color. + } BREATHING_EFFECT_TYPE; + + //! Custom effect type. + typedef struct CUSTOM_EFFECT_TYPE + { + RZCOLOR Color[MAX_LEDS]; //!< An array of colors for all the sides of the mousepad. First LED starts from top-right corner. + //!< LED 0-4 right side, 5-9 bottom side, 10-14 left side. + } CUSTOM_EFFECT_TYPE; + + //! Static effect type + typedef struct STATIC_EFFECT_TYPE + { + COLORREF Color; //!< Color of the effect + } STATIC_EFFECT_TYPE; + + //! Wave effect type + typedef struct WAVE_EFFECT_TYPE + { + //! Direction of the wave effect. + enum Direction + { + DIRECTION_NONE = 0, //!< No direction. + DIRECTION_LEFT_TO_RIGHT, //!< Left to right. + DIRECTION_RIGHT_TO_LEFT, //!< Right to left. + DIRECTION_INVALID //!< Invalid direction. + } Direction; //!< Direction of the wave. + } WAVE_EFFECT_TYPE; + } + + //! Keypads + namespace Keypad + { + //! Maximum number of rows. + const RZSIZE MAX_ROW = 4; + + //! Maximum number of columns. + const RZSIZE MAX_COLUMN = 5; + + //! Total number of keys. + const RZSIZE MAX_KEYS = MAX_ROW * MAX_COLUMN; + + //! Chroma keypad effect types + typedef enum EFFECT_TYPE + { + CHROMA_NONE = 0, //!< No effect. + CHROMA_BREATHING, //!< Breathing effect. + CHROMA_CUSTOM, //!< Custom effect. + CHROMA_REACTIVE, //!< Reactive effect. + CHROMA_SPECTRUMCYCLING, //!< Spectrum cycling effect. + CHROMA_STATIC, //!< Static effect. + CHROMA_WAVE, //!< Wave effect. + CHROMA_INVALID //!< Invalid effect. + } EFFECT_TYPE; + + // Chroma keypad effects + //! Breathing effect type. + typedef struct BREATHING_EFFECT_TYPE + { + //! Breathing effects. + enum Type + { + TWO_COLORS = 1, //!< 2 colors + RANDOM_COLORS, //!< Random colors + INVALID //!< Invalid type + } Type; + COLORREF Color1; //!< First color. + COLORREF Color2; //!< Second color. + } BREATHING_EFFECT_TYPE; + + //! Custom effect type + typedef struct CUSTOM_EFFECT_TYPE + { + RZCOLOR Color[MAX_ROW][MAX_COLUMN]; //!< Custom effect. + //!< For Razer Tartarus Chroma only Color[0] is valid. Use index '0' to change the keypad color. + } CUSTOM_EFFECT_TYPE; + + //! Reactive effect type + typedef struct REACTIVE_EFFECT_TYPE + { + //! Duration of the effect. + enum Duration + { + DURATION_NONE = 0, //!< No duration. + DURATION_SHORT, //!< Short duration. + DURATION_MEDIUM, //!< Medium duration. + DURATION_LONG, //!< Long duration. + DURATION_INVALID //!< Invalid duration. + } Duration; //!< The time taken for the effect to fade away. + + COLORREF Color; //!< Color of the effect + } REACTIVE_EFFECT_TYPE; + + //! Static effect type + typedef struct STATIC_EFFECT_TYPE + { + RZCOLOR Color; //!< Color of the effect. + } STATIC_EFFECT_TYPE; + + //! Wave effect type + typedef struct WAVE_EFFECT_TYPE + { + //! Direction of the wave effect. + enum Direction + { + DIRECTION_NONE = 0, //!< No direction. + DIRECTION_LEFT_TO_RIGHT, //!< Left to right. + DIRECTION_RIGHT_TO_LEFT, //!< Right to left. + DIRECTION_INVALID //!< Invalid direction. + } Direction; //!< Direction of the wave. + } WAVE_EFFECT_TYPE; + } +} + +#endif diff --git a/Artemis/Razer2Artemis/RzErrors.h b/Artemis/Razer2Artemis/RzErrors.h new file mode 100644 index 000000000..6d3f29bdf --- /dev/null +++ b/Artemis/Razer2Artemis/RzErrors.h @@ -0,0 +1,46 @@ + +//! \file RzErrors.h +//! \brief Error codes for Chroma SDK. If the error is not defined here, refer to WinError.h from the Windows SDK. + +#ifndef _RZERRORS_H_ +#define _RZERRORS_H_ + +#pragma once + +// Error codes +//! Invalid +#define RZRESULT_INVALID -1L +//! Success +#define RZRESULT_SUCCESS 0L +//! Access denied +#define RZRESULT_ACCESS_DENIED 5L +//! Invalid handle +#define RZRESULT_INVALID_HANDLE 6L +//! Not supported +#define RZRESULT_NOT_SUPPORTED 50L +//! Invalid parameter. +#define RZRESULT_INVALID_PARAMETER 87L +//! The service has not been started +#define RZRESULT_SERVICE_NOT_ACTIVE 1062L +//! Cannot start more than one instance of the specified program. +#define RZRESULT_SINGLE_INSTANCE_APP 1152L +//! Device not connected +#define RZRESULT_DEVICE_NOT_CONNECTED 1167L +//! Element not found. +#define RZRESULT_NOT_FOUND 1168L +//! Request aborted. +#define RZRESULT_REQUEST_ABORTED 1235L +//! An attempt was made to perform an initialization operation when initialization has already been completed. +#define RZRESULT_ALREADY_INITIALIZED 1247L +//! Resource not available or disabled +#define RZRESULT_RESOURCE_DISABLED 4309L +//! Device not available or supported +#define RZRESULT_DEVICE_NOT_AVAILABLE 4319L +//! The group or resource is not in the correct state to perform the requested operation. +#define RZRESULT_NOT_VALID_STATE 5023L +//! No more items +#define RZRESULT_NO_MORE_ITEMS 259L +//! General failure. +#define RZRESULT_FAILED 2147500037L + +#endif diff --git a/Artemis/Razer2Artemis/main.cpp b/Artemis/Razer2Artemis/main.cpp new file mode 100644 index 000000000..6a6ec9564 --- /dev/null +++ b/Artemis/Razer2Artemis/main.cpp @@ -0,0 +1,157 @@ +// 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 +#define WIN32_LEAN_AND_MEAN +#include +#include "Logger.h" + +#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::Debug); + + // Get the process that loaded the DLL + TCHAR overwatchFind[] = _T("Overwatch"); + TCHAR szPath[MAX_PATH]; + GetModuleFileName(NULL, szPath, MAX_PATH); + + if (_tcscmp(szPath, overwatchFind) != 0) + game = "overwatch"; + + CLogger::OutputLog("Attached to process.", LogLevel::Debug); + } + break; + + case DLL_PROCESS_DETACH: + { + cleanup(); + + CLogger::OutputLog_s("Detached from process.", LogLevel::Debug); + } + break; + } + + return true; +} + +RZRESULT Init() +{ + CLogger::OutputLog_s("Razer Init called.", LogLevel::Debug); + g_hasInitialised = true; + return 0; +} + +RZRESULT UnInit() +{ + CLogger::OutputLog_s("Razer UnInit called.", LogLevel::Debug); + return 0; +} + +RZRESULT CreateEffect(RZDEVICEID DeviceId, ChromaSDK::EFFECT_TYPE Effect, PRZPARAM pParam, RZEFFECTID* pEffectId) +{ + CLogger::OutputLog_s("Razer CreateEffect called.", LogLevel::Debug); + return 0; +} + +RZRESULT CreateKeyboardEffect(ChromaSDK::Keyboard::EFFECT_TYPE Effect, PRZPARAM pParam, RZEFFECTID* pEffectId) +{ + CLogger::OutputLog_s("Razer CreateKeyboardEffect called.", LogLevel::Debug); + return 0; +} + +RZRESULT CreateMouseEffect(ChromaSDK::Mouse::EFFECT_TYPE Effect, PRZPARAM pParam, RZEFFECTID* pEffectId) +{ + CLogger::OutputLog_s("Razer CreateMouseEffect called.", LogLevel::Debug); + return 0; +} + +RZRESULT CreateHeadsetEffect(ChromaSDK::Headset::EFFECT_TYPE Effect, PRZPARAM pParam, RZEFFECTID* pEffectId) +{ + CLogger::OutputLog_s("Razer CreateHeadsetEffect called.", LogLevel::Debug); + return 0; +} + +RZRESULT CreateMousepadEffect(ChromaSDK::Mousepad::EFFECT_TYPE Effect, PRZPARAM pParam, RZEFFECTID* pEffectId) +{ + CLogger::OutputLog_s("Razer CreateMousepadEffect called.", LogLevel::Debug); + return 0; +} + +RZRESULT CreateKeypadEffect(ChromaSDK::Keypad::EFFECT_TYPE Effect, PRZPARAM pParam, RZEFFECTID* pEffectId) +{ + CLogger::OutputLog_s("Razer CreateKeypadEffect called.", LogLevel::Debug); + return 0; +} + +RZRESULT DeleteEffect(RZEFFECTID EffectId) +{ + CLogger::OutputLog_s("Razer DeleteEffect called.", LogLevel::Debug); + return 0; +} + +RZRESULT SetEffect(RZEFFECTID EffectId) +{ + CLogger::OutputLog_s("Razer SetEffect called.", LogLevel::Debug); + return 0; +} + +RZRESULT RegisterEventNotification(HWND hWnd) +{ + CLogger::OutputLog_s("Razer RegisterEventNotification called.", LogLevel::Debug); + return 0; +} + +RZRESULT UnregisterEventNotification() +{ + CLogger::OutputLog_s("Razer UnregisterEventNotification called.", LogLevel::Debug); + return 0; +} + +RZRESULT QueryDevice(RZDEVICEID DeviceId, DEVICE_INFO_TYPE& DeviceInfo) +{ + CLogger::OutputLog_s("Razer QueryDevice called.", LogLevel::Debug); + return 0; +} diff --git a/Artemis/Razer2Artemis/main.h b/Artemis/Razer2Artemis/main.h new file mode 100644 index 000000000..5b2d675fb --- /dev/null +++ b/Artemis/Razer2Artemis/main.h @@ -0,0 +1,48 @@ +#define _RZCHROMASDK_H_ + +#pragma once + +#include "RzChromaSDKTypes.h" + +using namespace ChromaSDK; +using namespace Keyboard; +using namespace Mouse; +using namespace Headset; +using namespace Mousepad; +using namespace Keypad; + +// Exported functions +#ifdef __cplusplus +extern "C" +{ +#endif + + RZRESULT Init(void); + + RZRESULT UnInit(void); + + RZRESULT CreateEffect(RZDEVICEID DeviceId, ChromaSDK::EFFECT_TYPE Effect, PRZPARAM pParam, RZEFFECTID* pEffectId); + + RZRESULT CreateKeyboardEffect(Keyboard::EFFECT_TYPE Effect, PRZPARAM pParam, RZEFFECTID* pEffectId); + + RZRESULT CreateMouseEffect(Mouse::EFFECT_TYPE Effect, PRZPARAM pParam, RZEFFECTID* pEffectId); + + RZRESULT CreateHeadsetEffect(Headset::EFFECT_TYPE Effect, PRZPARAM pParam, RZEFFECTID* pEffectId); + + RZRESULT CreateMousepadEffect(Mousepad::EFFECT_TYPE Effect, PRZPARAM pParam, RZEFFECTID* pEffectId); + + RZRESULT CreateKeypadEffect(Keypad::EFFECT_TYPE Effect, PRZPARAM pParam, RZEFFECTID* pEffectId); + + RZRESULT DeleteEffect(RZEFFECTID EffectId); + + RZRESULT SetEffect(RZEFFECTID EffectId); + + RZRESULT RegisterEventNotification(HWND hWnd); + + RZRESULT UnregisterEventNotification(); + + RZRESULT QueryDevice(RZDEVICEID DeviceId, DEVICE_INFO_TYPE& DeviceInfo); + +#ifdef __cplusplus +} +#endif