diff options
| author | a1xd <[email protected]> | 2021-04-06 01:21:42 -0400 |
|---|---|---|
| committer | a1xd <[email protected]> | 2021-04-06 01:21:42 -0400 |
| commit | 7c1f14845bc948e9ea25908e96099203d9433a69 (patch) | |
| tree | eadfae6ec0a775a35c29807bde3c20be8160e034 | |
| parent | LUT text layout (diff) | |
| download | rawaccel-7c1f14845bc948e9ea25908e96099203d9433a69.tar.xz rawaccel-7c1f14845bc948e9ea25908e96099203d9433a69.zip | |
update wrapper + writer to handle lut
grapher is building but applying options still broken for the most part
| -rw-r--r-- | common/accel-union.hpp | 3 | ||||
| -rw-r--r-- | common/rawaccel-base.hpp | 3 | ||||
| -rw-r--r-- | common/rawaccel-validate.hpp | 3 | ||||
| -rw-r--r-- | converter/converter.cpp | 10 | ||||
| -rw-r--r-- | grapher/Constants/Constants.cs | 2 | ||||
| -rw-r--r-- | grapher/Form1.cs | 1 | ||||
| -rw-r--r-- | grapher/Layouts/JumpLayout.cs | 24 | ||||
| -rw-r--r-- | grapher/Layouts/LUTLayout.cs | 2 | ||||
| -rw-r--r-- | grapher/Layouts/LinearLayout.cs | 2 | ||||
| -rw-r--r-- | grapher/Models/AccelGUI.cs | 124 | ||||
| -rw-r--r-- | grapher/Models/Mouse/MouseWatcher.cs | 4 | ||||
| -rw-r--r-- | grapher/Models/Options/AccelTypeOptions.cs | 23 | ||||
| -rw-r--r-- | grapher/Models/Serialized/GUISettings.cs | 27 | ||||
| -rw-r--r-- | grapher/Models/Serialized/LookupTable.cs | 50 | ||||
| -rw-r--r-- | grapher/Models/Serialized/RawAccelSettings.cs | 141 | ||||
| -rw-r--r-- | grapher/Models/Serialized/SettingsManager.cs | 138 | ||||
| -rw-r--r-- | grapher/grapher.csproj | 3 | ||||
| -rw-r--r-- | wrapper/input.cpp | 74 | ||||
| -rw-r--r-- | wrapper/interop-exception.h | 21 | ||||
| -rw-r--r-- | wrapper/wrapper.cpp | 414 | ||||
| -rw-r--r-- | wrapper/wrapper.vcxproj | 3 | ||||
| -rw-r--r-- | wrapper/wrapper.vcxproj.filters | 6 | ||||
| -rw-r--r-- | writer/Program.cs | 88 |
23 files changed, 665 insertions, 501 deletions
diff --git a/common/accel-union.hpp b/common/accel-union.hpp index 3d41a18..7f3d5d5 100644 --- a/common/accel-union.hpp +++ b/common/accel-union.hpp @@ -22,6 +22,7 @@ namespace rawaccel { motivity_gain, lut_log, lut_lin, + lut_arb, noaccel }; @@ -31,6 +32,7 @@ namespace rawaccel { switch (lut_mode) { case table_mode::binlog: return internal_mode::lut_log; case table_mode::linear: return internal_mode::lut_lin; + case table_mode::arbitrary: return internal_mode::lut_arb; default: return internal_mode::noaccel; } } @@ -64,6 +66,7 @@ namespace rawaccel { case internal_mode::motivity_gain: return vis(u.motivity_g); case internal_mode::lut_log: return vis(u.log_lut); case internal_mode::lut_lin: return vis(u.lin_lut); + case internal_mode::lut_arb: default: return vis(u.noaccel); } } diff --git a/common/rawaccel-base.hpp b/common/rawaccel-base.hpp index 9900aab..d318db5 100644 --- a/common/rawaccel-base.hpp +++ b/common/rawaccel-base.hpp @@ -29,7 +29,8 @@ namespace rawaccel { enum class table_mode { off, binlog, - linear + linear, + arbitrary }; struct table_args { diff --git a/common/rawaccel-validate.hpp b/common/rawaccel-validate.hpp index bccb21c..d625d20 100644 --- a/common/rawaccel-validate.hpp +++ b/common/rawaccel-validate.hpp @@ -44,7 +44,7 @@ namespace rawaccel { error("stop must be greater than start"); } - if (lut_args.num_elements < 2 || + if (lut_args.num_elements < 2 || lut_args.num_elements > 1025) { error("num must be between 2 and 1025"); } @@ -73,6 +73,7 @@ namespace rawaccel { } } + if (args.offset < 0) { error("offset can not be negative"); } diff --git a/converter/converter.cpp b/converter/converter.cpp index 7b71af3..b1761b0 100644 --- a/converter/converter.cpp +++ b/converter/converter.cpp @@ -10,6 +10,7 @@ #include <string> using namespace System; +using namespace System::IO; using namespace System::Runtime::InteropServices; using namespace Newtonsoft::Json; @@ -181,9 +182,9 @@ bool try_convert(const ia_settings_t& ia_settings) { } default: return false; } - + DriverSettings^ new_settings = Marshal::PtrToStructure<DriverSettings^>((IntPtr)&ra_settings); - auto errors = gcnew SettingsErrors(new_settings); + SettingsErrors^ errors = gcnew SettingsErrors(new_settings); if (!errors->Empty()) { Console::WriteLine("Bad settings: {0}", errors); @@ -191,12 +192,11 @@ bool try_convert(const ia_settings_t& ia_settings) { } Console::Write("Sending to driver... "); - (gcnew ManagedAccel(new_settings))->Activate(); + (gcnew ManagedAccel(gcnew ExtendedSettings(new_settings)))->Activate(); Console::WriteLine("done"); Console::Write("Generating settings.json... "); - auto json = JsonConvert::SerializeObject(new_settings, Formatting::Indented); - System::IO::File::WriteAllText("settings.json", json); + File::WriteAllText("settings.json", RaConvert::Settings(new_settings)); Console::WriteLine("done"); return true; diff --git a/grapher/Constants/Constants.cs b/grapher/Constants/Constants.cs index 446f5fa..d2e747c 100644 --- a/grapher/Constants/Constants.cs +++ b/grapher/Constants/Constants.cs @@ -120,6 +120,8 @@ namespace grapher /// <summary> Default name of settings file. </summary> public const string DefaultSettingsFileName = @"settings.json"; + public const string GuiConfigFileName = ".config"; + /// <summary> Text to direcitonality panel title when panel is closed. </summary> public const string DirectionalityTitleClosed = "Anisotropy \u25BC"; diff --git a/grapher/Form1.cs b/grapher/Form1.cs index 5b13c8f..a4ece9e 100644 --- a/grapher/Form1.cs +++ b/grapher/Form1.cs @@ -28,7 +28,6 @@ namespace grapher { InitializeComponent(); - Version assemVersion = typeof(RawAcceleration).Assembly.GetName().Version; Version driverVersion = null; try diff --git a/grapher/Layouts/JumpLayout.cs b/grapher/Layouts/JumpLayout.cs new file mode 100644 index 0000000..cb77963 --- /dev/null +++ b/grapher/Layouts/JumpLayout.cs @@ -0,0 +1,24 @@ +using grapher.Models.Serialized; + +namespace grapher.Layouts +{ + public class JumpLayout : LayoutBase + { + public JumpLayout() + : base() + { + Name = "Jump"; + Index = (int)AccelMode.jump; + LogarithmicCharts = false; + + AccelLayout = new OptionLayout(false, Acceleration); + ScaleLayout = new OptionLayout(false, string.Empty); + CapLayout = new OptionLayout(true, string.Empty); + WeightLayout = new OptionLayout(false, Weight); + OffsetLayout = new OptionLayout(true, Offset); + LimitLayout = new OptionLayout(false, Limit); + ExponentLayout = new OptionLayout(false, string.Empty); + MidpointLayout = new OptionLayout(false, string.Empty); + } + } +} diff --git a/grapher/Layouts/LUTLayout.cs b/grapher/Layouts/LUTLayout.cs index 7449168..4b4b687 100644 --- a/grapher/Layouts/LUTLayout.cs +++ b/grapher/Layouts/LUTLayout.cs @@ -14,7 +14,7 @@ namespace grapher.Layouts : base() { Name = "LookUpTable"; - Index = (int)AccelMode.lut; + Index = (int)AccelMode.noaccel + 1; AccelLayout = new OptionLayout(false, Acceleration); ScaleLayout = new OptionLayout(false, string.Empty); diff --git a/grapher/Layouts/LinearLayout.cs b/grapher/Layouts/LinearLayout.cs index 4681ca9..d98baa5 100644 --- a/grapher/Layouts/LinearLayout.cs +++ b/grapher/Layouts/LinearLayout.cs @@ -16,7 +16,7 @@ namespace grapher.Layouts AccelLayout = new OptionLayout(true, Acceleration); ScaleLayout = new OptionLayout(false, string.Empty); CapLayout = new OptionLayout(true, Cap); - WeightLayout = new OptionLayout(true, Weight); + WeightLayout = new OptionLayout(false, Weight); OffsetLayout = new OptionLayout(true, Offset); LimitLayout = new OptionLayout(false, string.Empty); ExponentLayout = new OptionLayout(false, string.Empty); diff --git a/grapher/Models/AccelGUI.cs b/grapher/Models/AccelGUI.cs index 5a04030..9ed2cb9 100644 --- a/grapher/Models/AccelGUI.cs +++ b/grapher/Models/AccelGUI.cs @@ -32,7 +32,7 @@ namespace grapher AccelCharts = accelCharts; ApplyOptions = applyOptions; WriteButton = writeButton; - ToggleButton = (CheckBox)toggleButton; + DisableButton = (CheckBox)toggleButton; ScaleMenuItem = scaleMenuItem; Settings = settings; DefaultButtonFont = WriteButton.Font; @@ -42,7 +42,7 @@ namespace grapher ScaleMenuItem.Click += new System.EventHandler(OnScaleMenuItemClick); WriteButton.Click += new System.EventHandler(OnWriteButtonClick); - ToggleButton.Click += new System.EventHandler(OnToggleButtonClick); + DisableButton.Click += new System.EventHandler(DisableDriverEventHandler); AccelForm.FormClosing += new FormClosingEventHandler(SaveGUISettingsOnClose); ButtonTimerInterval = Convert.ToInt32(DriverSettings.WriteDelayMs); @@ -51,25 +51,8 @@ namespace grapher ChartRefresh = SetupChartTimer(); - bool settingsActive = Settings.Startup(); - SettingsNotDefault = !Settings.RawAccelSettings.IsDefaultEquivalent(); - - if (settingsActive) - { - LastToggleChecked = SettingsNotDefault; - ToggleButton.Enabled = LastToggleChecked; - RefreshOnRead(Settings.RawAccelSettings.AccelerationSettings); - } - else - { - DriverSettings active = ManagedAccel.GetActive().Settings; - bool activeNotDefault = !RawAccelSettings.IsDefaultEquivalent(active); - - LastToggleChecked = activeNotDefault; - ToggleButton.Enabled = SettingsNotDefault || activeNotDefault; - RefreshOnRead(active); - } - + RefreshUser(); + RefreshActive(); SetupButtons(); // TODO: The below removes an overlapping form from the anisotropy panel. @@ -94,7 +77,7 @@ namespace grapher public Button WriteButton { get; } - public CheckBox ToggleButton { get; } + public CheckBox DisableButton { get; } public Timer ButtonTimer { get; } @@ -104,8 +87,6 @@ namespace grapher public DeviceIDManager DeviceIDManager { get; } - public Action UpdateInputManagers { get; private set; } - private Timer ChartRefresh { get; } private Font SmallButtonFont { get; } @@ -125,46 +106,37 @@ namespace grapher private void SaveGUISettingsOnClose(Object sender, FormClosingEventArgs e) { var guiSettings = Settings.MakeGUISettingsFromFields(); - if (!Settings.RawAccelSettings.GUISettings.Equals(guiSettings)) + if (!Settings.GuiSettings.Equals(guiSettings)) { - Settings.RawAccelSettings.GUISettings = guiSettings; - Settings.RawAccelSettings.Save(); + guiSettings.Save(); } } public void UpdateActiveSettingsFromFields() { - var driverSettings = Settings.RawAccelSettings.AccelerationSettings; - - var newArgs = ApplyOptions.GetArgs(); - var settings = new DriverSettings { rotation = ApplyOptions.Rotation.Field.Data, - snap = driverSettings.snap, sensitivity = new Vec2<double> { x = ApplyOptions.Sensitivity.Fields.X, y = ApplyOptions.Sensitivity.Fields.Y }, combineMagnitudes = ApplyOptions.IsWhole, - args = newArgs, - minimumTime = driverSettings.minimumTime, - directionalMultipliers = driverSettings.directionalMultipliers, + args = ApplyOptions.GetArgs(), domainArgs = ApplyOptions.Directionality.GetDomainArgs(), rangeXY = ApplyOptions.Directionality.GetRangeXY(), deviceID = DeviceIDManager.ID, - maximumSpeed = driverSettings.maximumSpeed, - minimumSpeed = driverSettings.minimumSpeed }; + Settings.SetHiddenOptions(settings); + ButtonDelay(WriteButton); - SettingsErrors errors = Settings.TryUpdateActiveSettings(settings); + + SettingsErrors errors = Settings.TryActivate(settings); if (errors.Empty()) { - SettingsNotDefault = !Settings.RawAccelSettings.IsDefaultEquivalent(); - LastToggleChecked = SettingsNotDefault; - RefreshOnRead(Settings.RawAccelSettings.AccelerationSettings); + RefreshActive(); } else { @@ -172,25 +144,28 @@ namespace grapher } } - public void RefreshOnRead(DriverSettings args) + public void UpdateInputManagers() { - UpdateShownActiveValues(args); - UpdateGraph(args); - - UpdateInputManagers = () => - { - MouseWatcher.UpdateHandles(args.deviceID); - DeviceIDManager.Update(args.deviceID); - }; + MouseWatcher.UpdateHandles(Settings.ActiveSettings.baseSettings.deviceID); + DeviceIDManager.Update(Settings.ActiveSettings.baseSettings.deviceID); + } + public void RefreshActive() + { + UpdateGraph(); UpdateInputManagers(); } - public void UpdateGraph(DriverSettings args) + public void RefreshUser() + { + UpdateShownActiveValues(Settings.UserSettings); + } + + public void UpdateGraph() { AccelCharts.Calculate( Settings.ActiveAccel, - args); + Settings.ActiveSettings.baseSettings); AccelCharts.Bind(); } @@ -214,32 +189,31 @@ namespace grapher { WriteButton.Top = Constants.SensitivityChartAloneHeight - Constants.ButtonVerticalOffset; - ToggleButton.Appearance = Appearance.Button; - ToggleButton.FlatStyle = FlatStyle.System; - ToggleButton.TextAlign = ContentAlignment.MiddleCenter; - ToggleButton.Size = WriteButton.Size; - ToggleButton.Top = WriteButton.Top; + DisableButton.Appearance = Appearance.Button; + DisableButton.FlatStyle = FlatStyle.System; + DisableButton.TextAlign = ContentAlignment.MiddleCenter; + DisableButton.Size = WriteButton.Size; + DisableButton.Top = WriteButton.Top; SetButtonDefaults(); } private void SetButtonDefaults() { - ToggleButton.Checked = LastToggleChecked; - - ToggleButton.Font = DefaultButtonFont; - ToggleButton.Text = ToggleButton.Checked ? "Disable" : "Enable"; - ToggleButton.Update(); + DisableButton.Font = DefaultButtonFont; + DisableButton.Text = "Disable"; + DisableButton.Enabled = true; + DisableButton.Update(); WriteButton.Font = DefaultButtonFont; WriteButton.Text = Constants.WriteButtonDefaultText; - WriteButton.Enabled = ToggleButton.Checked || !ToggleButton.Enabled; + WriteButton.Enabled = true; WriteButton.Update(); } private void OnScaleMenuItemClick(object sender, EventArgs e) { - UpdateGraph(Settings.RawAccelSettings.AccelerationSettings); + UpdateGraph(); } private void OnWriteButtonClick(object sender, EventArgs e) @@ -247,24 +221,16 @@ namespace grapher UpdateActiveSettingsFromFields(); } - private void OnToggleButtonClick(object sender, EventArgs e) + private void DisableDriverEventHandler(object sender, EventArgs e) { - var accel = ToggleButton.Checked ? - new ManagedAccel(Settings.RawAccelSettings.AccelerationSettings) : - AccelTypeOptions.DefaultSettings; - - LastToggleChecked = ToggleButton.Checked; - ButtonDelay(ToggleButton); - - SettingsManager.SendToDriver(accel); - Settings.ActiveAccel = accel; - RefreshOnRead(accel.Settings); + ButtonDelay(DisableButton); + Settings.DisableDriver(); + RefreshActive(); } private void OnButtonTimerTick(object sender, EventArgs e) { ButtonTimer.Stop(); - ToggleButton.Enabled = SettingsNotDefault; SetButtonDefaults(); } @@ -276,15 +242,13 @@ namespace grapher private void ButtonDelay(ButtonBase btn) { - ToggleButton.Checked = false; - - ToggleButton.Enabled = false; + DisableButton.Enabled = false; WriteButton.Enabled = false; btn.Font = SmallButtonFont; btn.Text = $"{Constants.ButtonDelayText} : {ButtonTimerInterval} ms"; - ToggleButton.Update(); + DisableButton.Update(); WriteButton.Update(); StartButtonTimer(); diff --git a/grapher/Models/Mouse/MouseWatcher.cs b/grapher/Models/Mouse/MouseWatcher.cs index 163829f..c5c2ae5 100644 --- a/grapher/Models/Mouse/MouseWatcher.cs +++ b/grapher/Models/Mouse/MouseWatcher.cs @@ -772,8 +772,8 @@ namespace grapher.Models.Mouse // strip negative directional multipliers, charts calculated from positive input - Vec2<double> dirMults = SettingsManager.RawAccelSettings - .AccelerationSettings.directionalMultipliers; + Vec2<double> dirMults = SettingsManager.ActiveSettings.baseSettings + .directionalMultipliers; if (dirMults.x > 0 && x < 0) { diff --git a/grapher/Models/Options/AccelTypeOptions.cs b/grapher/Models/Options/AccelTypeOptions.cs index 7e2e3d7..556f969 100644 --- a/grapher/Models/Options/AccelTypeOptions.cs +++ b/grapher/Models/Options/AccelTypeOptions.cs @@ -17,13 +17,14 @@ namespace grapher new LinearLayout(), new ClassicLayout(), new NaturalLayout(), + new JumpLayout(), new PowerLayout(), new MotivityLayout(), new OffLayout(), new LUTLayout(), }.ToDictionary(k => k.Name); - public static readonly ManagedAccel DefaultSettings = new ManagedAccel(); + public static readonly AccelArgs DefaultArgs = new DriverSettings().args.x; #endregion Fields @@ -233,22 +234,18 @@ namespace grapher public void SetArgs(ref AccelArgs args) { - AccelArgs defaults = DefaultSettings.Settings.args.x; - args.accelClassic = defaults.accelClassic; - args.accelMotivity = defaults.accelMotivity; - args.accelNatural = defaults.accelClassic; - args.scale = Scale.Visible ? Scale.Field.Data : defaults.scale; - args.cap = Cap.Visible ? Cap.SensitivityCap : defaults.cap; - args.limit = Limit.Visible ? Limit.Field.Data : defaults.limit; - args.exponent = Exponent.Visible ? Exponent.Field.Data : defaults.exponent; - args.offset = Offset.Visible ? Offset.Offset : defaults.offset; - args.midpoint = Midpoint.Visible ? Midpoint.Field.Data : defaults.midpoint; - args.weight = Weight.Visible ? Weight.Field.Data : defaults.weight; + if (Scale.Visible) args.scale = Scale.Field.Data; + if (Cap.Visible) args.cap = Cap.SensitivityCap; + if (Limit.Visible) args.limit = Limit.Field.Data; + if (Exponent.Visible) args.exponent = Exponent.Field.Data; + if (Offset.Visible) args.offset = Offset.Offset; + if (Midpoint.Visible) args.midpoint = Midpoint.Field.Data; + if (Weight.Visible) args.weight = Weight.Field.Data; } public AccelArgs GenerateArgs() { - AccelArgs args = new AccelArgs(); + AccelArgs args = new DriverSettings().args.x; SetArgs(ref args); return args; } diff --git a/grapher/Models/Serialized/GUISettings.cs b/grapher/Models/Serialized/GUISettings.cs index bb35055..93d56de 100644 --- a/grapher/Models/Serialized/GUISettings.cs +++ b/grapher/Models/Serialized/GUISettings.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json; using System; +using System.IO; namespace grapher.Models.Serialized { @@ -65,6 +66,32 @@ namespace grapher.Models.Serialized AutoWriteToDriverOnStartup.GetHashCode(); } + public void Save() + { + File.WriteAllText(Constants.GuiConfigFileName, JsonConvert.SerializeObject(this)); + } + + public static GUISettings MaybeLoad() + { + GUISettings settings = null; + + try + { + settings = JsonConvert.DeserializeObject<GUISettings>( + File.ReadAllText(Constants.GuiConfigFileName)); + } + catch (Exception ex) + { + if (!(ex is JsonException || ex is FileNotFoundException)) + { + throw; + } + } + + return settings; + } + #endregion Methods + } } diff --git a/grapher/Models/Serialized/LookupTable.cs b/grapher/Models/Serialized/LookupTable.cs deleted file mode 100644 index d373461..0000000 --- a/grapher/Models/Serialized/LookupTable.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace grapher.Models.Serialized -{ - [Serializable] - public static class LookupTable - { - public static void Deserialize(string lutFile, ref DriverSettings settings) - { - if (!File.Exists(lutFile)) - { - throw new Exception($"LUT file does not exist at {lutFile}."); - } - - JObject lutJObject = JObject.Parse(File.ReadAllText(lutFile)); - - var spacedLut = lutJObject.ToObject<SpacedTable>(JsonSerializer.Create(RawAccelSettings.SerializerSettings)); - - if (spacedLut is null) - { - var arbitraryLut = lutJObject.ToObject<ArbitraryTable>(JsonSerializer.Create(RawAccelSettings.SerializerSettings)); - - if (arbitraryLut is null || arbitraryLut.points is null) - { - throw new Exception($"{lutFile} does not contain valid lookuptable json."); - } - - settings.ArbitraryTable = arbitraryLut; - settings.args.x.lutArgs.type = TableType.arbitrary; - } - else - { - if (spacedLut.points is null) - { - throw new Exception($"{lutFile} does not contain valid lookuptable json."); - } - - settings.SpacedTable = spacedLut; - settings.args.x.lutArgs = spacedLut.args; - } - } - } -} diff --git a/grapher/Models/Serialized/RawAccelSettings.cs b/grapher/Models/Serialized/RawAccelSettings.cs deleted file mode 100644 index dc4eb0a..0000000 --- a/grapher/Models/Serialized/RawAccelSettings.cs +++ /dev/null @@ -1,141 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.IO; -using System.Linq; - -namespace grapher.Models.Serialized -{ - [Serializable] - public class RawAccelSettings - { - #region Fields - - public static readonly string ExecutingDirectory = AppDomain.CurrentDomain.BaseDirectory; - public static readonly string DefaultSettingsFile = Path.Combine(ExecutingDirectory, Constants.DefaultSettingsFileName); - public static readonly JsonSerializerSettings SerializerSettings = new JsonSerializerSettings - { - MissingMemberHandling = MissingMemberHandling.Ignore, - }; - #endregion Fields - - #region Constructors - - public RawAccelSettings() { } - - public RawAccelSettings( - DriverSettings accelSettings, - GUISettings guiSettings) - { - AccelerationSettings = accelSettings; - GUISettings = guiSettings; - } - - #endregion Constructors - - #region Properties - [JsonProperty(Required = Required.Always)] - public GUISettings GUISettings { get; set; } - - [JsonProperty(DriverSettings.Key, Required = Required.Always)] - public DriverSettings AccelerationSettings { get; set; } - - #endregion Properties - - #region Methods - - public static RawAccelSettings Load(Func<GUISettings> DefaultGUISettingsSupplier) - { - return Load(DefaultSettingsFile, DefaultGUISettingsSupplier); - } - - public static RawAccelSettings Load(string file, Func<GUISettings> DefaultGUISettingsSupplier) - { - try - { - RawAccelSettings settings = null; - - JObject settingsJObject = JObject.Parse(File.ReadAllText(file)); - if (settingsJObject.ContainsKey(DriverSettings.Key)) - { - settings = settingsJObject.ToObject<RawAccelSettings>(JsonSerializer.Create(SerializerSettings)); - } - else - { - settings = new RawAccelSettings - { - AccelerationSettings = settingsJObject.ToObject<DriverSettings>(), - GUISettings = DefaultGUISettingsSupplier() - }; - } - - if (settings is null || settings.AccelerationSettings is null) - { - throw new JsonException($"{file} contains invalid JSON"); - } - - return settings; - } - catch (FileNotFoundException e) - { - throw new FileNotFoundException($"Settings file does not exist at {file}", e); - } - catch (JsonException e) - { - throw new JsonException($"Settings file at {file} does not contain valid Raw Accel Settings.", e); - } - } - - public static bool Exists() - { - return Exists(DefaultSettingsFile); - } - - public static bool Exists(string file) - { - return File.Exists(file); - } - - public void Save() - { - Save(DefaultSettingsFile); - } - - public void Save(string file) - { - JObject thisJO = JObject.FromObject(this); - AddComments(thisJO); - File.WriteAllText(file, thisJO.ToString(Formatting.Indented)); - } - - private void AddComments(JObject thisJO) - { - string modes = string.Join(" | ", Enum.GetNames(typeof(AccelMode))); - ((JObject)thisJO[DriverSettings.Key]) - .AddFirst(new JProperty("### Mode Types ###", modes)); - } - - public bool IsDefaultEquivalent() - { - return IsDefaultEquivalent(AccelerationSettings); - } - - public static bool IsDefaultEquivalent(DriverSettings accelSettings) - { - bool wholeOrNoY = accelSettings.combineMagnitudes || - accelSettings.args.y.mode == AccelMode.noaccel; - - return string.IsNullOrEmpty(accelSettings.deviceID) && - accelSettings.sensitivity.x == 1 && - accelSettings.sensitivity.y == 1 && - accelSettings.directionalMultipliers.x <= 0 && - accelSettings.directionalMultipliers.y <= 0 && - accelSettings.rotation == 0 && - accelSettings.snap == 0 && - accelSettings.args.x.mode == AccelMode.noaccel && - wholeOrNoY; - } - - #endregion Methods - } -} diff --git a/grapher/Models/Serialized/SettingsManager.cs b/grapher/Models/Serialized/SettingsManager.cs index 25aa534..c0cc413 100644 --- a/grapher/Models/Serialized/SettingsManager.cs +++ b/grapher/Models/Serialized/SettingsManager.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json; using System; +using System.IO; using System.Windows.Forms; using System.Threading; using System.Text; @@ -21,22 +22,41 @@ namespace grapher.Models.Serialized ToolStripMenuItem showVelocityAndGain, DeviceIDManager deviceIDManager) { - ActiveAccel = activeAccel; DpiField = dpiField; PollRateField = pollRateField; AutoWriteMenuItem = autoWrite; ShowLastMouseMoveMenuItem = showLastMouseMove; ShowVelocityAndGainMoveMenuItem = showVelocityAndGain; DeviceIDManager = deviceIDManager; + + SetActiveFields(activeAccel); + + GuiSettings = GUISettings.MaybeLoad(); + + if (GuiSettings is null) + { + GuiSettings = MakeGUISettingsFromFields(); + GuiSettings.Save(); + } + else + { + UpdateFieldsFromGUISettings(); + } + + UserSettings = InitUserSettings(); } #endregion Constructors #region Properties - public ManagedAccel ActiveAccel { get; set; } + public GUISettings GuiSettings { get; private set; } + + public ManagedAccel ActiveAccel { get; private set; } + + public ExtendedSettings ActiveSettings { get; private set; } - public RawAccelSettings RawAccelSettings { get; private set; } + public DriverSettings UserSettings { get; private set; } public Field DpiField { get; private set; } @@ -53,47 +73,54 @@ namespace grapher.Models.Serialized #endregion Properties #region Methods - public SettingsErrors TryUpdateActiveSettings(DriverSettings settings) - { - var errors = TryUpdateAccel(settings); - - if (errors.Empty()) - { - RawAccelSettings.AccelerationSettings = settings; - RawAccelSettings.GUISettings = MakeGUISettingsFromFields(); - RawAccelSettings.Save(); - } - return errors; + public void DisableDriver() + { + var defaultSettings = new ExtendedSettings(); + ActiveSettings = defaultSettings; + ActiveAccel.Settings = defaultSettings; + new Thread(() => ActiveAccel.Activate()).Start(); } public void UpdateFieldsFromGUISettings() { - DpiField.SetToEntered(RawAccelSettings.GUISettings.DPI); - PollRateField.SetToEntered(RawAccelSettings.GUISettings.PollRate); - ShowLastMouseMoveMenuItem.Checked = RawAccelSettings.GUISettings.ShowLastMouseMove; - ShowVelocityAndGainMoveMenuItem.Checked = RawAccelSettings.GUISettings.ShowVelocityAndGain; - AutoWriteMenuItem.Checked = RawAccelSettings.GUISettings.AutoWriteToDriverOnStartup; + DpiField.SetToEntered(GuiSettings.DPI); + PollRateField.SetToEntered(GuiSettings.PollRate); + ShowLastMouseMoveMenuItem.Checked = GuiSettings.ShowLastMouseMove; + ShowVelocityAndGainMoveMenuItem.Checked = GuiSettings.ShowVelocityAndGain; + AutoWriteMenuItem.Checked = GuiSettings.AutoWriteToDriverOnStartup; } - public SettingsErrors TryUpdateAccel(DriverSettings settings) + public SettingsErrors TryActivate(DriverSettings settings) { - var accel = new ManagedAccel(settings); - var errors = SendToDriverSafe(accel); - if (errors.Empty()) ActiveAccel= accel; - return errors; - } + var errors = new SettingsErrors(settings); - public static void SendToDriver(ManagedAccel accel) - { - new Thread(() => accel.Activate()).Start(); + if (errors.Empty()) + { + GuiSettings = MakeGUISettingsFromFields(); + GuiSettings.Save(); + + UserSettings = settings; + File.WriteAllText(Constants.DefaultSettingsFileName, RaConvert.Settings(settings)); + + ActiveSettings = new ExtendedSettings(settings); + ActiveAccel.Settings = ActiveSettings; + + new Thread(() => ActiveAccel.Activate()).Start(); + } + + return errors; } - public static SettingsErrors SendToDriverSafe(ManagedAccel accel) + public void SetHiddenOptions(DriverSettings settings) { - var errors = new SettingsErrors(accel.Settings); - if (errors.Empty()) SendToDriver(accel); - return errors; + settings.snap = UserSettings.snap; + settings.maximumSpeed = UserSettings.maximumSpeed; + settings.minimumSpeed = UserSettings.minimumSpeed; + settings.minimumTime = UserSettings.minimumTime; + settings.maximumTime = UserSettings.maximumTime; + settings.ignore = UserSettings.ignore; + settings.directionalMultipliers = UserSettings.directionalMultipliers; } public GUISettings MakeGUISettingsFromFields() @@ -108,32 +135,51 @@ namespace grapher.Models.Serialized }; } - // Returns true when file settings are active - public bool Startup() + public bool TableActive() + { + return ActiveSettings.tables.x != null || ActiveSettings.tables.y != null; + } + + public void SetActiveFields(ManagedAccel activeAccel) { - if (RawAccelSettings.Exists()) + ActiveAccel = activeAccel; + ActiveSettings = activeAccel.Settings; + } + + private DriverSettings InitUserSettings() + { + var path = Constants.DefaultSettingsFileName; + if (File.Exists(path)) { try { - RawAccelSettings = RawAccelSettings.Load(() => MakeGUISettingsFromFields()); - UpdateFieldsFromGUISettings(); - if (RawAccelSettings.GUISettings.AutoWriteToDriverOnStartup) + DriverSettings settings = RaConvert.Settings(File.ReadAllText(path)); + + if (!GuiSettings.AutoWriteToDriverOnStartup || + TableActive() || + TryActivate(settings).Empty()) { - TryUpdateAccel(RawAccelSettings.AccelerationSettings); + return settings; } - return RawAccelSettings.GUISettings.AutoWriteToDriverOnStartup; + } catch (JsonException e) { - Console.WriteLine($"bad settings: {e}"); + System.Diagnostics.Debug.WriteLine($"bad settings: {e}"); } } - RawAccelSettings = new RawAccelSettings( - ManagedAccel.GetActive().Settings, - MakeGUISettingsFromFields()); - RawAccelSettings.Save(); - return true; + if (!TableActive()) + { + File.WriteAllText(path, RaConvert.Settings(ActiveSettings.baseSettings)); + return ActiveSettings.baseSettings; + } + else + { + var defaultSettings = new DriverSettings(); + File.WriteAllText(path, RaConvert.Settings(defaultSettings)); + return defaultSettings; + } } #endregion Methods diff --git a/grapher/grapher.csproj b/grapher/grapher.csproj index e884c0d..c896510 100644 --- a/grapher/grapher.csproj +++ b/grapher/grapher.csproj @@ -80,6 +80,7 @@ <Compile Include="Constants\Constants.cs" /> <Compile Include="Layouts\LUTLayout.cs" /> <Compile Include="Layouts\MotivityLayout.cs" /> + <Compile Include="Layouts\JumpLayout.cs" /> <Compile Include="MessageDialog.cs"> <SubType>Form</SubType> </Compile> @@ -137,8 +138,6 @@ <Compile Include="Models\Options\OptionXY.cs" /> <Compile Include="Models\Options\TextOption.cs" /> <Compile Include="Models\Serialized\GUISettings.cs" /> - <Compile Include="Models\Serialized\LookupTable.cs" /> - <Compile Include="Models\Serialized\RawAccelSettings.cs" /> <Compile Include="Models\Serialized\SettingsManager.cs" /> <Compile Include="Program.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> diff --git a/wrapper/input.cpp b/wrapper/input.cpp new file mode 100644 index 0000000..d50f774 --- /dev/null +++ b/wrapper/input.cpp @@ -0,0 +1,74 @@ +#include "interop-exception.h" + +#include <utility-rawinput.hpp> +#include <algorithm> +#include <msclr\marshal_cppstd.h> + +using namespace System; +using namespace System::Collections::Generic; + +struct device_info { + std::wstring name; + std::wstring id; +}; + +std::vector<device_info> get_unique_device_info() { + std::vector<device_info> info; + + rawinput_foreach_with_interface([&](const auto& dev, const WCHAR* name) { + info.push_back({ + L"", // get_property_wstr(name, &DEVPKEY_Device_FriendlyName), /* doesn't work */ + dev_id_from_interface(name) + }); + }); + + std::sort(info.begin(), info.end(), + [](auto&& l, auto&& r) { return l.id < r.id; }); + auto last = std::unique(info.begin(), info.end(), + [](auto&& l, auto&& r) { return l.id == r.id; }); + info.erase(last, info.end()); + + return info; +} + +public ref struct RawInputInterop +{ + static void AddHandlesFromID(String^ deviceID, List<IntPtr>^ rawInputHandles) + { + try + { + std::vector<HANDLE> nativeHandles = rawinput_handles_from_dev_id( + msclr::interop::marshal_as<std::wstring>(deviceID)); + + for (auto nh : nativeHandles) rawInputHandles->Add(IntPtr(nh)); + } + catch (const std::exception& e) + { + throw gcnew RawInputInteropException(e); + } + } + + static List<ValueTuple<String^, String^>>^ GetDeviceIDs() + { + try + { + auto managed = gcnew List<ValueTuple<String^, String^>>(); + + for (auto&& [name, id] : get_unique_device_info()) + { + managed->Add( + ValueTuple<String^, String^>( + msclr::interop::marshal_as<String^>(name), + msclr::interop::marshal_as<String^>(id))); + } + + return managed; + } + catch (const std::exception& e) + { + throw gcnew RawInputInteropException(e); + } + } + +}; + diff --git a/wrapper/interop-exception.h b/wrapper/interop-exception.h new file mode 100644 index 0000000..8ebae5c --- /dev/null +++ b/wrapper/interop-exception.h @@ -0,0 +1,21 @@ +#pragma once + +#include <exception> + +public ref struct InteropException : System::Exception { + InteropException(System::String^ what) : + Exception(what) {} + InteropException(const char* what) : + Exception(gcnew System::String(what)) {} + InteropException(const std::exception& e) : + InteropException(e.what()) {} +}; + +public ref struct RawInputInteropException : InteropException { + RawInputInteropException(System::String^ what) : + InteropException(what) {} + RawInputInteropException(const char* what) : + InteropException(what) {} + RawInputInteropException(const std::exception& e) : + InteropException(e) {} +}; diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp index 7583312..eb7d4d0 100644 --- a/wrapper/wrapper.cpp +++ b/wrapper/wrapper.cpp @@ -1,22 +1,17 @@ #pragma once +#include "interop-exception.h" + #include <rawaccel-io.hpp> #include <rawaccel-validate.hpp> -#include <utility-rawinput.hpp> - -#include <algorithm> -#include <type_traits> -#include <msclr\marshal_cppstd.h> using namespace System; using namespace System::Collections::Generic; -using namespace System::IO; using namespace System::Runtime::InteropServices; using namespace System::Reflection; -using namespace Windows::Forms; - using namespace Newtonsoft::Json; +using namespace Newtonsoft::Json::Linq; namespace ra = rawaccel; @@ -25,17 +20,13 @@ ra::settings default_settings; [JsonConverter(Converters::StringEnumConverter::typeid)] public enum class AccelMode { - classic, jump, natural, power, motivity, lut, noaccel + classic, jump, natural, power, motivity, noaccel }; +[JsonConverter(Converters::StringEnumConverter::typeid)] public enum class TableMode { - off, binlog, linear -}; - -public enum class TableType -{ - spaced, arbitrary + off, binlog, linear, arbitrary }; [StructLayout(LayoutKind::Sequential)] @@ -44,9 +35,6 @@ public value struct TableArgs [JsonIgnore] TableMode mode; - [JsonIgnore] - TableType type; - [MarshalAs(UnmanagedType::U1)] bool transfer; @@ -67,24 +55,6 @@ public value struct Vec2 T y; }; -public ref struct SpacedTable -{ - [JsonProperty("Arguments for spacing in table")] - TableArgs args; - - [JsonProperty("Series of points for use in curve")] - List<double>^ points; -}; - -public ref struct ArbitraryTable -{ - [JsonProperty("Whether points affect velocity (true) or sensitivity (false)")] - bool transfer; - - [JsonProperty("Series of points for use in curve")] - List<Vec2<double>>^ points; -}; - [StructLayout(LayoutKind::Sequential)] public value struct AccelArgs { @@ -171,12 +141,6 @@ public ref struct DriverSettings [MarshalAs(UnmanagedType::ByValTStr, SizeConst = ra::MAX_DEV_ID_LEN)] String^ deviceID = ""; - [JsonIgnore] - SpacedTable^ SpacedTable; - - [JsonIgnore] - ArbitraryTable^ ArbitraryTable; - bool ShouldSerializeminimumTime() { return minimumTime != ra::DEFAULT_TIME_MIN; @@ -191,49 +155,254 @@ public ref struct DriverSettings { Marshal::PtrToStructure(IntPtr(&default_settings), this); } - - void ToFile(String^ path) +}; + +[JsonObject(ItemRequired = Required::Always)] +public ref struct LutBase abstract +{ + [JsonConverter(Converters::StringEnumConverter::typeid)] + enum class Mode { - using namespace Newtonsoft::Json::Linq; + logarithmic, linear, arbitrary + } mode; - JObject^ thisJO = JObject::FromObject(this); - String^ modes = String::Join(" | ", Enum::GetNames(AccelMode::typeid)); - thisJO->AddFirst(gcnew JProperty("### Accel Modes ###", modes)); - File::WriteAllText(path, thisJO->ToString(Formatting::Indented)); + virtual void SetArgs(TableArgs%) abstract; + virtual void SetData(ra::accel_union&) abstract; +}; + +[JsonObject(ItemRequired = Required::Always)] +public ref struct ArbitraryLut sealed : public LutBase +{ + [JsonProperty("Whether points affect velocity (true) or sensitivity (false)")] + bool transfer; + + array<float, 2>^ data; + + virtual void SetArgs(TableArgs% args) override + { + args.mode = TableMode::arbitrary; + args.transfer = transfer; } - static DriverSettings^ FromFile(String^ path) + virtual void SetData(ra::accel_union& accel) override { - if (!File::Exists(path)) - { - throw gcnew FileNotFoundException( - String::Format("Settings file not found at {0}", path)); + throw gcnew NotImplementedException(); + } + +}; + +[JsonObject(ItemRequired = Required::Always)] +public ref struct SpacedLut abstract : public LutBase +{ + [JsonProperty("Whether points affect velocity (true) or sensitivity (false)")] + bool transfer; + + double start; + double stop; + array<float>^ data; + + void SetArgsBase(TableArgs% args) + { + args.transfer = transfer; + args.start = start; + args.stop = stop; + } + + void SetDataBase(ra::accel_union& accel) + { + if (size_t(data->LongLength) > ra::LUT_CAPACITY) { + throw gcnew InteropException("data is too large"); } + } +}; - auto settings = JsonConvert::DeserializeObject<DriverSettings^>( - File::ReadAllText(path)); +[JsonObject(ItemRequired = Required::Always)] +public ref struct LinearLut sealed : public SpacedLut +{ + LinearLut(const ra::linear_lut& table) + { + mode = Mode::linear; + transfer = table.transfer; + start = table.range.start; + stop = table.range.stop; + data = gcnew array<float>(table.range.num); + + pin_ptr<float> pdata = &data[0]; + std::memcpy(pdata, &table.data, sizeof(float) * data->Length); + } - if (settings == nullptr) { - throw gcnew JsonException(String::Format("{0} contains invalid JSON", path)); + virtual void SetArgs(TableArgs% args) override + { + SetArgsBase(args); + args.num = data->Length; + args.mode = TableMode::linear; + } + + virtual void SetData(ra::accel_union& accel) override + { + SetDataBase(accel); + pin_ptr<float> pdata = &data[0]; + std::memcpy(&accel.lin_lut.data, pdata, sizeof(float) * data->Length); + } +}; + +[JsonObject(ItemRequired = Required::Always)] +public ref struct BinLogLut sealed : public SpacedLut +{ + short num; + + BinLogLut(const ra::binlog_lut& table) + { + mode = Mode::logarithmic; + transfer = table.transfer; + start = table.range.start; + stop = table.range.stop; + num = table.range.num; + data = gcnew array<float>(1 + num * (int(stop) - int(start))); + + pin_ptr<float> pdata = &data[0]; + std::memcpy(pdata, &table.data, sizeof(float) * data->Length); + } + + virtual void SetArgs(TableArgs% args) override + { + SetArgsBase(args); + args.num = num; + args.mode = TableMode::binlog; + } + + virtual void SetData(ra::accel_union& accel) override + { + SetDataBase(accel); + + if (data->Length != 1 + num * (int(stop) - int(start))) { + throw gcnew InteropException("size of data does not match args"); } - return settings; + pin_ptr<float> pdata = &data[0]; + std::memcpy(&accel.log_lut.data, pdata, sizeof(float) * data->Length); } }; -public ref struct InteropException : public Exception { -public: - InteropException(String^ what) : - Exception(what) {} - InteropException(const char* what) : - Exception(gcnew String(what)) {} - InteropException(const std::exception& e) : - InteropException(e.what()) {} +public ref struct RaConvert { + + static DriverSettings^ Settings(String^ json) + { + return NonNullable<DriverSettings^>(json); + } + + static String^ Settings(DriverSettings^ settings) + { + JObject^ jObject = JObject::FromObject(settings); + String^ modes = String::Join(" | ", Enum::GetNames(AccelMode::typeid)); + jObject->AddFirst(gcnew JProperty("### Accel Modes ###", modes)); + return jObject->ToString(Formatting::Indented); + } + + static LutBase^ Table(String^ json) + { + JObject^ jObject = JObject::Parse(json); + + if ((Object^)jObject == nullptr) { + throw gcnew JsonException("bad json"); + } + + LutBase^ base = NonNullable<LutBase^>(jObject); + + switch (base->mode) { + case LutBase::Mode::logarithmic: + return NonNullable<BinLogLut^>(jObject); + case LutBase::Mode::linear: + return NonNullable<LinearLut^>(jObject); + case LutBase::Mode::arbitrary: + return NonNullable<ArbitraryLut^>(jObject); + default: + throw gcnew NotImplementedException(); + } + } + + static String^ Table(LutBase^ lut) + { + auto serializerSettings = gcnew JsonSerializerSettings(); + return JsonConvert::SerializeObject( + lut, lut->GetType(), Formatting::Indented, serializerSettings); + }; + + generic <typename T> + static T NonNullable(String^ json) + { + T obj = JsonConvert::DeserializeObject<T>(json); + if (obj == nullptr) throw gcnew JsonException("invalid JSON"); + return obj; + } + + generic <typename T> + static T NonNullable(JObject^ jObject) + { + T obj = jObject->ToObject<T>(); + if (obj == nullptr) throw gcnew JsonException("invalid JSON"); + return obj; + } +}; + +public ref struct ExtendedSettings { + DriverSettings^ baseSettings; + Vec2<LutBase^> tables; + + using JSON = String^; + + ExtendedSettings(DriverSettings^ driverSettings) : + baseSettings(driverSettings) {} + + ExtendedSettings() : + ExtendedSettings(gcnew DriverSettings()) {} + + ExtendedSettings(JSON settingsJson) : + ExtendedSettings(settingsJson, nullptr, nullptr, false) {} + + ExtendedSettings(JSON settingsJson, JSON tableJson) : + ExtendedSettings(settingsJson, tableJson, nullptr, false) {} + + ExtendedSettings(JSON settingsJson, JSON xTableJson, JSON yTableJson) : + ExtendedSettings(settingsJson, xTableJson, yTableJson, true) {} + +private: + ExtendedSettings(JSON settingsJson, JSON xTableJson, JSON yTableJson, bool byComponent) + { + if (settingsJson) { + baseSettings = RaConvert::Settings(settingsJson); + } + else { + baseSettings = gcnew DriverSettings(); + } + + if (xTableJson || yTableJson) { + baseSettings->combineMagnitudes = !byComponent; + } + + if (xTableJson) { + tables.x = RaConvert::Table(xTableJson); + tables.x->SetArgs(baseSettings->args.x.lutArgs); + } + + if (yTableJson) { + if (Object::ReferenceEquals(yTableJson, xTableJson)) { + tables.y = tables.x; + } + else { + tables.y = RaConvert::Table(yTableJson); + } + + tables.y->SetArgs(baseSettings->args.y.lutArgs); + } + } + }; public ref class SettingsErrors { public: + List<String^>^ list; int countX; int countY; @@ -242,9 +411,12 @@ public: void Add(const char* msg) { - list->Add(msclr::interop::marshal_as<String^>(msg)); + list->Add(gcnew String(msg)); } + SettingsErrors(ExtendedSettings^ settings) : + SettingsErrors(settings->baseSettings) {} + SettingsErrors(DriverSettings^ settings) { MsgHandler^ del = gcnew MsgHandler(this, &SettingsErrors::Add); @@ -289,71 +461,6 @@ public: } }; -struct device_info { - std::wstring name; - std::wstring id; -}; - -std::vector<device_info> get_unique_device_info() { - std::vector<device_info> info; - - rawinput_foreach_with_interface([&](const auto& dev, const WCHAR* name) { - info.push_back({ - L"", // get_property_wstr(name, &DEVPKEY_Device_FriendlyName), /* doesn't work */ - dev_id_from_interface(name) - }); - }); - - std::sort(info.begin(), info.end(), - [](auto&& l, auto&& r) { return l.id < r.id; }); - auto last = std::unique(info.begin(), info.end(), - [](auto&& l, auto&& r) { return l.id == r.id; }); - info.erase(last, info.end()); - - return info; -} - -public ref struct RawInputInterop -{ - static void AddHandlesFromID(String^ deviceID, List<IntPtr>^ rawInputHandles) - { - try - { - std::vector<HANDLE> nativeHandles = rawinput_handles_from_dev_id( - msclr::interop::marshal_as<std::wstring>(deviceID)); - - for (auto nh : nativeHandles) rawInputHandles->Add(IntPtr(nh)); - } - catch (const std::exception& e) - { - throw gcnew InteropException(e); - } - } - - static List<ValueTuple<String^, String^>>^ GetDeviceIDs() - { - try - { - auto managed = gcnew List<ValueTuple<String^, String^>>(); - - for (auto&& [name, id] : get_unique_device_info()) - { - managed->Add( - ValueTuple<String^, String^>( - msclr::interop::marshal_as<String^>(name), - msclr::interop::marshal_as<String^>(id))); - } - - return managed; - } - catch (const std::exception& e) - { - throw gcnew InteropException(e); - } - } - -}; - struct instance_t { ra::io_t data; vec2<ra::accel_invoker> inv; @@ -364,9 +471,9 @@ public ref class ManagedAccel instance_t* const instance = new instance_t(); public: - ManagedAccel() {}; + ManagedAccel() {} - ManagedAccel(DriverSettings^ settings) + ManagedAccel(ExtendedSettings^ settings) { Settings = settings; } @@ -403,20 +510,32 @@ public: } } - property DriverSettings^ Settings + property ExtendedSettings^ Settings { - DriverSettings^ get() + ExtendedSettings^ get() { - DriverSettings^ settings = gcnew DriverSettings(); - Marshal::PtrToStructure(IntPtr(&instance->data.args), settings); + auto settings = gcnew ExtendedSettings(); + Marshal::PtrToStructure(IntPtr(&instance->data.args), settings->baseSettings); + settings->tables.x = extract(instance->data.args.argsv.x.lut_args.mode, + instance->data.mod.accels.x); + settings->tables.y = extract(instance->data.args.argsv.y.lut_args.mode, + instance->data.mod.accels.y); return settings; } - void set(DriverSettings^ val) + void set(ExtendedSettings^ val) { - Marshal::StructureToPtr(val, IntPtr(&instance->data.args), false); + Marshal::StructureToPtr(val->baseSettings, IntPtr(&instance->data.args), false); instance->data.mod = { instance->data.args }; instance->inv = ra::invokers(instance->data.args); + + if (val->tables.x) { + val->tables.x->SetData(instance->data.mod.accels.x); + } + + if (val->tables.y) { + val->tables.y->SetData(instance->data.mod.accels.y); + } } } @@ -433,6 +552,18 @@ public: throw gcnew InteropException(e); } } + +private: + LutBase^ extract(ra::table_mode mode, ra::accel_union& au) + { + switch (mode) { + case ra::table_mode::off: return nullptr; + case ra::table_mode::linear: return gcnew LinearLut(au.lin_lut); + case ra::table_mode::binlog: return gcnew BinLogLut(au.log_lut); + case ra::table_mode::arbitrary: + default: throw gcnew NotImplementedException(); + } + } }; public ref struct VersionHelper @@ -449,5 +580,4 @@ public ref struct VersionHelper throw gcnew InteropException(e); } } - }; diff --git a/wrapper/wrapper.vcxproj b/wrapper/wrapper.vcxproj index fba03a7..8de0cfb 100644 --- a/wrapper/wrapper.vcxproj +++ b/wrapper/wrapper.vcxproj @@ -83,17 +83,18 @@ copy /Y "$(TargetDir)Newtonsoft.Json.dll" "$(SolutionDir)signed\Newtonsoft.Json. </ResourceCompile> </ItemDefinitionGroup> <ItemGroup> + <ClInclude Include="interop-exception.h" /> <ClInclude Include="resource.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="AssemblyInfo.cpp" /> + <ClCompile Include="input.cpp" /> <ClCompile Include="wrapper.cpp" /> </ItemGroup> <ItemGroup> <Reference Include="Newtonsoft.Json"> <HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath> </Reference> - <Reference Include="System.Windows.Forms" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="wrapper.rc" /> diff --git a/wrapper/wrapper.vcxproj.filters b/wrapper/wrapper.vcxproj.filters index 96b8e1a..9caeae1 100644 --- a/wrapper/wrapper.vcxproj.filters +++ b/wrapper/wrapper.vcxproj.filters @@ -18,6 +18,9 @@ <ClInclude Include="resource.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="interop-exception.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="wrapper.cpp"> @@ -26,6 +29,9 @@ <ClCompile Include="AssemblyInfo.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="input.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ResourceCompile Include="wrapper.rc"> diff --git a/writer/Program.cs b/writer/Program.cs index d381c16..6cbcf8e 100644 --- a/writer/Program.cs +++ b/writer/Program.cs @@ -1,8 +1,9 @@ using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Windows.Forms; namespace writer @@ -11,9 +12,71 @@ namespace writer class Program { - static void Show(string msg) + static void ExitWithMessage(string msg) { MessageBox.Show(msg, "Raw Accel writer"); + Environment.Exit(1); + } + + static void ExitWithUsage() + { + ExitWithMessage($"Usage: {System.AppDomain.CurrentDomain.FriendlyName} <settings file path>"); + } + + delegate string PopOption(params string[] aliases); + + static string Read(string path) + { + return path == null ? null : File.ReadAllText(path); + } + + static ExtendedSettings Parse(List<string> args) + { + PopOption maybePop = aliases => + { + int idx = args.FindIndex(aliases.Contains); + + if (idx == -1) return null; + + if (idx == args.Count - 1) ExitWithUsage(); + + string val = args[idx + 1]; + args.RemoveRange(idx, 2); + return val; + }; + + string settingsPath = null; + + string tablePath = maybePop("table", "t"); + + if (tablePath != null) + { + if (args.Count > 1) ExitWithUsage(); + else if (args.Count == 1) settingsPath = args[0]; + + return new ExtendedSettings(Read(settingsPath), Read(tablePath)); + } + + string xTablePath = maybePop("xtable", "xt"); + string yTablePath = maybePop("ytable", "yt"); + + if (args.Count > 1) ExitWithUsage(); + else if (args.Count == 1) settingsPath = args[0]; + else if (xTablePath == null && yTablePath == null) ExitWithUsage(); + + string xTableJson = Read(xTablePath); + string yTableJson = null; + + if (xTablePath != null && xTablePath.Equals(yTablePath)) + { + yTableJson = xTableJson; + } + else + { + yTableJson = Read(yTablePath); + } + + return new ExtendedSettings(Read(settingsPath), xTableJson, yTableJson); } static void Main(string[] args) @@ -24,19 +87,12 @@ namespace writer } catch (InteropException e) { - Show(e.Message); - return; - } - - if (args.Length != 1) - { - Show($"Usage: {System.AppDomain.CurrentDomain.FriendlyName} <settings file path>"); - return; + ExitWithMessage(e.Message); } try { - var settings = DriverSettings.FromFile(args[0]); + var settings = Parse(new List<string>(args)); var errors = new SettingsErrors(settings); if (errors.Empty()) @@ -45,16 +101,20 @@ namespace writer } else { - Show($"Bad settings:\n\n{errors}"); + ExitWithMessage($"Bad settings:\n\n{errors}"); } } + catch (System.IO.FileNotFoundException e) + { + ExitWithMessage(e.Message); + } catch (JsonException e) { - Show($"Settings invalid:\n\n{e.Message}"); + ExitWithMessage($"Settings invalid:\n\n{e.Message}"); } catch (Exception e) { - Show($"Error:\n\n{e}"); + ExitWithMessage($"Error:\n\n{e}"); } } } |