cemu-DS4Windows/DS4Windows/DS4Forms/ViewModels/RecordBoxViewModel.cs

437 lines
14 KiB
C#
Raw Normal View History

2019-12-18 22:33:23 +01:00
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using DS4Windows;
namespace DS4WinWPF.DS4Forms.ViewModels
{
public class RecordBoxViewModel
{
private Stopwatch sw = new Stopwatch();
private int deviceNum;
public int DeviceNum { get => deviceNum; }
private DS4ControlSettings settings;
public DS4ControlSettings Settings { get => settings; }
private bool shift;
public bool Shift { get => shift; }
private bool recordDelays;
public bool RecordDelays { get => recordDelays; set => recordDelays = value; }
private int macroModeIndex;
public int MacroModeIndex { get => macroModeIndex; set => macroModeIndex = value; }
private bool recording;
public bool Recording { get => recording; set => recording = value; }
private bool toggleLightbar;
public bool ToggleLightbar { get => toggleLightbar; set => toggleLightbar = value; }
private bool toggleRummble;
public bool ToggleRumble { get => toggleRummble; set => toggleRummble = value; }
private bool toggle4thMouse;
private bool toggle5thMouse;
private int appendIndex = -1;
private object _colLockobj = new object();
private ObservableCollection<MacroStepItem> macroSteps =
new ObservableCollection<MacroStepItem>();
public ObservableCollection<MacroStepItem> MacroSteps { get => macroSteps; }
private int macroStepIndex;
public int MacroStepIndex
{
get => macroStepIndex;
set
{
if (macroStepIndex == value) return;
macroStepIndex = value;
MacroStepIndexChanged?.Invoke(this, EventArgs.Empty);
}
}
public event EventHandler MacroStepIndexChanged;
public Stopwatch Sw { get => sw; }
public bool Toggle4thMouse { get => toggle4thMouse; set => toggle4thMouse = value; }
public bool Toggle5thMouse { get => toggle5thMouse; set => toggle5thMouse = value; }
public int AppendIndex { get => appendIndex; set => appendIndex = value; }
public int EditMacroIndex { get => editMacroIndex; set => editMacroIndex = value; }
public Dictionary<int, bool> KeysdownMap { get => keysdownMap; }
public bool UseScanCode { get => useScanCode; set => useScanCode = value; }
private int editMacroIndex = -1;
private Dictionary<int, bool> keysdownMap = new Dictionary<int, bool>();
private bool useScanCode;
public RecordBoxViewModel(int deviceNum, DS4ControlSettings controlSettings, bool shift)
{
this.deviceNum = deviceNum;
settings = controlSettings;
this.shift = shift;
if (!shift && settings.keyType.HasFlag(DS4KeyType.HoldMacro))
{
macroModeIndex = 1;
}
else if (shift && settings.shiftKeyType.HasFlag(DS4KeyType.HoldMacro))
{
macroModeIndex = 1;
}
if (!shift && settings.keyType.HasFlag(DS4KeyType.ScanCode))
{
useScanCode = true;
}
else if (shift && settings.shiftKeyType.HasFlag(DS4KeyType.ScanCode))
{
useScanCode = true;
}
if (!shift && settings.action is int[])
{
LoadMacro();
}
else if (shift && settings.shiftAction is int[])
{
LoadMacro();
}
BindingOperations.EnableCollectionSynchronization(macroSteps, _colLockobj);
// By default RECORD button appends new steps. User must select (click) an existing step to insert new steps in front of the selected step
this.MacroStepIndex = -1;
2019-12-18 22:33:23 +01:00
}
public void LoadMacro()
{
int[] macro;
if (!shift)
{
macro = (int[])settings.action;
}
else
{
macro = (int[])settings.shiftAction;
}
MacroParser macroParser = new MacroParser(macro);
macroParser.LoadMacro();
foreach(MacroStep step in macroParser.MacroSteps)
{
MacroStepItem item = new MacroStepItem(step);
macroSteps.Add(item);
}
}
public void ExportMacro()
{
int[] outmac = new int[macroSteps.Count];
int index = 0;
foreach(MacroStepItem step in macroSteps)
{
outmac[index] = step.Step.Value;
index++;
}
if (!shift)
{
settings.action = outmac;
settings.actionType = DS4ControlSettings.ActionType.Macro;
settings.keyType = DS4KeyType.Macro;
if (macroModeIndex == 1)
{
settings.keyType |= DS4KeyType.HoldMacro;
}
if (useScanCode)
{
settings.keyType |= DS4KeyType.ScanCode;
}
}
else
{
settings.shiftAction = outmac;
settings.shiftActionType = DS4ControlSettings.ActionType.Macro;
settings.shiftKeyType = DS4KeyType.Macro;
if (macroModeIndex == 1)
{
settings.shiftKeyType |= DS4KeyType.HoldMacro;
}
if (useScanCode)
{
settings.shiftKeyType |= DS4KeyType.ScanCode;
}
}
}
public void WriteCycleProgramsPreset()
{
MacroStep step = new MacroStep(18, KeyInterop.KeyFromVirtualKey(18).ToString(),
MacroStep.StepType.ActDown, MacroStep.StepOutput.Key);
macroSteps.Add(new MacroStepItem(step));
step = new MacroStep(9, KeyInterop.KeyFromVirtualKey(9).ToString(),
MacroStep.StepType.ActDown, MacroStep.StepOutput.Key);
macroSteps.Add(new MacroStepItem(step));
step = new MacroStep(9, KeyInterop.KeyFromVirtualKey(9).ToString(),
MacroStep.StepType.ActUp, MacroStep.StepOutput.Key);
macroSteps.Add(new MacroStepItem(step));
step = new MacroStep(18, KeyInterop.KeyFromVirtualKey(18).ToString(),
MacroStep.StepType.ActUp, MacroStep.StepOutput.Key);
macroSteps.Add(new MacroStepItem(step));
step = new MacroStep(1300, $"Wait 1000ms",
MacroStep.StepType.Wait, MacroStep.StepOutput.None);
macroSteps.Add(new MacroStepItem(step));
}
public void LoadPresetFromFile(string filepath)
{
string[] macs = File.ReadAllText(filepath).Split('/');
List<int> tmpmacro = new List<int>();
int temp;
foreach (string s in macs)
{
if (int.TryParse(s, out temp))
tmpmacro.Add(temp);
}
MacroParser macroParser = new MacroParser(tmpmacro.ToArray());
macroParser.LoadMacro();
foreach (MacroStep step in macroParser.MacroSteps)
{
MacroStepItem item = new MacroStepItem(step);
macroSteps.Add(item);
}
}
public void SavePreset(string filepath)
{
int[] outmac = new int[macroSteps.Count];
int index = 0;
foreach (MacroStepItem step in macroSteps)
{
outmac[index] = step.Step.Value;
index++;
}
string macro = string.Join("/", outmac);
StreamWriter sw = new StreamWriter(filepath);
sw.Write(macro);
sw.Close();
}
public void AddMacroStep(MacroStep step)
{
if (recordDelays && macroSteps.Count > 0)
{
int elapsed = (int)sw.ElapsedMilliseconds + 300;
MacroStep waitstep = new MacroStep(elapsed, $"Wait {elapsed - 300}ms",
MacroStep.StepType.Wait, MacroStep.StepOutput.None);
MacroStepItem waititem = new MacroStepItem(waitstep);
if (appendIndex == -1)
{
macroSteps.Add(waititem);
}
else
{
macroSteps.Insert(appendIndex, waititem);
appendIndex++;
}
}
sw.Restart();
MacroStepItem item = new MacroStepItem(step);
if (appendIndex == -1)
{
macroSteps.Add(item);
}
else
{
macroSteps.Insert(appendIndex, item);
appendIndex++;
}
}
public void StartForcedColor(Color color)
{
if (deviceNum < 4)
{
DS4Color dcolor = new DS4Color() { red = color.R, green = color.G, blue = color.B };
DS4LightBar.forcedColor[deviceNum] = dcolor;
DS4LightBar.forcedFlash[deviceNum] = 0;
DS4LightBar.forcelight[deviceNum] = true;
}
}
public void EndForcedColor()
{
if (deviceNum < 4)
{
DS4LightBar.forcedColor[deviceNum] = new DS4Color(0, 0, 0);
DS4LightBar.forcedFlash[deviceNum] = 0;
DS4LightBar.forcelight[deviceNum] = false;
}
}
public void UpdateForcedColor(Color color)
{
if (deviceNum < 4)
{
DS4Color dcolor = new DS4Color() { red = color.R, green = color.G, blue = color.B };
DS4LightBar.forcedColor[deviceNum] = dcolor;
DS4LightBar.forcedFlash[deviceNum] = 0;
DS4LightBar.forcelight[deviceNum] = true;
}
}
public void ProcessDS4Tick()
{
if (Program.rootHub.DS4Controllers[0] != null)
{
DS4Device dev = Program.rootHub.DS4Controllers[0];
DS4State cState = dev.getCurrentStateRef();
for (DS4Controls dc = DS4Controls.LXNeg; dc < DS4Controls.GyroXPos; dc++)
{
// Ignore Touch controls
if (dc >= DS4Controls.TouchLeft && dc <= DS4Controls.TouchRight)
{
continue;
}
int macroValue = Global.macroDS4Values[dc];
keysdownMap.TryGetValue(macroValue, out bool isdown);
2019-12-18 22:33:23 +01:00
if (!isdown && Mapping.getBoolMapping(0, dc, cState, null, null))
{
MacroStep step = new MacroStep(macroValue, MacroParser.macroInputNames[macroValue],
MacroStep.StepType.ActDown, MacroStep.StepOutput.Button);
AddMacroStep(step);
keysdownMap.Add(macroValue, true);
2019-12-18 22:33:23 +01:00
}
else if (isdown && !Mapping.getBoolMapping(0, dc, cState, null, null))
{
MacroStep step = new MacroStep(macroValue, MacroParser.macroInputNames[macroValue],
MacroStep.StepType.ActUp, MacroStep.StepOutput.Button);
AddMacroStep(step);
keysdownMap.Remove(macroValue);
2019-12-18 22:33:23 +01:00
}
}
}
}
}
public class MacroStepItem
{
private static string[] imageSources = new string[]
{
"/DS4Windows;component/Resources/keydown.png",
"/DS4Windows;component/Resources/keyup.png",
"/DS4Windows;component/Resources/clock.png",
};
private MacroStep step;
private string image;
public string Image { get => image; }
public MacroStep Step { get => step; }
public int DisplayValue
{
get
{
int result = step.Value;
if (step.ActType == MacroStep.StepType.Wait)
{
result -= 300;
}
return result;
}
set
{
int result = value;
if (step.ActType == MacroStep.StepType.Wait)
{
result += 300;
}
step.Value = result;
}
}
public int RumbleHeavy
{
get
{
int result = step.Value;
result -= 1000000;
string temp = result.ToString();
result = int.Parse(temp.Substring(0, 3));
return result;
}
set
{
int result = step.Value;
result -= 1000000;
int curHeavy = result / 1000;
int curLight = result - (curHeavy * 1000);
result = curLight + (value * 1000) + 1000000;
step.Value = result;
}
}
public int RumbleLight
{
get
{
int result = step.Value;
result -= 1000000;
string temp = result.ToString();
result = int.Parse(temp.Substring(3, 3));
return result;
}
set
{
int result = step.Value;
result -= 1000000;
int curHeavy = result / 1000;
result = value + (curHeavy * 1000) + 1000000;
step.Value = result;
}
}
public MacroStepItem(MacroStep step)
{
this.step = step;
image = imageSources[(int)step.ActType];
}
public void UpdateLightbarValue(Color color)
{
step.Value = 1000000000 + (color.R*1000000)+(color.G*1000)+color.B;
}
public Color LightbarColorValue()
{
int temp = step.Value - 1000000000;
int r = temp / 1000000;
temp -= (r * 1000000);
int g = temp / 1000;
temp -= (g * 1000);
int b = temp;
return new Color() { A = 255, R = (byte)r, G = (byte)g, B = (byte)b };
}
}
}