using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using NonFormTimer = System.Timers.Timer; using Microsoft.Win32; using Xceed.Wpf.Toolkit; using DS4WinWPF.DS4Forms.ViewModels; namespace DS4WinWPF.DS4Forms { /// /// Interaction logic for RecordBox.xaml /// public partial class RecordBox : UserControl { private RecordBoxViewModel recordBoxVM; public RecordBoxViewModel RecordBoxVM { get => recordBoxVM; } private bool saved; public bool Saved { get => saved; } public event EventHandler Save; public event EventHandler Cancel; private ColorPickerWindow colorDialog; private NonFormTimer ds4 = new NonFormTimer(); public RecordBox(int deviceNum, DS4Windows.DS4ControlSettings controlSettings, bool shift, bool showscan = true) { InitializeComponent(); recordBoxVM = new RecordBoxViewModel(deviceNum, controlSettings, shift); mouseButtonsPanel.Visibility = Visibility.Hidden; extraConPanel.Visibility = Visibility.Hidden; if (!showscan) { useScanCode.Visibility = Visibility.Collapsed; } ds4.Elapsed += Ds4_Tick; ds4.Interval = 10; DataContext = recordBoxVM; SetupLateEvents(); } private void Ds4_Tick(object sender, System.Timers.ElapsedEventArgs e) { recordBoxVM.ProcessDS4Tick(); } private void SetupLateEvents() { macroListBox.SelectionChanged += MacroListBox_SelectionChanged; recordBoxVM.MacroSteps.CollectionChanged += MacroSteps_CollectionChanged; } private void MacroSteps_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add) { Dispatcher.BeginInvoke((Action)(() => { int count = recordBoxVM.MacroSteps.Count; if (count > 0) { macroListBox.ScrollIntoView(recordBoxVM.MacroSteps[count - 1]); } })); } } private void MacroListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (!recordBoxVM.Recording) { if (recordBoxVM.MacroStepIndex >= 0) { MacroStepItem item = recordBoxVM.MacroSteps[recordBoxVM.MacroStepIndex]; recordBtn.Content = $"Record Before {item.Step.Name}"; } else { recordBtn.Content = "Record"; } if (recordBoxVM.EditMacroIndex > -1) { UpdateDataRevertTemplate(); } } } private void MacroListBox_LostFocus(object sender, RoutedEventArgs e) { if (!recordBoxVM.Recording) { recordBtn.Content = "Record"; } } private void SaveBtn_Click(object sender, RoutedEventArgs e) { if (recordBoxVM.EditMacroIndex > -1) { UpdateDataRevertTemplate(); } saved = true; recordBoxVM.ExportMacro(); Save?.Invoke(this, EventArgs.Empty); } private void CancelBtn_Click(object sender, RoutedEventArgs e) { Cancel?.Invoke(this, EventArgs.Empty); } private void RecordBtn_Click(object sender, RoutedEventArgs e) { bool recording = recordBoxVM.Recording = !recordBoxVM.Recording; if (recording) { DS4Windows.Program.rootHub.recordingMacro = true; recordBtn.Content = "Stop"; if (recordBoxVM.MacroStepIndex == -1) { // Don't clear macro steps in RECORD button because nowadays there is a separate CLEAR button. RECORD btn without a selection appends new steps to existing macro sequence //recordBoxVM.MacroSteps.Clear(); } else { recordBoxVM.AppendIndex = recordBoxVM.MacroStepIndex; } mouseButtonsPanel.Visibility = Visibility.Visible; if (recordBoxVM.RecordDelays) { extraConPanel.Visibility = Visibility.Visible; } ds4.Start(); Enable_Controls(false); recordBoxVM.Sw.Restart(); this.Focus(); } else { DS4Windows.Program.rootHub.recordingMacro = false; recordBoxVM.AppendIndex = -1; ds4.Stop(); recordBtn.Content = "Record"; mouseButtonsPanel.Visibility = Visibility.Hidden; extraConPanel.Visibility = Visibility.Hidden; recordBoxVM.Sw.Stop(); if (recordBoxVM.Toggle4thMouse) { FourMouseBtnAction(); } if (recordBoxVM.Toggle5thMouse) { FiveMouseBtnAction(); } if (recordBoxVM.ToggleLightbar) { ChangeLightbarAction(); } if (recordBoxVM.ToggleRumble) { ChangeRumbleAction(); } Enable_Controls(true); } recordBoxVM.EditMacroIndex = -1; recordBoxVM.ToggleLightbar = false; recordBoxVM.ToggleRumble = false; changeLightBtn.Content = "Change Lightbar Color"; addRumbleBtn.Content = "Add Rumble"; recordBoxVM.MacroStepIndex = -1; } private void ClearStepsBtn_Click(object sender, RoutedEventArgs e) { if (!recordBoxVM.Recording) { recordBoxVM.MacroStepIndex = -1; recordBoxVM.MacroSteps.Clear(); } } private void Enable_Controls(bool on) { macroListBox.IsEnabled = on; recordDelaysCk.IsEnabled = on; saveBtn.IsEnabled = on; cancelBtn.IsEnabled = on; loadPresetBtn.IsEnabled = on; savePresetBtn.IsEnabled = on; macroModeCombo.IsEnabled = on; clearStepsBtn.IsEnabled = on; } private void ChangeLightbarAction() { bool light = recordBoxVM.ToggleLightbar = !recordBoxVM.ToggleLightbar; if (light) { changeLightBtn.Content = "Reset Lightbar Color"; DS4Windows.MacroStep step = new DS4Windows.MacroStep(1255255255, $"Lightbar Color: 255,255,255", DS4Windows.MacroStep.StepType.ActDown, DS4Windows.MacroStep.StepOutput.Lightbar); recordBoxVM.AddMacroStep(step); } else { changeLightBtn.Content = "Change Lightbar Color"; DS4Windows.MacroStep step = new DS4Windows.MacroStep(1000000000, $"Reset Lightbar", DS4Windows.MacroStep.StepType.ActUp, DS4Windows.MacroStep.StepOutput.Lightbar); recordBoxVM.AddMacroStep(step); } } private void ChangeLightBtn_Click(object sender, RoutedEventArgs e) { ChangeLightbarAction(); } private void ChangeRumbleAction() { bool rumble = recordBoxVM.ToggleRumble = !recordBoxVM.ToggleRumble; if (rumble) { addRumbleBtn.Content = "Stop Rumble"; DS4Windows.MacroStep step = new DS4Windows.MacroStep(1255255, $"Rumble 255,255", DS4Windows.MacroStep.StepType.ActDown, DS4Windows.MacroStep.StepOutput.Rumble); recordBoxVM.AddMacroStep(step); } else { addRumbleBtn.Content = "Add Rumble"; DS4Windows.MacroStep step = new DS4Windows.MacroStep(1000000, $"Stop Rumble", DS4Windows.MacroStep.StepType.ActUp, DS4Windows.MacroStep.StepOutput.Rumble); recordBoxVM.AddMacroStep(step); } } private void AddRumbleBtn_Click(object sender, RoutedEventArgs e) { ChangeRumbleAction(); } private void LoadPresetBtn_Click(object sender, RoutedEventArgs e) { loadPresetBtn.ContextMenu.IsOpen = true; } private void SavePresetBtn_Click(object sender, RoutedEventArgs e) { macroListBox.ItemsSource = null; SaveFileDialog dialog = new SaveFileDialog(); dialog.AddExtension = true; dialog.DefaultExt = ".txt"; dialog.Filter = "Text Documents (*.txt)|*.txt"; dialog.Title = "Select Export File"; dialog.InitialDirectory = $"{DS4Windows.Global.appdatapath}\\Macros"; if (dialog.ShowDialog() == true) { //recordBoxVM.MacroSteps.Clear(); recordBoxVM.SavePreset(dialog.FileName); } macroListBox.ItemsSource = recordBoxVM.MacroSteps; } private void UserControl_KeyDown(object sender, KeyEventArgs e) { if (recordBoxVM.Recording) { Key tempKey = e.SystemKey == Key.None ? e.Key : e.SystemKey; int value = KeyInterop.VirtualKeyFromKey(tempKey); recordBoxVM.KeysdownMap.TryGetValue(value, out bool isdown); if (!isdown) { DS4Windows.MacroStep step = new DS4Windows.MacroStep(value, tempKey.ToString(), DS4Windows.MacroStep.StepType.ActDown, DS4Windows.MacroStep.StepOutput.Key); recordBoxVM.AddMacroStep(step); recordBoxVM.KeysdownMap.Add(value, true); } e.Handled = true; //Console.WriteLine(e.Key); //Console.WriteLine(e.SystemKey); } else if (e.Key == Key.Delete && recordBoxVM.MacroStepIndex >= 0) { recordBoxVM.MacroSteps.RemoveAt(recordBoxVM.MacroStepIndex); e.Handled = true; } } private void UserControl_KeyUp(object sender, KeyEventArgs e) { if (recordBoxVM.Recording) { Key tempKey = e.SystemKey == Key.None ? e.Key : e.SystemKey; int value = KeyInterop.VirtualKeyFromKey(tempKey); recordBoxVM.KeysdownMap.TryGetValue(value, out bool isdown); if (isdown) { DS4Windows.MacroStep step = new DS4Windows.MacroStep(value, tempKey.ToString(), DS4Windows.MacroStep.StepType.ActUp, DS4Windows.MacroStep.StepOutput.Key); recordBoxVM.AddMacroStep(step); recordBoxVM.KeysdownMap.Remove(value); } e.Handled = true; //Console.WriteLine(e.Key); //Console.WriteLine(e.SystemKey); } } private void MacroListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e) { if (recordBoxVM.MacroStepIndex >= 0) { MacroStepItem item = recordBoxVM.MacroSteps[recordBoxVM.MacroStepIndex]; if (item.Step.ActType == DS4Windows.MacroStep.StepType.Wait) { ListBoxItem lbitem = macroListBox.ItemContainerGenerator.ContainerFromIndex(recordBoxVM.MacroStepIndex) as ListBoxItem; lbitem.ContentTemplate = this.FindResource("EditTemplate") as DataTemplate; recordBoxVM.EditMacroIndex = recordBoxVM.MacroStepIndex; } else if (item.Step.OutputType == DS4Windows.MacroStep.StepOutput.Rumble && item.Step.ActType == DS4Windows.MacroStep.StepType.ActDown) { ListBoxItem lbitem = macroListBox.ItemContainerGenerator.ContainerFromIndex(recordBoxVM.MacroStepIndex) as ListBoxItem; lbitem.ContentTemplate = this.FindResource("EditRumbleTemplate") as DataTemplate; recordBoxVM.EditMacroIndex = recordBoxVM.MacroStepIndex; } else if (item.Step.OutputType == DS4Windows.MacroStep.StepOutput.Lightbar && item.Step.ActType == DS4Windows.MacroStep.StepType.ActDown) { colorDialog = new ColorPickerWindow(); colorDialog.Owner = Application.Current.MainWindow; Color tempcolor = item.LightbarColorValue(); colorDialog.colorPicker.SelectedColor = tempcolor; recordBoxVM.StartForcedColor(tempcolor); colorDialog.ColorChanged += (sender2, color) => { recordBoxVM.UpdateForcedColor(color); }; colorDialog.ShowDialog(); recordBoxVM.EndForcedColor(); item.UpdateLightbarValue(colorDialog.colorPicker.SelectedColor.GetValueOrDefault()); FocusNavigationDirection focusDirection = FocusNavigationDirection.Next; TraversalRequest request = new TraversalRequest(focusDirection); UIElement elementWithFocus = Keyboard.FocusedElement as UIElement; elementWithFocus?.MoveFocus(request); } } } private void RevertListItemTemplate() { if (recordBoxVM.EditMacroIndex >= 0) { ListBoxItem lbitem = macroListBox.ItemContainerGenerator.ContainerFromIndex(recordBoxVM.EditMacroIndex) as ListBoxItem; lbitem.ContentTemplate = this.FindResource("DisplayTemplate") as DataTemplate; recordBoxVM.EditMacroIndex = -1; } } private void UpdateDataRevertTemplate() { ListBoxItem lbitem = macroListBox.ItemContainerGenerator.ContainerFromIndex(recordBoxVM.EditMacroIndex) as ListBoxItem; ContentPresenter contentPresenter = UtilMethods.FindVisualChild(lbitem); DataTemplate oldDataTemplate = contentPresenter.ContentTemplate; MacroStepItem item = recordBoxVM.MacroSteps[recordBoxVM.EditMacroIndex]; if (item.Step.ActType == DS4Windows.MacroStep.StepType.Wait) { IntegerUpDown integerUpDown = oldDataTemplate.FindName("waitIUD", contentPresenter) as IntegerUpDown; if (integerUpDown != null) { BindingExpression bindExp = integerUpDown.GetBindingExpression(IntegerUpDown.ValueProperty); bindExp.UpdateSource(); } } else if (item.Step.OutputType == DS4Windows.MacroStep.StepOutput.Rumble) { IntegerUpDown heavyRumble = oldDataTemplate.FindName("heavyRumbleUD", contentPresenter) as IntegerUpDown; IntegerUpDown lightRumble = oldDataTemplate.FindName("lightRumbleUD", contentPresenter) as IntegerUpDown; if (heavyRumble != null && lightRumble != null) { BindingExpression bindExp = heavyRumble.GetBindingExpression(IntegerUpDown.ValueProperty); bindExp.UpdateSource(); bindExp = lightRumble.GetBindingExpression(IntegerUpDown.ValueProperty); bindExp.UpdateSource(); } } lbitem.ContentTemplate = this.FindResource("DisplayTemplate") as DataTemplate; recordBoxVM.EditMacroIndex = -1; } private void CycleProgPresetMenuItem_Click(object sender, RoutedEventArgs e) { macroListBox.ItemsSource = null; recordBoxVM.MacroSteps.Clear(); recordBoxVM.WriteCycleProgramsPreset(); macroListBox.ItemsSource = recordBoxVM.MacroSteps; } private void LoadPresetFromFileMenuItem_Click(object sender, RoutedEventArgs e) { macroListBox.ItemsSource = null; OpenFileDialog dialog = new OpenFileDialog(); dialog.AddExtension = true; dialog.DefaultExt = ".txt"; dialog.Filter = "Text Documents (*.txt)|*.txt"; dialog.Title = "Select Preset File"; dialog.InitialDirectory = $"{DS4Windows.Global.appdatapath}\\Macros"; if (dialog.ShowDialog() == true) { recordBoxVM.MacroSteps.Clear(); recordBoxVM.LoadPresetFromFile(dialog.FileName); } macroListBox.ItemsSource = recordBoxVM.MacroSteps; } private void WaitIUD_KeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Enter) { IntegerUpDown integerUpDown = sender as IntegerUpDown; BindingExpression bindExp = integerUpDown.GetBindingExpression(IntegerUpDown.ValueProperty); bindExp.UpdateSource(); ListBoxItem lbitem = macroListBox.ItemContainerGenerator.ContainerFromIndex(recordBoxVM.EditMacroIndex) as ListBoxItem; lbitem.ContentTemplate = this.FindResource("DisplayTemplate") as DataTemplate; recordBoxVM.EditMacroIndex = -1; } } private void FourMouseBtnAction() { int value = 259; recordBoxVM.KeysdownMap.TryGetValue(value, out bool isdown); if (!isdown) { DS4Windows.MacroStep step = new DS4Windows.MacroStep(value, DS4Windows.MacroParser.macroInputNames[value], DS4Windows.MacroStep.StepType.ActDown, DS4Windows.MacroStep.StepOutput.Button); recordBoxVM.AddMacroStep(step); recordBoxVM.KeysdownMap.Add(value, true); } else { DS4Windows.MacroStep step = new DS4Windows.MacroStep(value, DS4Windows.MacroParser.macroInputNames[value], DS4Windows.MacroStep.StepType.ActUp, DS4Windows.MacroStep.StepOutput.Button); recordBoxVM.AddMacroStep(step); recordBoxVM.KeysdownMap.Remove(value); } } private void FourMouseBtn_Click(object sender, RoutedEventArgs e) { FourMouseBtnAction(); } private void FiveMouseBtnAction() { int value = 260; recordBoxVM.KeysdownMap.TryGetValue(value, out bool isdown); if (!isdown) { DS4Windows.MacroStep step = new DS4Windows.MacroStep(value, DS4Windows.MacroParser.macroInputNames[value], DS4Windows.MacroStep.StepType.ActDown, DS4Windows.MacroStep.StepOutput.Button); recordBoxVM.AddMacroStep(step); recordBoxVM.KeysdownMap.Add(value, true); } else { DS4Windows.MacroStep step = new DS4Windows.MacroStep(value, DS4Windows.MacroParser.macroInputNames[value], DS4Windows.MacroStep.StepType.ActUp, DS4Windows.MacroStep.StepOutput.Button); recordBoxVM.AddMacroStep(step); recordBoxVM.KeysdownMap.Remove(value); } } private void FiveMouseBtn_Click(object sender, RoutedEventArgs e) { FiveMouseBtnAction(); } private void UserControl_MouseDown(object sender, MouseButtonEventArgs e) { if (recordBoxVM.Recording) { int value; switch (e.ChangedButton) { case MouseButton.Left: value = 256; break; case MouseButton.Right: value = 257; break; case MouseButton.Middle: value = 258; break; case MouseButton.XButton1: value = 259; break; case MouseButton.XButton2: value = 260; break; default: value = 0; break; } DS4Windows.MacroStep step = new DS4Windows.MacroStep(value, DS4Windows.MacroParser.macroInputNames[value], DS4Windows.MacroStep.StepType.ActDown, DS4Windows.MacroStep.StepOutput.Button); recordBoxVM.AddMacroStep(step); recordBoxVM.KeysdownMap.Add(value, true); e.Handled = true; } } private void UserControl_MouseUp(object sender, MouseButtonEventArgs e) { if (recordBoxVM.Recording) { int value; switch (e.ChangedButton) { case MouseButton.Left: value = 256; break; case MouseButton.Right: value = 257; break; case MouseButton.Middle: value = 258; break; case MouseButton.XButton1: value = 259; break; case MouseButton.XButton2: value = 260; break; default: value = 0; break; } DS4Windows.MacroStep step = new DS4Windows.MacroStep(value, DS4Windows.MacroParser.macroInputNames[value], DS4Windows.MacroStep.StepType.ActUp, DS4Windows.MacroStep.StepOutput.Button); recordBoxVM.AddMacroStep(step); recordBoxVM.KeysdownMap.Remove(value); e.Handled = true; } } } }